/** * 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 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.VariableBindings; 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.DefaultVariableConditionalSlot; 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[%s])", _bufferName, _referant, _slots); } /** * 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(VariableBindings bindings) throws CannotInstantiateException { AddAction action = new AddAction(getBufferName(), getReferant(), _slots); action.bindChunk(bindings); action.bindSlotValues(bindings, action._slots); return action; } protected void bindChunk(VariableBindings 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((IMutableSlot)s.clone()); } /** * Remove a specific slot from the addaction. * * @param s * Description of Parameter * @since */ public void removeSlot(ISlot s) { _slots.remove(s); } /** * return a mutable copy of the request that underlies this action. * * @return */ public IRequest getRequest() { return createRequest(); } 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()); IRequest request = createRequest(); IRequestableBuffer rb = (IRequestableBuffer) buffer .getAdapter(IRequestableBuffer.class); if (rb != null) { if (rb.willAccept(request)) rb.request(request, firingTime); else throw new IllegalActionStateException(rb.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"); return 0; } }