/**
* Copyright (C) 2001-3, Anthony Harrison anh23@pitt.edu 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.production.action;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jactr.core.buffer.IActivationBuffer;
import org.jactr.core.buffer.IRequestableBuffer;
import org.jactr.core.buffer.delegate.AddChunkRequestDelegate;
import org.jactr.core.buffer.delegate.AddChunkTypeRequestDelegate;
import org.jactr.core.chunk.IChunk;
import org.jactr.core.chunktype.IChunkType;
import org.jactr.core.model.IModel;
import org.jactr.core.production.CannotInstantiateException;
import org.jactr.core.production.IInstantiation;
import org.jactr.core.production.request.ChunkRequest;
import org.jactr.core.production.request.ChunkTypeRequest;
import org.jactr.core.production.request.IRequest;
import org.jactr.core.production.request.SlotBasedRequest;
import org.jactr.core.slot.DefaultConditionalSlot;
import org.jactr.core.slot.IMutableSlot;
import org.jactr.core.slot.ISlot;
/**
* AddAction represents the consequence of adding a chunk to a buffer. It can
* add an existing chunk to a buffer, add a chunk that is referenced by a
* variable name, or to create a new chunk in the buffer.
*
* @author harrison
* @created January 22, 2003
*/
public class AddAction extends DefaultAction implements IBufferAction,
org.jactr.core.slot.ISlotContainer
{
private static transient Log LOGGER = LogFactory
.getLog(AddAction.class
.getName());
static private AddChunkTypeRequestDelegate _chunkTypeDelegate;
static private AddChunkRequestDelegate _chunkDelegate;
static
{
_chunkTypeDelegate = new AddChunkTypeRequestDelegate();
_chunkTypeDelegate.setAsynchronous(true);
_chunkDelegate = new AddChunkRequestDelegate(true);
_chunkDelegate.setAsynchronous(true);
}
/**
* the name of the buffer for the chunk to be inserted into
*
* @since
*/
private String _bufferName;
// required
/**
* a map of slots to be assigned to the to be inserted chunk
*
* @since
*/
private Collection<IMutableSlot> _slots;
/**
* referant can be either a chunkname, a variable name, a chunktype or a chunk
* proper
*
* @since
*/
private Object _referant;
/**
* default constructor equivalent to AddAction("goal", null)
*
* @since
*/
public AddAction()
{
this(IActivationBuffer.GOAL, (Object) null);
}
/**
* add a chunk (ref) to bufferName buffer
*
* @param bufferName
* name of the buffer to insert into
* @param ref
* IChunk, IChunkType, chunkName, or variable name
* @since
*/
public AddAction(String bufferName, Object ref,
Collection<? extends ISlot> slots)
{
_bufferName = bufferName.toLowerCase();
_slots = new ArrayList<IMutableSlot>(slots.size());
_referant = ref;
for (ISlot slot : slots)
addSlot(slot);
}
@SuppressWarnings("unchecked")
public AddAction(String bufferName, Object ref)
{
this(bufferName, ref, Collections.EMPTY_LIST);
}
/**
* Description of the Method
*
* @return Description of the Returned Value
* @since
*/
@Override
public String toString()
{
return String.format("Add(%s, %s)", _bufferName, _referant);
}
/**
* Description of the Method
*
* @since
*/
@Override
public void dispose()
{
if (LOGGER.isDebugEnabled()) LOGGER.debug("dispose : " + this);
super.dispose();
if (_slots != null) _slots.clear();
_slots = null;
_referant = null;
}
/**
* Gets the referant attribute of the AddAction object
*
* @return The referant value
* @since
*/
public Object getReferant()
{
return _referant;
}
/**
* Sets the referant attribute of the AddAction object
*
* @param o
* The new referant value
* @since
*/
public void setReferant(Object o)
{
_referant = o;
}
public IAction bind(Map<String, Object> bindings)
throws CannotInstantiateException
{
AddAction action = new AddAction(getBufferName(), getReferant(), _slots);
action.bindChunk(bindings);
action.bindSlotValues(bindings, action._slots);
return action;
}
protected void bindChunk(Map<String, Object> bindings)
throws CannotInstantiateException
{
String name = getChunkName();
if (name != null)
if (name.startsWith("="))
{
/*
* the punk is a variable name..
*/
Object resolved = resolve(name, bindings);
if (resolved == null)
throw new CannotInstantiateException(
"Could not resolve variable name " + name + " possible:"
+ bindings);
if (LOGGER.isDebugEnabled())
LOGGER.debug("Resolved " + name + " to " + resolved + "("
+ resolved.getClass().getName() + ") " + bindings);
setReferant(resolved);
}
}
/**
* return the name of the buffer that the chunk will be added to
*
* @return The bufferName value
* @since
*/
public String getBufferName()
{
return _bufferName;
}
/**
* override the constructor and set the buffer name
*
* @param name
* The new bufferName value
* @since
*/
public void setBufferName(String name)
{
_bufferName = name.toLowerCase();
}
/**
* set the chunktype of the chunk to be created
*
* @param ct
* The new chunkType value
* @since
*/
public void setChunkType(IChunkType ct)
{
_referant = ct;
}
/**
* set the variable name of the chunk to be added. This must be a valid
* variable name and must be previously defined by a condition or another
* action
*
* @param name
* The new chunkName value
* @since
*/
public void setChunkName(String name)
{
_referant = name;
}
/**
* set the chunk that will be added to the buffer
*
* @param c
* The new chunk value
* @since
*/
public void setChunk(IChunk c)
{
_referant = c;
}
/**
* return the variable name of the chunk if it has been specified, null
* otherwise
*
* @return The chunkName value
* @since
*/
public String getChunkName()
{
if (_referant instanceof String) return (String) _referant;
return null;
}
/**
* return the chunktype of the to-be created chunk if it has been specified,
* null otherwise
*
* @return The chunkType value
* @since
*/
public IChunkType getChunkType()
{
if (_referant instanceof IChunkType) return (IChunkType) _referant;
return null;
}
/**
* return the chunk to be added if it was specified.
*
* @return The chunk value
* @since
*/
public IChunk getChunk()
{
if (_referant instanceof IChunk) return (IChunk) _referant;
return null;
}
protected Collection<IMutableSlot> getSlotsInternal()
{
return _slots;
}
/**
* Return all the slots that this addaction will attempt to set for the to be
* added chunk.
*
* @return The slots value
* @since
*/
public Collection<? extends ISlot> getSlots()
{
return Collections.unmodifiableCollection(_slots);
}
public Collection<ISlot> getSlots(Collection<ISlot> slots)
{
if (slots == null) slots = new ArrayList<ISlot>();
slots.addAll(_slots);
return slots;
}
/**
* In addition to adding chunks to a buffer, the IChunk?s slot values can be
* changed at the same time. This prevents the need to an additional action
* just to change the slot values. The slot added will be used to modify the
* same named slot in the chunk.
*
* @param s
* The feature to be added to the ISlot attribute
* @since
*/
public void addSlot(ISlot s)
{
_slots.add(new DefaultConditionalSlot(s));
}
/**
* Remove a specific slot from the addaction.
*
* @param s
* Description of Parameter
* @since
*/
public void removeSlot(ISlot s)
{
_slots.remove(s);
}
protected IRequest createRequest()
{
IRequest request = null;
Object referant = getReferant();
if (referant instanceof IRequest)
request = (IRequest) referant;
else if (referant instanceof IChunk)
/*
* +buffer> chunk (or =chunk)
*/
request = new ChunkRequest((IChunk) referant, _slots);
else if (referant instanceof IChunkType) /*
* +buffer> isa chunk
*/
request = new ChunkTypeRequest((IChunkType) referant, _slots);
else
/*
* +buffer> slot value
*/
request = new SlotBasedRequest(_slots);
return request;
}
@Override
public double fire(IInstantiation instantiation, double firingTime)
{
/*
* this handles two basic set ups.. if the buffer handles requests, the
* request is created and passed on directly. otherwise, it is redirected
* through the request delegates..
*/
IModel model = instantiation.getModel();
IActivationBuffer buffer = model.getActivationBuffer(getBufferName());
// ITimedEvent event = null;
// double pFire = instantiation.getSubsymbolicProduction().getFiringTime();
// double endTime = firingTime + pFire;
IRequest request = createRequest();
if (buffer instanceof IRequestableBuffer)
{
IRequestableBuffer rBuffer = (IRequestableBuffer) buffer;
if (rBuffer.willAccept(request))
rBuffer.request(request, firingTime);
else
throw new IllegalActionStateException(rBuffer.getName()
+ " rejected processing of request " + request);
}
else /*
* wasn't accepted directly.. we'll do so indirectly
*/
if (request instanceof ChunkRequest)
_chunkDelegate.request(request, buffer, firingTime);
else if (request instanceof ChunkTypeRequest)
_chunkTypeDelegate.request(request, buffer, firingTime);
else
throw new IllegalActionStateException(buffer.getName()
+ " cannot accept slot only requests");
// model.getTimedEventQueue().enqueue(event);
// /*
// * We will add all of these events with a start time of now and a firing
// * time of now + pFire. This means that when the production has "finished"
// * firing, all of these events will be fired off as well.
// */
//
// /*
// * if a chunktype is specified it is either a pattern addition or a chunk
// * create and insert..
// */
// if (chunkType != null)
// {
// /*
// * pattern..
// */
// boolean handled = false;
// if (buffer instanceof IRequestableBuffer)
// {
// IRequestableBuffer pBuff = (IRequestableBuffer) buffer;
// ChunkPattern pattern = new ChunkPattern(chunkType, getSlots());
//
// if (pBuff.willAccept(pattern))
// {
// fireTime = firingTime + pFire;
//
// event = new DelayedBufferInsertionTimedEvent(buffer, pattern, firingTime,
// fireTime);
// handled = true;
// }
// }
//
// if (!handled)
// {
// /*
// * we need to create a new chunk..
// */
// Future<IChunk> newChunk = model.getDeclarativeModule().createChunk(
// chunkType, null);
// event = new FutureChunkInsertionTimedEvent(newChunk, buffer, firingTime,
// fireTime) {
// @Override
// public void fire(double currentTime)
// {
// IChunk chunk = null;
// try
// {
// chunk = getFutureChunk().get();
// updateSlots(chunk, getSlots());
// super.fire(currentTime);
// }
// catch (Exception e)
// {
// throw new IllegalActionStateException(
// "Could not get chunk from future", e);
// }
// }
// };
// }
// }
//
// /*
// * perhaps the chunk was specified exactly?
// */
// IChunk chunk = getChunk();
// if (chunk != null)
// event = new DelayedBufferInsertionTimedEvent(buffer, chunk, firingTime,
// fireTime) {
// @Override
// public void fire(double currentTime)
// {
// /*
// * this chunk was likely already encoded, so we insert it first, snag
// * the actual chunk added (likely a copy), and then modify it.
// */
// super.fire(currentTime);
// updateSlots(getInsertedChunk(), getSlots());
// }
// };
//
// /*
// * perhaps it was a specified name?
// */
// final String chunkName = getChunkName();
// if (chunkName != null)
// {
// if (LOGGER.isDebugEnabled())
// LOGGER.debug("Searching for chunk named " + chunkName);
// Future<IChunk> fetchedChunk = model.getDeclarativeModule().getChunk(
// chunkName);
// event = new FutureChunkInsertionTimedEvent(fetchedChunk, buffer,
// firingTime,
// fireTime) {
// @Override
// public void fire(double currentTime)
// {
// /*
// * let it insert the chunk, then we snag the chunk that is actually in
// * the buffer (likely a copy) and modify it
// */
// super.fire(currentTime);
//
// IChunk inserted = getInsertedChunk();
// if (inserted == null)
// throw new RuntimeException("Could not find any chunk named "
// + chunkName);
//
// updateSlots(inserted, getSlots());
// }
// };
// }
//
//
return 0;
}
}