/**
* 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.chunk.basic;
import java.util.concurrent.locks.Lock;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jactr.core.chunk.IChunk;
import org.jactr.core.chunk.ISymbolicChunk;
import org.jactr.core.chunk.IllegalChunkStateException;
import org.jactr.core.chunk.event.ChunkEvent;
import org.jactr.core.chunktype.IChunkType;
import org.jactr.core.slot.BasicSlot;
import org.jactr.core.slot.IMutableSlot;
import org.jactr.core.slot.ISlot;
import org.jactr.core.slot.NotifyingSlotContainer;
import org.jactr.core.utils.IAdaptable;
/**
* default symbolic chunk implementation
*
* @author harrison
* @created February 5, 2003
*/
public class BasicSymbolicChunk extends NotifyingSlotContainer implements
ISymbolicChunk, IAdaptable
{
private static transient Log LOGGER = LogFactory
.getLog(BasicSymbolicChunk.class
.getName());
protected IChunkType _chunkType;
protected String _chunkName;
protected IChunk _parentChunk;
private ISlot _chunkTypeSlot; // for
// efficiency
private static int TOTAL_COUNT = 0;
public BasicSymbolicChunk()
{
TOTAL_COUNT++;
}
public void bind(IChunk wrapper, IChunkType type)
{
clear();
_parentChunk = wrapper;
setChunkType(type);
}
protected Lock readLock()
{
return _parentChunk.getReadLock();
}
protected Lock writeLock()
{
return _parentChunk.getWriteLock();
}
/**
* cannot add/remove slots from a chunk
*/
public boolean canModify()
{
return false;
}
/**
* return the IChunk wrapper
*/
public IChunk getParentChunk()
{
return _parentChunk;
}
/**
* no op
*/
public void encode(double when)
{
}
/**
* @see org.jactr.core.chunk.ISymbolicChunk#getName()
*/
public String getName()
{
if (_chunkName == null || _chunkName == "")
setName(_chunkType.getSymbolicChunkType().getName() + "-" + TOTAL_COUNT);
Lock l = readLock();
try
{
l.lock();
return _chunkName;
}
finally
{
l.unlock();
}
}
/**
* set the chunk name, once encoded this will fail
*/
public void setName(String name)
{
if (_parentChunk.isEncoded())
throw new IllegalChunkStateException(
"Cannot change chunks name once encoded");
Lock l = writeLock();
try
{
l.lock();
if (_chunkName != null && _chunkName.equals(name)) return;
if (LOGGER.isDebugEnabled()) LOGGER.debug("Setting chunk name " + name);
_chunkName = name;
}
finally
{
l.unlock();
}
}
/**
* @see org.jactr.core.chunk.ISymbolicChunk#getChunkType()
*/
public IChunkType getChunkType()
{
return _chunkType;
}
/**
* @param ct
*/
private void setChunkType(IChunkType ct)
{
if (LOGGER.isDebugEnabled())
LOGGER.debug("Setting chunk type " + ct.getSymbolicChunkType().getName());
if (_chunkType != null)
throw new IllegalChunkStateException(
"Cannot overwrite parent IChunkType in chunk " + getName());
Lock l = writeLock();
try
{
l.lock();
_chunkType = ct;
for (ISlot slot : _chunkType.getSymbolicChunkType().getSlots())
addSlotInternal(slot);
}
finally
{
l.unlock();
}
}
/**
* add a slot by copying it first. Not locked since this is only called from
* the constructor
*
* @param s
*/
private void addSlotInternal(ISlot s)
{
if (LOGGER.isDebugEnabled()) LOGGER.debug("adding slot " + s);
super.addSlot(s);
}
/**
* will set the value of a slot You cannot add slots to a chunk, only the
* chunk-type - but this will set the value, assuming the slot exists
*/
@Override
public void addSlot(ISlot s)
{
/**
* not locked, ChunkSlot will do this for us.
*/
((IMutableSlot) getSlot(s.getName())).setValue(s.getValue());
}
/**
* noop
*
* @see org.jactr.core.slot.ISlotContainer#removeSlot(org.jactr.core.slot.ISlot)
*/
@Override
public void removeSlot(ISlot s)
{
// NoOp chunks cant remove slots
}
/**
* @see org.jactr.core.chunk.ISymbolicChunk#isA(org.jactr.core.chunktype.IChunkType)
*/
public boolean isA(IChunkType ct)
{
if (_chunkType != null) return _chunkType.isA(ct);
return false;
}
/**
* @see org.jactr.core.chunk.ISymbolicChunk#isAStrict(org.jactr.core.chunktype.IChunkType)
*/
public boolean isAStrict(IChunkType ct)
{
return ct == _chunkType;
}
/**
* notify both the slot container listeners and the chunk listeners
*/
@Override
public void valueChanged(ISlot slot, Object oldValue, Object newValue)
{
super.valueChanged(slot, oldValue, newValue);
if (_parentChunk.hasListeners())
_parentChunk.dispatch(new ChunkEvent(_parentChunk, slot, oldValue));
}
/**
* return the actual slot
*/
@Override
public ISlot getSlot(String slotName)
{
if(slotName.equalsIgnoreCase("isa")) {
if(_chunkTypeSlot == null)
_chunkTypeSlot = new BasicSlot("isa",_chunkType);
return _chunkTypeSlot;
}
ISlot s = super.getSlot(slotName);
if (s == null)
throw new IllegalChunkStateException(getName() + " of type "
+ getChunkType() + " does not contain a slot named " + slotName
+ " possible " + getSlots());
return s;
}
@Override
public String toString()
{
return getName();
}
public Object getAdapter(Class adapterClass)
{
if (adapterClass.isAssignableFrom(getClass())) return this;
return null;
}
}