package org.jactr.core.module.declarative.basic;
/*
* default logging
*/
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jactr.core.chunk.IChunk;
import org.jactr.core.chunktype.IChunkType;
import org.jactr.core.event.ACTREventDispatcher;
import org.jactr.core.module.AbstractModule;
import org.jactr.core.module.declarative.IDeclarativeModule;
import org.jactr.core.module.declarative.event.DeclarativeModuleEvent;
import org.jactr.core.module.declarative.event.IDeclarativeModuleListener;
/**
* @author harrison
*/
public abstract class AbstractDeclarativeModule extends AbstractModule
implements IDeclarativeModule
{
/**
* Logger definition
*/
static private final transient Log LOGGER = LogFactory
.getLog(AbstractDeclarativeModule.class);
private IChunk _freeChunk;
private IChunk _busyChunk;
private IChunk _errorChunk;
private IChunk _emptyChunk;
private IChunk _fullChunk;
private IChunk _newChunk;
private IChunk _requestedChunk;
private IChunk _unrequestedChunk;
private ACTREventDispatcher<IDeclarativeModule, IDeclarativeModuleListener> _eventDispatcher;
public AbstractDeclarativeModule(String name)
{
super(name);
_eventDispatcher = new ACTREventDispatcher<IDeclarativeModule, IDeclarativeModuleListener>();
}
@SuppressWarnings("unchecked")
@Override
public void initialize()
{
}
public void addListener(IDeclarativeModuleListener listener, Executor executor)
{
_eventDispatcher.addListener(listener, executor);
}
public void removeListener(IDeclarativeModuleListener listener)
{
_eventDispatcher.removeListener(listener);
}
protected void fireChunkCreated(IChunk chunk)
{
if (_eventDispatcher.hasListeners())
_eventDispatcher.fire(new DeclarativeModuleEvent(this,
DeclarativeModuleEvent.Type.CHUNK_CREATED, chunk));
}
protected void fireChunkTypeCreated(IChunkType chunkType)
{
if (_eventDispatcher.hasListeners())
_eventDispatcher.fire(new DeclarativeModuleEvent(this,
DeclarativeModuleEvent.Type.CHUNK_TYPE_CREATED, chunkType));
}
protected void fireChunkAdded(IChunk chunk)
{
if (_eventDispatcher.hasListeners())
_eventDispatcher.fire(new DeclarativeModuleEvent(this,
DeclarativeModuleEvent.Type.CHUNK_ADDED, chunk));
}
protected void fireChunkTypeAdded(IChunkType chunkType)
{
if (_eventDispatcher.hasListeners())
_eventDispatcher.fire(new DeclarativeModuleEvent(this,
DeclarativeModuleEvent.Type.CHUNK_TYPE_ADDED, chunkType));
}
protected void fireChunksMerged(IChunk original, IChunk duplicateChunk)
{
if (_eventDispatcher.hasListeners())
_eventDispatcher.fire(new DeclarativeModuleEvent(this,
DeclarativeModuleEvent.Type.CHUNKS_MERGED, original, duplicateChunk));
}
protected void fireChunkTypesMerged(IChunkType original, IChunkType duplicate)
{
if (_eventDispatcher.hasListeners())
_eventDispatcher.fire(new DeclarativeModuleEvent(this,
DeclarativeModuleEvent.Type.CHUNK_TYPES_MERGED, original, duplicate));
}
protected boolean hasListeners()
{
return _eventDispatcher.hasListeners();
}
protected void dispatch(DeclarativeModuleEvent event)
{
_eventDispatcher.fire(event);
}
public IChunk getBusyChunk()
{
return _busyChunk;
}
public IChunk getEmptyChunk()
{
return _emptyChunk;
}
public IChunk getErrorChunk()
{
return _errorChunk;
}
public IChunk getFreeChunk()
{
return _freeChunk;
}
public IChunk getFullChunk()
{
return _fullChunk;
}
public IChunk getNewChunk()
{
return _newChunk;
}
public IChunk getRequestedChunk()
{
return _requestedChunk;
}
public IChunk getUnrequestedChunk()
{
return _unrequestedChunk;
}
/**
* create a chunk by delegating to
* {@link #createChunkInternal(IChunkType, String)} on {@link #getExecutor()}
*
* @param parent
* @param name
* @return
* @see org.jactr.core.module.declarative.IDeclarativeModule#createChunk(org.jactr.core.chunktype.IChunkType,
* java.lang.String)
*/
public Future<IChunk> createChunk(final IChunkType parent, final String name)
{
if (parent == null)
throw new NullPointerException("IChunkType cannot be null");
return delayedFuture(new Callable<IChunk>() {
public IChunk call() throws Exception
{
return createChunkInternal(parent, name);
}
}, getExecutor());
}
/**
* create the chunk
*
* @param parent
* @param name
* @return
*/
abstract protected IChunk createChunkInternal(IChunkType parent, String name);
/**
* add chunk to DM. merely delegates to {@link #addChunkInternal(IChunk)} on
* {@link #getExecutor()}
*
* @param chunk
* @return
* @see org.jactr.core.module.declarative.IDeclarativeModule#addChunk(org.jactr.core.chunk.IChunk)
*/
public Future<IChunk> addChunk(final IChunk chunk)
{
if (chunk.isEncoded())
{
if (LOGGER.isDebugEnabled())
LOGGER.debug(chunk + " has already been encoded, silly");
return immediateReturn(chunk);
}
return delayedFuture(new Callable<IChunk>() {
public IChunk call() throws Exception
{
try
{
IChunk rtn = addChunkInternal(chunk);
String name = rtn.getSymbolicChunk().getName();
if (_busyChunk == null && name.equals("busy"))
_busyChunk = rtn;
else if (_emptyChunk == null && name.equals("empty"))
_emptyChunk = rtn;
else if (_errorChunk == null && name.equals("error"))
_errorChunk = rtn;
else if (_freeChunk == null && name.equals("free"))
_freeChunk = rtn;
else if (_fullChunk == null && name.equals("full"))
_fullChunk = rtn;
else if (_newChunk == null && name.equals("new"))
_newChunk = rtn;
else if (_requestedChunk == null && name.equals("requested"))
_requestedChunk = rtn;
else if (_unrequestedChunk == null && name.equals("unrequested"))
_unrequestedChunk = rtn;
return rtn;
}
catch (Exception e)
{
LOGGER.error("Error while encoding chunk "+chunk+" ",e);
throw e;
}
}
}, getExecutor());
}
/**
* add the chunk to DM on the module's executor. If the executor is INLINE or
* multiply threaded, thread safety is a must.
*
* @param chunkToAdd
* @return
*/
abstract protected IChunk addChunkInternal(IChunk chunkToAdd);
public Future<IChunk> copyChunk(final IChunk sourceChunk)
{
if (sourceChunk == null)
throw new NullPointerException("sourceChunk cannot be null");
return delayedFuture(new Callable<IChunk>() {
public IChunk call() throws Exception
{
String name = sourceChunk.getSymbolicChunk().getName();
IChunkType parent = sourceChunk.getSymbolicChunk().getChunkType();
IChunk copy = createChunkInternal(parent, name);
copyChunkInternal(sourceChunk, copy);
return copy;
}
}, getExecutor());
}
/**
* copy source to copy
*
* @param sourceChunk
* @param copy
*/
abstract protected void copyChunkInternal(IChunk sourceChunk, IChunk copy);
/**
* delegated
*
* @param name
* @return
* @see org.jactr.core.module.declarative.IDeclarativeModule#getChunk(java.lang.String)
*/
public Future<IChunk> getChunk(final String name)
{
Callable<IChunk> callable = new Callable<IChunk>() {
public IChunk call() throws Exception
{
return getChunkInternal(name);
}
};
return delayedFuture(callable, getExecutor());
}
abstract protected IChunk getChunkInternal(String chunkName);
/**
* @return
* @see org.jactr.core.module.declarative.IDeclarativeModule#getChunks()
*/
public Future<Collection<IChunk>> getChunks()
{
Callable<Collection<IChunk>> callable = new Callable<Collection<IChunk>>() {
public Collection<IChunk> call() throws Exception
{
return getChunksInternal();
}
};
return delayedFuture(callable, getExecutor());
}
abstract protected Collection<IChunk> getChunksInternal();
/**
* create chunktype, delegates to
* {@link #createChunkTypeInternal(IChunkType, String)} on
* {@link #getExecutor()}
*
* @param parent
* @param name
* @return
* @see org.jactr.core.module.declarative.IDeclarativeModule#createChunkType(org.jactr.core.chunktype.IChunkType,
* java.lang.String)
*/
public Future<IChunkType> createChunkType(final IChunkType parent,
final String name)
{
return delayedFuture(new Callable<IChunkType>() {
public IChunkType call() throws Exception
{
return createChunkTypeInternal(parent, name);
}
}, getExecutor());
}
/**
* @param parent
* @param name
* @return
*/
abstract protected IChunkType createChunkTypeInternal(IChunkType parent,
String name);
/**
* add chunktype to DM, delegated to {@link #addChunkTypeInternal(IChunkType)}
* on {@link #getExecutor()}
*
* @param chunkType
* @return
* @see org.jactr.core.module.declarative.IDeclarativeModule#addChunkType(org.jactr.core.chunktype.IChunkType)
*/
public Future<IChunkType> addChunkType(final IChunkType chunkType)
{
if (chunkType.isEncoded())
{
if (LOGGER.isDebugEnabled())
LOGGER.debug(chunkType + " has already been encoded silly");
return immediateReturn(chunkType);
}
return delayedFuture(new Callable<IChunkType>() {
public IChunkType call() throws Exception
{
return addChunkTypeInternal(chunkType);
}
}, getExecutor());
}
/**
* add the chunktype DM on the module's executor. If the executor is INLINE or
* multithreaded, thread safety is a must.
*
* @param chunkType
* @return
*/
abstract protected IChunkType addChunkTypeInternal(IChunkType chunkType);
/**
* delegated
*
* @param name
* @return
* @see org.jactr.core.module.declarative.IDeclarativeModule#getChunkType(java.lang.String)
*/
public Future<IChunkType> getChunkType(final String name)
{
Callable<IChunkType> callable = new Callable<IChunkType>() {
public IChunkType call() throws Exception
{
return getChunkTypeInternal(name);
}
};
return delayedFuture(callable, getExecutor());
}
abstract protected IChunkType getChunkTypeInternal(String name);
/**
* delegated
*
* @return
* @see org.jactr.core.module.declarative.IDeclarativeModule#getChunkTypes()
*/
public Future<Collection<IChunkType>> getChunkTypes()
{
Callable<Collection<IChunkType>> callable = new Callable<Collection<IChunkType>>() {
public Collection<IChunkType> call() throws Exception
{
return getChunkTypesInternal();
}
};
return delayedFuture(callable, getExecutor());
}
abstract protected Collection<IChunkType> getChunkTypesInternal();
}