package org.insa.algo; import java.lang.reflect.Constructor; import java.util.IdentityHashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.insa.algo.shortestpath.AStarAlgorithm; import org.insa.algo.shortestpath.BellmanFordAlgorithm; import org.insa.algo.shortestpath.DijkstraAlgorithm; import org.insa.algo.shortestpath.ShortestPathAlgorithm; import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsAlgorithm; /** * Factory class used to register and retrieve algorithms based on their common * ancestor and name. * */ public class AlgorithmFactory { // Map between algorithm names and class. private final static Map>, Map>>> ALGORITHMS = new IdentityHashMap<>(); static { // Register weakly-connected components algorithm: registerAlgorithm(WeaklyConnectedComponentsAlgorithm.class, "WCC basic", WeaklyConnectedComponentsAlgorithm.class); // Register shortest path algorithm: registerAlgorithm(ShortestPathAlgorithm.class, "Bellman-Ford", BellmanFordAlgorithm.class); registerAlgorithm(ShortestPathAlgorithm.class, "Dijkstra", DijkstraAlgorithm.class); registerAlgorithm(ShortestPathAlgorithm.class, "A*", AStarAlgorithm.class); // Register your algorithms here: // registerAlgorithm(CarPoolingAlgorithm.class, "My Awesome Algorithm", // MyCarPoolingAlgorithm.class); } /** * Register the given algorithm class with the given name as a child class of * the given base algorithm. * * @param baseAlgorithm Base algorithm class that corresponds to the newly * registered algorithm class (e.g., generic algorithm class for the * problem). * @param name Name for the registered algorithm class. * @param algoClass Algorithm class to register. */ public static void registerAlgorithm(Class> baseAlgorithm, String name, Class> algoClass) { if (!ALGORITHMS.containsKey(baseAlgorithm)) { ALGORITHMS.put(baseAlgorithm, new LinkedHashMap<>()); } ALGORITHMS.get(baseAlgorithm).put(name, algoClass); } /** * Create an instance of the given algorithm class using the given input data. * Assuming algorithm correspond to a class "Algorithm", this function returns * an object equivalent to `new Algorithm(data)`. * * @param algorithm Class of the algorithm to create. * @param data Input data for the algorithm. * * @return A new instance of the given algorithm class using the given data. * * @throws Exception if something wrong happens when constructing the object, * i.e. the given input data does not correspond to the given algorithm * and/or no constructor that takes a single parameter of type * (data.getClass()) exists. */ public static AbstractAlgorithm createAlgorithm( Class> algorithm, AbstractInputData data) throws Exception { // Retrieve the set of constructors for the given algorithm class. Constructor[] constructors = algorithm.getDeclaredConstructors(); // Within this set, find the constructor that can be called with "data" (only). AbstractAlgorithm constructed = null; for (Constructor c: constructors) { Class[] params = c.getParameterTypes(); if (params.length == 1 && params[0].isAssignableFrom(data.getClass())) { c.setAccessible(true); constructed = (AbstractAlgorithm) c.newInstance(new Object[]{ data }); break; } } return constructed; } /** * Return the algorithm class corresponding to the given base algorithm class * and name. The algorithm must have been previously registered using * registerAlgorithm. * * @param baseAlgorithm Base algorithm class for the algorithm to retrieve. * @param name Name of the algorithm to retrieve. * * @return Class corresponding to the given name. * * @see #registerAlgorithm */ public static Class> getAlgorithmClass( Class> baseAlgorithm, String name) { return ALGORITHMS.get(baseAlgorithm).get(name); } /** * Return the list of names corresponding to the registered algorithm classes * for the given base algorithm class. * * @param baseAlgorithm Base algorithm class for the algorithm class names to * retrieve. * * @return Names of the currently registered algorithms. * * @see #registerAlgorithm */ public static Set getAlgorithmNames( Class> baseAlgorithm) { if (!ALGORITHMS.containsKey(baseAlgorithm)) { return new TreeSet<>(); } return ALGORITHMS.get(baseAlgorithm).keySet(); } }