/* * This file is part of JGAP. * * JGAP offers a dual license model containing the LGPL as well as the MPL. * * For licensing information please see the file license.txt included with JGAP * or have a look at the top of class org.jgap.Chromosome which representatively * includes the JGAP license policy applicable for any file delivered with JGAP. */ package org.jgap.impl; import java.io.*; import java.util.*; import org.jgap.*; import org.jgap.util.*; import org.apache.commons.lang.builder.*; /** * Central factory for creating default objects to use, e.g. random generators. * Could be made configurable. An instance of JGAPFactory can be accessed via<p> * <code>Genotype.getConfiguration().getJGAPFactory();</code><p> * To use your own factory class instead, use:<p> * <code> * System.setProperty(Configuration.PROPERTY_JGAPFACTORY_CLASS, "myFactory");<p> * </code> * with "myFactory" representing the name of your class to use. * * @author Klaus Meffert * @since 2.6 */ public class JGAPFactory implements IJGAPFactory, Serializable, ICloneable, Comparable { /** String containing the CVS revision. Read out via reflection!*/ private final static String CVS_REVISION = "$Revision: 1.19 $"; private List m_parameters; private List m_cloneHandlers; private List m_initer; private List m_compareHandlers; private ICloneHandler m_defaultCloneHandler; private IInitializer m_defaultIniter; private ICompareToHandler m_defaultComparer; private IGeneticOperatorConstraint m_geneticOpConstraint; private transient LRUCache m_cache; private boolean m_useCaching; private Map<String,Long> m_lastKeys; public JGAPFactory(boolean a_useCaching) { m_initer = new Vector(); m_cache = new LRUCache(50); m_useCaching = a_useCaching; m_cloneHandlers = new Vector(); m_compareHandlers = new Vector(); // Construct default handlers at the beginning to avoid multi-threading // conflicts in getXXXFor methods. m_defaultCloneHandler = new DefaultCloneHandler(); m_defaultIniter = new DefaultInitializer(); m_defaultComparer = new DefaultCompareToHandler(); m_lastKeys = new HashMap(); } /** * Allows setting (generic because unknown) parameters for creating objects. * * @param a_parameters Collection of generic parameters * * @author Klaus Meffert * @since 2.6 */ public void setParameters(final Collection a_parameters) { m_parameters = new Vector(a_parameters); } /** * @return Collection of generic parameters * * @author Klaus Meffert * @since 3.0 */ public Collection getParameters() { return m_parameters; } public RandomGenerator createRandomGenerator() { return new StockRandomGenerator(); } /** * Registers a clone handler that could be retrieved by * getCloneHandlerFor(Class). * * @param a_cloneHandler the ICloneHandler to register * @return index of the added clone handler, needed when removeCloneHandler * will be called * * @author Klaus Meffert * @since 2.6 */ public int registerCloneHandler(final ICloneHandler a_cloneHandler) { m_cloneHandlers.add(a_cloneHandler); return m_cloneHandlers.size() - 1; } /** * Removes a clone handler at a given index (which is obtained from * registerCloneHandler). * * @param a_index the index of the clone handler to remove * @return the removed ICloneHandler, or Exception if not successfull * * @author Klaus Meffert * @since 2.6 */ public ICloneHandler removeCloneHandler(final int a_index) { return (ICloneHandler) m_cloneHandlers.remove(a_index); } /** * Retrieves a clone handler capable of clone the given class. * * @param a_obj the object to clone (maybe null) * @param a_classToClone the class to clone an object of (maybe null) * @return the clone handler found capable of clone the given * class, or null if none registered * * @author Klaus Meffert * @since 2.6 */ public ICloneHandler getCloneHandlerFor(final Object a_obj, final Class a_classToClone) { return (ICloneHandler) findHandlerFor(a_obj, a_classToClone, m_cloneHandlers, m_defaultCloneHandler, "clone"); } /** * Registers an initializer that could be retrieved by * getInitializerFor(Class). * * @param a_chromIniter the IChromosomeInitializer to register * @return index of the added initializer, needed when * removeChromosomeInitializer will be called * * @author Klaus Meffert * @since 2.6 */ public int registerInitializer(final IInitializer a_chromIniter) { m_initer.add(a_chromIniter); return m_initer.size() - 1; } /** * Removes an initializer at a given index (which is obtained from * registerInitializer). * * @param a_index the index of the initializer to remove * @return the removed IInitializer, or null if not successfull * * @author Klaus Meffert * @since 2.6 */ public IInitializer removeInitializer(final int a_index) { return (IInitializer) m_initer.remove(a_index); } /** * Retrieves an initializer capable of initializing the Object of the given * class. * * @param a_obj the object to init (maybe null) * @param a_class the object class to init (maybe null) * @return new instance (should be!) of initialized object * * @author Klaus Meffert * @since 2.6 */ public IInitializer getInitializerFor(final Object a_obj, final Class a_class) { return (IInitializer) findHandlerFor(a_obj, a_class, m_initer, m_defaultIniter, "init"); } public void setGeneticOperatorConstraint(final IGeneticOperatorConstraint a_constraint) { m_geneticOpConstraint = a_constraint; } public IGeneticOperatorConstraint getGeneticOperatorConstraint() { return m_geneticOpConstraint; } /** * Retrieves a handler capable of comparing two instances of the given class. * * @param a_obj the object to compare (maybe null) * @param a_classToCompareTo the class instances to compare (maybe null) * @return the handler found capable of comparing instances * of the given class, or null if none registered * * @author Klaus Meffert * @since 2.6 */ public ICompareToHandler getCompareToHandlerFor(Object a_obj, Class a_classToCompareTo) { return (ICompareToHandler) findHandlerFor(a_obj, a_classToCompareTo, m_compareHandlers, m_defaultComparer, "compare"); } /** * Registers a compareTo-handler that could be retrieved by * getCompareToHandlerFor(Class). * * @param a_compareToHandler the ICompareToHandler to register * @return index of the added handler, needed when removeCompareToHandler * will be called * * @author Klaus Meffert * @since 2.6 */ public int registerCompareToHandler(ICompareToHandler a_compareToHandler) { m_compareHandlers.add(a_compareToHandler); return m_compareHandlers.size() - 1; } /** * Removes a compareTo-handler at a given index (which is obtained from * registerCompareToHandler). * * @param a_index the index of the handler to remove * @return the removed handler, or Exception if not successfull * * @author Klaus Meffert * @since 2.6 */ public ICompareToHandler removeCompareToHandler(final int a_index) { return (ICompareToHandler) m_compareHandlers.remove(a_index); } /** * Helper: Finds a handler for a given Object or Class, returns the default * handler, if one is provided. Uses an LRU cache to speedup things! * * @param a_obj the object to find a handler for (maybe null) * @param a_class the class to find a handler for (maybe null) * @param a_list list of available handlers * @param a_default a default handler to return in none other is found * @param a_listID arbitrary unique string for accessing the cache * @return the handler found, or null if none registered * * @author Klaus Meffert * @since 2.6 */ protected IHandler findHandlerFor(final Object a_obj, final Class a_class, final List a_list, final IHandler a_default, final String a_listID) { String key = null; String key1, key2; if (m_useCaching) { // Construct key for cache lookup: // Class name of list + a_class-Name + a_obj.hashCode() // ---------------------------------------------------- if (a_class == null) { key1 = "null"; } else { key1 = a_class.getName(); } if (a_obj == null) { key2 = "null"; } else { key2 = a_obj.getClass().getName(); } key = a_listID + "/" + key1 + "/" + key2; // Lookup cache. // ------------- Object handler = m_cache.get(key); if (handler != null) { return (IHandler) handler; } // Not found in cache. Search initially. // ------------------------------------- } IHandler result = null; Iterator it = a_list.iterator(); while (it.hasNext()) { IHandler initer = (IHandler) it.next(); if (initer.isHandlerFor(a_obj, a_class)) { result = initer; break; } } if (result == null) { // No registered handler found. Try the default handler. // ----------------------------------------------------- if (a_default != null) { if (a_default.isHandlerFor(a_obj, a_class)) { result = a_default; } } } if (m_useCaching) { // Add to cache. // ------------- if (result != null) { m_cache.put(key, result); } } return result; } /** * @return true: caching used, false: no caching used * * @author Klaus Meffert * @since 3.0 */ public boolean isUseCaching() { return m_useCaching; } public Object clone() { try { /**@todo check if it works this way*/ return super.clone(); } catch (CloneNotSupportedException cex) { throw new CloneException(cex); } } /** * The equals-method * @param a_other sic * @return sic * * @author Klaus Meffert * @since 3.2 */ public boolean equals(Object a_other) { try { return compareTo(a_other) == 0; } catch (ClassCastException cex) { return false; } } /** * @param a_other other object to compare * @return as always * * @author Klaus Meffert * @since 3.2 */ public int compareTo(Object a_other) { if (a_other == null) { return 1; } else { // Do not consider m_parameters, m_cache and m_useCaching. // ------------------------------------------------------- JGAPFactory other = (JGAPFactory) a_other; return new CompareToBuilder() .append(m_cloneHandlers.toArray(), other.m_cloneHandlers.toArray()) .append(m_initer.toArray(), other.m_initer.toArray()) .append(m_compareHandlers.toArray(), other.m_compareHandlers.toArray()) .append(m_defaultCloneHandler, other.m_defaultCloneHandler) .append(m_defaultComparer, other.m_defaultComparer) .append(m_geneticOpConstraint, other.m_geneticOpConstraint) .toComparison(); } } /** * Returns a unique key for the given context. The key uses the current date * and time and a GUID. Thus it is quite probable, that the key is unique * worldwide. * * @param a_context the context to get the next key for, like "Chromosome". * @return the unique key for the given context * * @author Klaus Meffert * @since 3.5 */ public String getUniqueKey(String a_context) { // For each context, keep track of keys used. // ------------------------------------------ Long lastKey = m_lastKeys.get(a_context); if(lastKey == null) { lastKey = new Long(1); } else { // The next key is always the increment of the previous key. // --------------------------------------------------------- lastKey = lastKey.longValue() + 1; } m_lastKeys.put(a_context, lastKey); String GUID = UUID.randomUUID().toString(); String key = GUID + "_"+ DateKit.getNowAsString() + "_" + lastKey; return key; } }