/* * Created on Aug 14, 2006 Copyright (C) 2001-6, Anthony Harrison anh23@pitt.edu * (jactr.org) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the License, * or (at your option) any later version. This library is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU Lesser General Public License for more details. You should have * received a copy of the GNU Lesser General Public License along with this * library; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jactr.core.module.declarative.basic; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.Map; import java.util.SortedSet; import java.util.TreeMap; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.locks.ReentrantReadWriteLock; import javolution.text.TextBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.core.buffer.IActivationBuffer; import org.jactr.core.buffer.event.ActivationBufferEvent; import org.jactr.core.buffer.event.IActivationBufferListener; import org.jactr.core.chunk.IChunk; import org.jactr.core.chunk.ISymbolicChunk; import org.jactr.core.chunktype.IChunkType; import org.jactr.core.chunktype.IRemovableSymbolicChunkType; import org.jactr.core.chunktype.ISymbolicChunkType; import org.jactr.core.concurrent.ExecutorServices; import org.jactr.core.event.IParameterEvent; import org.jactr.core.logging.Logger; import org.jactr.core.model.IModel; import org.jactr.core.module.declarative.IDeclarativeModule; import org.jactr.core.module.declarative.IRemovableDeclarativeModule; import org.jactr.core.module.declarative.basic.chunk.DefaultChunkFactory; import org.jactr.core.module.declarative.basic.chunk.DefaultSubsymbolicChunkFactory5; import org.jactr.core.module.declarative.basic.chunk.DefaultSymbolicChunkFactory; import org.jactr.core.module.declarative.basic.chunk.IChunkConfigurator; import org.jactr.core.module.declarative.basic.chunk.IChunkFactory; import org.jactr.core.module.declarative.basic.chunk.IChunkNamer; import org.jactr.core.module.declarative.basic.chunk.ISubsymbolicChunkFactory; import org.jactr.core.module.declarative.basic.chunk.ISymbolicChunkFactory; import org.jactr.core.module.declarative.basic.chunk.NoOpChunkConfigurator; import org.jactr.core.module.declarative.basic.chunk.NoOpChunkNamer; import org.jactr.core.module.declarative.basic.type.DefaultChunkTypeFactory; import org.jactr.core.module.declarative.basic.type.DefaultSubsymbolicChunkTypeFactory; import org.jactr.core.module.declarative.basic.type.DefaultSymbolicChunkTypeFactory; import org.jactr.core.module.declarative.basic.type.IChunkTypeConfigurator; import org.jactr.core.module.declarative.basic.type.IChunkTypeFactory; import org.jactr.core.module.declarative.basic.type.IChunkTypeNamer; import org.jactr.core.module.declarative.basic.type.ISubsymbolicChunkTypeFactory; import org.jactr.core.module.declarative.basic.type.ISymbolicChunkTypeFactory; import org.jactr.core.module.declarative.basic.type.NoOpChunkTypeConfigurator; import org.jactr.core.module.declarative.basic.type.NoOpChunkTypeNamer; import org.jactr.core.module.declarative.search.ISearchSystem; import org.jactr.core.module.declarative.search.filter.IChunkFilter; import org.jactr.core.module.declarative.search.filter.ILoggedChunkFilter; import org.jactr.core.module.declarative.search.local.DefaultSearchSystem; import org.jactr.core.production.request.ChunkTypeRequest; import org.jactr.core.utils.StringUtilities; import org.jactr.core.utils.collections.SkipListSetFactory; import org.jactr.core.utils.parameter.ClassNameParameterHandler; import org.jactr.core.utils.parameter.IParameterized; import org.jactr.core.utils.parameter.ParameterHandler; /** * default declarative module that incorporates many useful features. This * module is full thread safe, and parameterizes the creation factories. <br/> * This module also uses the local {@link DefaultSearchSystem} for the indexing * of chunks.<br/> * This module provides encoding services for any buffer that returns false for * {@link IActivationBuffer#handlesEncoding()}.<br/> * This is the ideal point to start from when creating a new declarative module. <br/> * <br/> * Most modelers should be content with this or it's version specific * subclasses. If you need to add theoretic behavior, it is recommended that you * start with customizing the symbolic/ subsymbolic factories (most likely just * the {@link ISubsymbolicChunkFactory}). Custom {@link IChunk}s should not be * required as they are simply wrappers to the theoretically relevant contents. <br/> * <br/> * Most extensions will just extend this module to add their parameter * accessors, and any required listeners. If chunks do not need to be extended, * merely configured differently there is the {@link IChunkConfigurator}. * * @see http://jactr.org/node/121 * @author harrison */ public class DefaultDeclarativeModule extends AbstractDeclarativeModule implements IDeclarativeModule, IParameterized, IRemovableDeclarativeModule { /** * logger definition */ static final Log LOGGER = LogFactory .getLog(DefaultDeclarativeModule.class); static public final String CHUNK_FACTORY_PARAM = "ChunkFactoryClass"; static public final String SYMBOLIC_CHUNK_FACTORY_PARAM = "SymbolicChunkFactoryClass"; static public final String SUBSYMBOLIC_CHUNK_FACTORY_PARAM = "SubsymbolicChunkFactoryClass"; static public final String CHUNK_TYPE_FACTORY_PARAM = "ChunkTypeFactoryClass"; static public final String SYMBOLIC_CHUNK_TYPE_FACTORY_PARAM = "SymbolicChunkTypeFactoryClass"; static public final String SUBSYMBOLIC_CHUNK_TYPE_FACTORY_PARAM = "SubsymbolicChunkTypeFactoryClass"; static public final String CHUNK_NAMER_PARAM = "ChunkNamerClass"; static public final String CHUNK_CONFIGURATOR_PARAM = "ChunkConfiguratorClass"; static public final String CHUNK_TYPE_NAMER_PARAM = "ChunkTypeNamerClass"; static public final String CHUNK_TYPE_CONFIGURATOR_PARAM = "ChunkTypeConfiguratorClass"; protected ReentrantReadWriteLock _chunkTypeLock; protected ReentrantReadWriteLock _chunkLock; protected DefaultSearchSystem _searchSystem; protected Map<String, IChunk> _allChunks; protected Map<String, IChunkType> _allChunkTypes; /** * used to encode chunks after removal */ protected IActivationBufferListener _encodeChunksOnRemove; public DefaultDeclarativeModule() { super("declarative"); setAssociativeLinkageSystem(new DefaultAssociativeLinkageSystem()); _allChunks = new TreeMap<String, IChunk>(); _allChunkTypes = new TreeMap<String, IChunkType>(); _searchSystem = new DefaultSearchSystem(this); _chunkLock = new ReentrantReadWriteLock(); _chunkTypeLock = new ReentrantReadWriteLock(); setChunkFactory(new DefaultChunkFactory()); setSymbolicChunkFactory(new DefaultSymbolicChunkFactory()); setSubsymbolicChunkFactory(new DefaultSubsymbolicChunkFactory5()); setChunkTypeFactory(new DefaultChunkTypeFactory()); setSymbolicChunkTypeFactory(new DefaultSymbolicChunkTypeFactory()); setSubsymbolicChunkTypeFactory(new DefaultSubsymbolicChunkTypeFactory()); _encodeChunksOnRemove = new IActivationBufferListener() { public void chunkMatched(ActivationBufferEvent abe) { // noop } public void requestAccepted(ActivationBufferEvent abe) { // noop } public void sourceChunkAdded(ActivationBufferEvent abe) { // noop } public void sourceChunkRemoved(ActivationBufferEvent abe) { /* * queue up the encoding. we dont encode it here so that any inline * listeners after this one will get the actual instance of the removed * chunk and not the merged version after encoding (if a merge occurs) */ if (!abe.getSource().handlesEncoding()) deferredEncode(abe.getSourceChunks()); } public void sourceChunksCleared(ActivationBufferEvent abe) { sourceChunkRemoved(abe); } public void statusSlotChanged(ActivationBufferEvent abe) { // noop } @SuppressWarnings("unchecked") public void parameterChanged(IParameterEvent pe) { // noop } }; } @Override synchronized public void dispose() { for (IActivationBuffer buffer : getModel().getActivationBuffers()) buffer.removeListener(_encodeChunksOnRemove); _searchSystem.clear(); _searchSystem = null; try { _chunkTypeLock.writeLock().lock(); // dispose of all the chunktypes (and chunks by extension) for (IChunkType chunkType : _allChunkTypes.values()) chunkType.dispose(); _allChunkTypes.clear(); } finally { _chunkTypeLock.writeLock().unlock(); } try { _chunkLock.writeLock().lock(); _allChunks.clear(); } finally { _chunkLock.writeLock().unlock(); } super.dispose(); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override protected IChunk addChunkInternal(IChunk chunk, Collection<IChunk> possibleMatches) { if (possibleMatches.size() > 0) { if (LOGGER.isDebugEnabled()) LOGGER.debug("chunk " + chunk + " has yielded " + possibleMatches.size() + " matches " + possibleMatches); if (possibleMatches.size() > 1) if (LOGGER.isWarnEnabled()) LOGGER.warn(String.format( "Found multiple identical chunks to %s : %s", chunk, possibleMatches)); IChunk mergeInto = possibleMatches.iterator().next(); if (possibleMatches instanceof ConcurrentSkipListSet) SkipListSetFactory.recycle((ConcurrentSkipListSet) possibleMatches); return merge(mergeInto, chunk); } double now = getModel().getAge(); boolean added = false; try { _chunkLock.writeLock().lock(); String name = getChunkNamer().generateName(chunk); String newName = getSafeName(name, _allChunks); if (LOGGER.isDebugEnabled()) LOGGER.debug("Safe name for chunk " + name + " is " + newName); chunk.getSymbolicChunk().setName(newName); /* * notify the chunktype of this chunk */ chunk.setMetaData(IChunkFactory.COPIED_FROM_KEY, null); chunk.getSymbolicChunk().getChunkType().getSymbolicChunkType() .addChunk(chunk); _allChunks.put(newName.toLowerCase(), chunk); added = true; return chunk; } finally { _chunkLock.writeLock().unlock(); // this will fire some chunk event.. so get out of the lock if (added) { if (LOGGER.isDebugEnabled()) LOGGER.debug("Encoding " + chunk); chunk.encode(now); if (Logger.hasLoggers(getModel())) Logger.log(getModel(), Logger.Stream.DECLARATIVE, "Encoded " + StringUtilities.toString(chunk)); /* * we index after since an unencoded chunk wont be indexed */ _searchSystem.index(chunk); fireChunkAdded(chunk); } } } /** * merely remove the chunk from the internal DM store and the chunktype store. * Other chunk references to the removed chunk will be unaffected. There is no * tombstone marking. The removed chunk itself is not disposed of. if all is * successful, this will fire the chunk removed event. * * @param chunk */ public void removeChunk(final IChunk chunk) { delayedFuture(new Callable<IChunk>() { public IChunk call() throws Exception { try { removeChunkInternal(chunk); } catch (Exception e) { LOGGER.error("Error while removing chunk " + chunk + " ", e); throw e; } return chunk; } }, getExecutor()); } protected void removeChunkInternal(IChunk chunk) { boolean removed = false; // noop if (!chunk.isEncoded() || chunk.hasBeenDisposed()) { if (LOGGER.isDebugEnabled()) LOGGER .debug(String .format( "%s has not been encoded or has been disposed of, no need to remove", chunk)); return; } ISymbolicChunk sc = chunk.getSymbolicChunk(); chunk.getSubsymbolicChunk(); String chunkName = sc.getName(); try { _chunkLock.writeLock().lock(); /* * we merely remove the chunk from our indices */ IChunk removedChunk = _allChunks.remove(chunkName.toLowerCase()); removed = removedChunk != null; // we can only remove from chunktype if it is supported if (removed) { /* * just so that we are sure we are using the encoded chunk handle and * not a merged, restored, or otherwise indirect handle */ chunk = removedChunk; ISymbolicChunkType ct = sc.getChunkType().getSymbolicChunkType(); IRemovableSymbolicChunkType rct = ct .getAdapter(IRemovableSymbolicChunkType.class); if (rct != null) rct.removeChunk(chunk); _searchSystem.unindex(chunk); } } catch (Exception e) { LOGGER.error(String.format("Failed to remove chunk %s", chunk), e); } finally { _chunkLock.writeLock().unlock(); if (removed) { if (Logger.hasLoggers(getModel())) Logger.log(getModel(), Logger.Stream.DECLARATIVE, "Removed " + StringUtilities.toString(chunk)); fireChunkRemoved(chunk); } } } /** * create a callable that will do all the work of adding a chunktype to the * model and firing the appropriate events * * @param chunkType * @return */ @Override protected IChunkType addChunkTypeInternal(IChunkType chunkType) { if (LOGGER.isDebugEnabled()) LOGGER.debug("Adding chunkType " + chunkType); boolean added = false; try { _chunkTypeLock.writeLock().lock(); ISymbolicChunkType sct = chunkType.getSymbolicChunkType(); String name = getChunkTypeNamer().generateName(chunkType); name = getSafeName(name, _allChunkTypes); sct.setName(name); _allChunkTypes.put(name.toLowerCase(), chunkType); addChunkTypeToParents(chunkType, chunkType.getSymbolicChunkType() .getParents()); added = true; return chunkType; } finally { _chunkTypeLock.writeLock().unlock(); // this will fire an event, so get out of the lock if (added) { chunkType.encode(); if (Logger.hasLoggers(getModel())) Logger.log(getModel(), Logger.Stream.DECLARATIVE, "Encoded " + chunkType); fireChunkTypeAdded(chunkType); } } } private void addChunkTypeToParents(IChunkType chunkType, Collection<IChunkType> parents) { for (IChunkType parent : parents) { parent.getSymbolicChunkType().addChild(chunkType); addChunkTypeToParents(chunkType, parent.getSymbolicChunkType() .getParents()); } } public ISearchSystem getSearchSystem() { return _searchSystem; } protected Collection<IChunk> findExactMatchesInternal( ChunkTypeRequest pattern, final Comparator<IChunk> sorter, IChunkFilter filter) { TextBuilder logMessage = null; SortedSet<IChunk> candidates = _searchSystem.findExact(pattern, sorter, filter); if (filter instanceof ILoggedChunkFilter) logMessage = ((ILoggedChunkFilter) filter).getMessageBuilder(); // just incase a message builder wasn't created if (logMessage == null && Logger.hasLoggers(getModel())) logMessage = new TextBuilder(); if (LOGGER.isDebugEnabled()) LOGGER.debug("find exact matches (" + pattern + ") evaluating " + candidates.size() + " candidates"); if (Logger.hasLoggers(getModel())) logMessage.insert(0, String.format("Evaluating exact matches : %s \n", candidates)); if (Logger.hasLoggers(getModel())) Logger.log(getModel(), Logger.Stream.DECLARATIVE, logMessage.toString()); // clean up // if (candidates instanceof FastSet) FastSet.recycle((FastSet) candidates); // logMessage.delete(0, logMessage.length()); return candidates; } protected Collection<IChunk> findPartialMatchesInternal( ChunkTypeRequest pattern, Comparator<IChunk> sorter, IChunkFilter filter) { if (LOGGER.isDebugEnabled()) LOGGER.debug("find partial matches (" + pattern + ")"); SortedSet<IChunk> candidates = _searchSystem.findFuzzy(pattern, sorter, filter); TextBuilder logMessage = null; if (filter instanceof ILoggedChunkFilter) logMessage = ((ILoggedChunkFilter) filter).getMessageBuilder(); else logMessage = new TextBuilder(); if (Logger.hasLoggers(getModel())) { logMessage.insert(0, String.format("Evaluating partial matches : %s \n", candidates)); Logger.log(getModel(), Logger.Stream.DECLARATIVE, logMessage.toString()); } return candidates; } @Override protected IChunk getChunkInternal(String name) { return _allChunks.get(name.toLowerCase()); } @Override protected IChunkType getChunkTypeInternal(String name) { return _allChunkTypes.get(name.toLowerCase()); } @Override protected Collection<IChunkType> getChunkTypesInternal() { return new ArrayList<IChunkType>(_allChunkTypes.values()); } @Override protected Collection<IChunk> getChunksInternal() { return new ArrayList<IChunk>(_allChunks.values()); } public long getNumberOfChunks() { try { _chunkLock.readLock().lock(); return _allChunks.size(); } finally { _chunkLock.readLock().unlock(); } } /** * here we attach a buffer listener to all the buffers and catch the removal * notifications to see if we should encode the chunk.. * * @see org.jactr.core.module.AbstractModule#initialize() */ @Override public void initialize() { super.initialize(); IModel model = getModel(); for (IActivationBuffer buffer : model.getActivationBuffers()) buffer.addListener(_encodeChunksOnRemove, ExecutorServices.INLINE_EXECUTOR); } /** * @see org.jactr.core.module.declarative.six.AbstractDeclarativeModule#copyChunkInternal(org.jactr.core.chunk.IChunk, * org.jactr.core.chunk.IChunk) */ /** * @see org.jactr.core.module.declarative.IDeclarativeModule#findExactMatches(ChunkTypeRequest, * java.util.Comparator, IChunkFilter) */ public CompletableFuture<Collection<IChunk>> findExactMatches( final ChunkTypeRequest request, final Comparator<IChunk> sorter, final IChunkFilter filter) { return delayedFuture(new Callable<Collection<IChunk>>() { public Collection<IChunk> call() throws Exception { return findExactMatchesInternal(request, sorter, filter); } }, getExecutor()); } /** * @see org.jactr.core.module.declarative.IDeclarativeModule#findPartialMatches(ChunkTypeRequest, * java.util.Comparator, IChunkFilter) */ public CompletableFuture<Collection<IChunk>> findPartialMatches( final ChunkTypeRequest request, final Comparator<IChunk> sorter, final IChunkFilter filter) { return delayedFuture(new Callable<Collection<IChunk>>() { public Collection<IChunk> call() throws Exception { return findPartialMatchesInternal(request, sorter, filter); } }, getExecutor()); } public String getParameter(String key) { if (CHUNK_FACTORY_PARAM.equalsIgnoreCase(key)) return getChunkFactory().getClass().getName(); else if (SYMBOLIC_CHUNK_FACTORY_PARAM.equalsIgnoreCase(key)) return getSymbolicChunkFactory().getClass().getName(); else if (SUBSYMBOLIC_CHUNK_FACTORY_PARAM.equalsIgnoreCase(key)) return getSubsymbolicChunkFactory().getClass().getName(); else if (CHUNK_TYPE_FACTORY_PARAM.equalsIgnoreCase(key)) return getChunkTypeFactory().getClass().getName(); else if (SYMBOLIC_CHUNK_TYPE_FACTORY_PARAM.equalsIgnoreCase(key)) return getSymbolicChunkTypeFactory().getClass().getName(); else if (SUBSYMBOLIC_CHUNK_TYPE_FACTORY_PARAM.equalsIgnoreCase(key)) return getSubsymbolicChunkTypeFactory().getClass().getName(); else if (CHUNK_NAMER_PARAM.equalsIgnoreCase(key)) return getChunkNamer().getClass().getName(); else if (CHUNK_CONFIGURATOR_PARAM.equalsIgnoreCase(key)) return getChunkConfigurator().getClass().getName(); else if (CHUNK_TYPE_NAMER_PARAM.equalsIgnoreCase(key)) return getChunkTypeNamer().getClass().getName(); else if (CHUNK_TYPE_CONFIGURATOR_PARAM.equalsIgnoreCase(key)) return getChunkTypeConfigurator().getClass().getName(); return null; } public Collection<String> getPossibleParameters() { return getSetableParameters(); } public Collection<String> getSetableParameters() { Collection<String> rtn = new ArrayList<String>(10); rtn.add(CHUNK_FACTORY_PARAM); rtn.add(SYMBOLIC_CHUNK_FACTORY_PARAM); rtn.add(SUBSYMBOLIC_CHUNK_FACTORY_PARAM); rtn.add(CHUNK_NAMER_PARAM); rtn.add(CHUNK_CONFIGURATOR_PARAM); rtn.add(CHUNK_TYPE_FACTORY_PARAM); rtn.add(SYMBOLIC_CHUNK_TYPE_FACTORY_PARAM); rtn.add(SUBSYMBOLIC_CHUNK_TYPE_FACTORY_PARAM); rtn.add(CHUNK_TYPE_NAMER_PARAM); rtn.add(CHUNK_TYPE_CONFIGURATOR_PARAM); return rtn; } public void setParameter(String key, String value) { if (CHUNK_FACTORY_PARAM.equalsIgnoreCase(key)) { IChunkFactory factory = (IChunkFactory) instantiate(value); if (factory == null) { if (LOGGER.isWarnEnabled()) LOGGER.warn(String.format("Could not instantiate %s", value)); factory = new DefaultChunkFactory(); } setChunkFactory(factory); } else if (SYMBOLIC_CHUNK_FACTORY_PARAM.equalsIgnoreCase(key)) { ISymbolicChunkFactory factory = (ISymbolicChunkFactory) instantiate(value); if (factory == null) { if (LOGGER.isWarnEnabled()) LOGGER.warn(String.format("Could not instantiate %s", value)); factory = new DefaultSymbolicChunkFactory(); } setSymbolicChunkFactory(factory); } else if (SUBSYMBOLIC_CHUNK_FACTORY_PARAM.equalsIgnoreCase(key)) { ISubsymbolicChunkFactory factory = (ISubsymbolicChunkFactory) instantiate(value); if (factory == null) { if (LOGGER.isWarnEnabled()) LOGGER.warn(String.format("Could not instantiate %s", value)); factory = new DefaultSubsymbolicChunkFactory5(); } setSubsymbolicChunkFactory(factory); } else if (CHUNK_TYPE_FACTORY_PARAM.equalsIgnoreCase(key)) { IChunkTypeFactory factory = (IChunkTypeFactory) instantiate(value); if (factory == null) { if (LOGGER.isWarnEnabled()) LOGGER.warn(String.format("Could not instantiate %s", value)); factory = new DefaultChunkTypeFactory(); } setChunkTypeFactory(factory); } else if (SYMBOLIC_CHUNK_TYPE_FACTORY_PARAM.equalsIgnoreCase(key)) { ISymbolicChunkTypeFactory factory = (ISymbolicChunkTypeFactory) instantiate(value); if (factory == null) { if (LOGGER.isWarnEnabled()) LOGGER.warn(String.format("Could not instantiate %s", value)); factory = new DefaultSymbolicChunkTypeFactory(); } setSymbolicChunkTypeFactory(factory); } else if (SUBSYMBOLIC_CHUNK_TYPE_FACTORY_PARAM.equalsIgnoreCase(key)) { ISubsymbolicChunkTypeFactory factory = (ISubsymbolicChunkTypeFactory) instantiate(value); if (factory == null) { if (LOGGER.isWarnEnabled()) LOGGER.warn(String.format("Could not instantiate %s", value)); factory = new DefaultSubsymbolicChunkTypeFactory(); } setSubsymbolicChunkTypeFactory(factory); } else if (CHUNK_NAMER_PARAM.equalsIgnoreCase(key)) { IChunkNamer factory = (IChunkNamer) instantiate(value); if (factory == null) { if (LOGGER.isWarnEnabled()) LOGGER.warn(String.format("Could not instantiate %s", value)); factory = new NoOpChunkNamer(); } setChunkNamer(factory); } else if (CHUNK_CONFIGURATOR_PARAM.equalsIgnoreCase(key)) { IChunkConfigurator factory = (IChunkConfigurator) instantiate(value); if (factory == null) { if (LOGGER.isWarnEnabled()) LOGGER.warn(String.format("Could not instantiate %s", value)); factory = new NoOpChunkConfigurator(); } setChunkConfigurator(factory); } else if (CHUNK_TYPE_NAMER_PARAM.equalsIgnoreCase(key)) { IChunkTypeNamer factory = (IChunkTypeNamer) instantiate(value); if (factory == null) { if (LOGGER.isWarnEnabled()) LOGGER.warn(String.format("Could not instantiate %s", value)); factory = new NoOpChunkTypeNamer(); } setChunkTypeNamer(factory); } else if (CHUNK_TYPE_CONFIGURATOR_PARAM.equalsIgnoreCase(key)) { IChunkTypeConfigurator factory = (IChunkTypeConfigurator) instantiate(value); if (factory == null) { if (LOGGER.isWarnEnabled()) LOGGER.warn(String.format("Could not instantiate %s", value)); factory = new NoOpChunkTypeConfigurator(); } setChunkTypeConfigurator(factory); } else if (LOGGER.isWarnEnabled()) LOGGER.warn(String.format( "%s doesn't recognize %s. Available parameters : %s", getClass() .getSimpleName(), key, getSetableParameters())); } private Object instantiate(String className) { ClassNameParameterHandler ph = ParameterHandler.classInstance(); try { return ph.coerce(className).newInstance(); } catch (Exception e) { return null; } } public void reset() {// noop } }