/*- * Copyright (c) 2012 Diamond Light Source Ltd. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package uk.ac.diamond.scisoft.analysis.fitting.functions; import java.lang.reflect.Constructor; import java.util.Collections; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import org.eclipse.dawnsci.analysis.api.fitting.functions.IFunction; import org.eclipse.dawnsci.analysis.api.fitting.functions.IPeak; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Use this factory to return your function by name. * * Avoid using concrete instances of functions is reduces flexibility of the product * because functions cannot be swapped into different parts of the code. * * Instead use something like: * <code> * double[] params = ... * IFunction box = FunctionFactory.getFunction("Box", params); * * </code> * * In the ideal world the functions would be package private classes. * * * NOTE If using the function actor, functions must also be declared in 'FunctionType' * */ @SuppressWarnings("unchecked") public final class FunctionFactory { private static final SortedMap<String, Class<? extends IFunction>> FUNCTIONS; private static final SortedMap<String, Class<? extends IPeak>> PEAKS; static { FUNCTIONS = new TreeMap<String, Class<? extends IFunction>>(); PEAKS = new TreeMap<String, Class<? extends IPeak>>(); /** * Functions *must* have a zero argument constructor. * * Previously included full list of functions. Now these are * imported as Extension Points. Left in case of future need. */ // registerFunctions( // ); } private static final Logger logger = LoggerFactory.getLogger(FunctionFactory.class); // Not for public use: only used by OSGI public FunctionFactory() { } /** * Register a block of functions with factory. * @param classes */ @SafeVarargs public static void registerFunctions(Boolean ignoreDuplicates, Class<? extends IFunction>... classes) { for (Class<? extends IFunction> clazz : classes) { try { registerFunction(clazz, null, ignoreDuplicates,null); } catch (Throwable e) { logger.error("Cannot register function "+clazz.getCanonicalName()+"!", e); } } } /** * Register a function with its class and whether we should ignore duplicates * in the maps. This is useful for tests. * @param clazz * @param ignoreDuplicates * @throws Exception */ public static void registerFunction(Class<? extends IFunction> clazz, Boolean ignoreDuplicates) throws Exception { registerFunction(clazz, null, ignoreDuplicates, null); } /** * Register a function with its class, function name and use case list. * (This is default option that should be used) * @param clazz - function class * @param fnName - string of user defined function name * @param useCaseList - list of use cases ids extracted from extension point * @throws Exception */ public static void registerFunction(Class<? extends IFunction> clazz, String fnName, Set<String> useCaseList) throws Exception { registerFunction(clazz, fnName, false, useCaseList); } /** * Full method allowing registration of functions with the factory and also * (for testing) ignoring of duplicates in the PEAKS and FUNCTIONS maps. * @param clazz * @param fnName * @param ignoreDuplicates * @throws Exception */ public static void registerFunction(Class<? extends IFunction> clazz, String fnName, Boolean ignoreDuplicates, Set<String> useCaseList) throws Exception { final IFunction function = clazz.newInstance(); final String name; //Register with a different name to the one in the class if (fnName != null) { name = fnName; } else { name = function.getName(); } //Add function to FUNCTION map if (!FUNCTIONS.containsKey(name)) { FUNCTIONS.put(name, clazz); //If this is a peak function, register it in the PEAK map too if (function instanceof IPeak) { if (!PEAKS.containsKey(name)) { PEAKS.put(name, (Class<? extends IPeak>) clazz); } else { if (ignoreDuplicates) { //pass } else { throw new IllegalArgumentException("A peak function is already registered with the name "+name+"."); } } } if (useCaseList != null) { FunctionUseCaseService.setFunctionUseCases(name, useCaseList); } } else { if (ignoreDuplicates) { //Pass } else { throw new IllegalArgumentException("A function is already registered with the name "+name+"."); } } } /** * @return set of function names */ public static Set<String> getFunctionNames() { return Collections.unmodifiableSet(FUNCTIONS.keySet()); } /** * @return set of peak function names */ public static Set<String> getPeakFunctionNames() { return Collections.unmodifiableSet(PEAKS.keySet()); } /** * Returns the complete set of functions with their names and classes * registered with the factory * @return Map of names (strings) and classes (IFunction) */ public static Map<String, Class<? extends IFunction>> getFunctions() { return FUNCTIONS; } /** * Returns an instance of a function * @param name of registered function * @return IFunction * @throws IllegalArgumentException if not found or could not create */ public static IFunction getFunction(String name) { Class<? extends IFunction> functionClass = getFunctionClass(name); try { return functionClass.newInstance(); } catch (Exception e) { logger.error("Could not create instance of {}", functionClass, e); throw new IllegalArgumentException("Could not create instance of " + functionClass, e); } } /** * Returns an instance of a function with given arguments * @param name of registered function * @param args arguments for constructor * @return IFunction * @throws IllegalArgumentException if not found or could not create */ public static IFunction getFunction(String name, double... args) { Class<? extends IFunction> functionClass = getFunctionClass(name); try { final Constructor<? extends IFunction> c = functionClass.getConstructor(double[].class); return c.newInstance(args); } catch (Exception e) { logger.error("Could not create instance of {}", functionClass, e); throw new IllegalArgumentException("Could not create instance of " + functionClass, e); } } /** * Returns a registered function class * @param name of registered function * @return IFunction class * @throws IllegalArgumentException if not found */ public static Class<? extends IFunction> getFunctionClass(String name) { Class<? extends IFunction> functionClass = FUNCTIONS.get(name); if (functionClass == null) { logger.error("There is no function with the name '{}' registered!", name); throw new IllegalArgumentException("There is no function with the name " + name + " registered!"); } return functionClass; } /** * Returns an instance of a peak * @param name of registered peak * @return IPeak * @throws IllegalArgumentException if not found or could not create */ public static IPeak getPeakFunction(String name) { Class<? extends IPeak> peakClass = getPeakFunctionClass(name); try { return peakClass.newInstance(); } catch (Exception e) { logger.error("Could not create instance of {}", peakClass, e); throw new IllegalArgumentException("Could not create instance of " + peakClass, e); } } /** * Returns a registered peak class * @param name of registered peak * @return IPeak class * @throws IllegalArgumentException if not found */ public static Class<? extends IPeak> getPeakFunctionClass(String name) { Class<? extends IPeak> peakClass = PEAKS.get(name); if (peakClass == null) { logger.error("There is no peak function with the name '{}' registered!", name); throw new IllegalArgumentException("There is no peak function with the name " + name + " registered!"); } return peakClass; } }