package jadex.rules.tools.stateviewer;
import jadex.commons.collection.IdentityHashSet;
import jadex.commons.concurrent.ISynchronizator;
import jadex.rules.state.IOAVState;
import jadex.rules.state.IOAVStateListener;
import jadex.rules.state.IProfiler;
import jadex.rules.state.OAVAttributeType;
import jadex.rules.state.OAVJavaType;
import jadex.rules.state.OAVObjectType;
import jadex.rules.state.OAVTypeModel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* A copy state allows to decouple a state
* from the user (e.g. a local or remote gui tool).
* Changes to the original state will be represented
* in the copy state, but synchronized to a user
* environment (e.g. swing thread).
* Therefore, a synchronizator needs to be set.
*/
public class CopyState implements IOAVState
{
//-------- attributes --------
/** The state copy. */
protected Map copy;
/** The typemodel. */
protected OAVTypeModel tmodel;
/** The root objects. */
protected Set rootobjects;
/** The synchronizator (e.g. swing sync.). */
protected ISynchronizator synchronizator;
/** The original state. */
protected IOAVState state;
/** The listener on the original state. */
protected IOAVStateListener listener;
/** The listeners. */
protected List listeners;
//-------- constructors --------
/**
* Create a local copy state.
* @param state The original state.
* @param synchronizator The synchronizator used to reflect changes in the copy state.
*/
public CopyState(final IOAVState state, ISynchronizator synchronizator)
{
this.state = state;
this.copy = state.isJavaIdentity() ? (Map)new IdentityHashMap() : new HashMap();
this.rootobjects = state.isJavaIdentity() ? (Set)new IdentityHashSet() : new HashSet();
setSynchronizator(synchronizator);
// Copy initial objects.
this.tmodel = state.getTypeModel();
for(Iterator it=state.getDeepObjects(); it.hasNext(); )
{
Object id = it.next();
OAVObjectType type = state.getType(id);
if(!(type instanceof OAVJavaType))
{
Map obj = copyObject(state, id, type);
copy.put(id, obj);
}
else
{
copy.put(id, id);
}
}
for(Iterator it=state.getRootObjects(); it.hasNext(); )
{
rootobjects.add(it.next());
}
// Add listener for updating on changes.
listener = new IOAVStateListener()
{
public void objectModified(final Object id, final OAVObjectType type,
final OAVAttributeType attr, final Object oldvalue, final Object newvalue)
{
if(!(type instanceof OAVJavaType))
{
// For multiplicity always copy complete collection (hack???)
Object val = newvalue;
if(!OAVAttributeType.NONE.equals(attr.getMultiplicity()))
{
Collection coll = state.getAttributeValues(id, attr);
if(coll!=null)
{
coll = new ArrayList(coll);
}
val = coll;
}
final Object newval = val;
CopyState.this.synchronizator.invokeLater(new Runnable()
{
public void run()
{
Map obj = (Map)copy.get(id);
assert obj!=null : id;
obj.put(attr, newval);
if(listeners!=null)
{
IOAVStateListener[] alist = (IOAVStateListener[])listeners.toArray(new IOAVStateListener[listeners.size()]);
for(int i=0; i<alist.length; i++)
alist[i].objectModified(id, type, attr, oldvalue, newvalue);
}
}
});
}
}
/**
* Notification when an object has been added to the state.
* @param id The object id.
* @param type The object type.
*/
public void objectAdded(final Object id, final OAVObjectType type, final boolean root)
{
Object tmp;
if(!(type instanceof OAVJavaType))
{
// Copy current attribute values into map (on agent thread.)
tmp = copyObject(state, id, type);
}
else
{
tmp = id;
}
final Object obj = tmp;
CopyState.this.synchronizator.invokeLater(new Runnable()
{
public void run()
{
// Add map to state copy (on sync thread).
copy.put(id, obj);
if(root)
rootobjects.add(id);
if(listeners!=null)
{
IOAVStateListener[] alist = (IOAVStateListener[])listeners.toArray(new IOAVStateListener[listeners.size()]);
for(int i=0; i<alist.length; i++)
alist[i].objectAdded(id, type, root);
}
}
});
}
/**
* Notification when an object has been removed from state.
* @param id The object id.
* @param type The object type.
*/
public void objectRemoved(final Object id, final OAVObjectType type)
{
// if(!(type instanceof OAVJavaType))
{
CopyState.this.synchronizator.invokeLater(new Runnable()
{
public void run()
{
assert copy.containsKey(id);
copy.remove(id);
if(listeners!=null)
{
IOAVStateListener[] alist = (IOAVStateListener[])listeners.toArray(new IOAVStateListener[listeners.size()]);
for(int i=0; i<alist.length; i++)
alist[i].objectRemoved(id, type);
}
}
});
}
}
};
state.addStateListener(listener , false);
}
/**
* Dispose the state.
*/
public void dispose()
{
state.removeStateListener(listener);
}
//-------- methods --------
/**
* Copy an OAV object into a map.
*/
protected static Map copyObject(IOAVState state, Object id, OAVObjectType type)
{
Map obj = new HashMap();
obj.put("type", type);
while(type!=null)
{
Collection attrs = type.getDeclaredAttributeTypes();
for(Iterator it=attrs.iterator(); it.hasNext(); )
{
OAVAttributeType attr = (OAVAttributeType)it.next();
if(OAVAttributeType.NONE.equals(attr.getMultiplicity()))
{
Object value = state.getAttributeValue(id, attr);
obj.put(attr, value);
}
else // Map, List, Set.
{
Collection coll = state.getAttributeValues(id, attr);
if(coll!=null)
{
coll = new ArrayList(coll);
}
obj.put(attr, coll);
}
}
type = type.getSupertype();
}
return obj;
}
//-------- IOAVState interface --------
//-------- type management --------
/**
* Get the type model.
* @return The type model.
*/
public OAVTypeModel getTypeModel()
{
return tmodel;
}
//-------- object management --------
/**
* Create an object.
* Creates an object identifier that can be used
* to store/retrieve attribute values.
* May reuse old object identifiers for performance.
* @param type The object type (null for defining meta types).
* @return An object identifier.
*/
public Object createObject(OAVObjectType type)
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Create a root object. A root object will not be automatically
* garbage collected when no references point to this object
* any longer.
* Creates an object identifier that can be used
* to store/retrieve attribute values.
* May reuse old object identifiers for performance.
* @return An object identifier.
*/
public Object createRootObject(OAVObjectType type)
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Drop an object from the state.
* Recursively removes the object and all connected objects that are not
* referenced elsewhere.
* @param object The identifier of the object to remove.
*/
public void dropObject(Object object)
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Add a Java object as root object.
* @param object The Java object.
*/
public void addJavaRootObject(Object object)
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Remove a Java object from root objects.
* @param object The Java object.
*/
public void removeJavaRootObject(Object object)
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Clone an object in the state (deep copy)
* @param object The handle to the object to be cloned.
* @param targetstate The target state in which the clone should be created.
* @return The identifier of the newly created clone.
* /
public Object cloneObject(Object object, IOAVState targetstate);*/
/**
* Test if the state contains a specific object.
* @param object The object identifier.
* @return True, if contained.
*/
public boolean containsObject(Object object)
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Get the type of an object.
* @param object The object identifier.
*/
public OAVObjectType getType(Object object)
{
OAVObjectType ret;
Object obj = copy.get(object);
if(obj instanceof Map)
{
ret = (OAVObjectType)((Map)obj).get("type");
}
else
{
ret = getTypeModel().getJavaType(object.getClass());
}
return ret;
}
/**
* Get all objects in the state.
*/
public Iterator getObjects()
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Get all objects in the state and its substates.
*/
public Iterator getDeepObjects()
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Get the root objects of the state.
*/
public Iterator getRootObjects()
{
return rootobjects.iterator();
}
/**
* Get the number of objects in the state.
* Optional operation used for debugging only.
*/
public int getSize()
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Get all unreferenced objects.
* @return All unreferenced objects of the state.
*/
public Collection getUnreferencedObjects()
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Find a cycle in a given set of objects.
*/
public List findCycle(Collection objects)
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Get those objects referencing a given object.
*/
public Collection getReferencingObjects(Object value)
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Add an external usage of a state object. This prevents
* the oav object of being garbage collected as long
* as external references are present.
* @param id The oav object id.
* @param external The user object.
*/
public void addExternalObjectUsage(Object id, Object external)
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Remove an external usage of a state object. This allows
* the oav object of being garbage collected when no
* further external references and no internal references
* are present.
* @param id The oav object id.
* @param external The state external object.
*/
public void removeExternalObjectUsage(Object id, Object external)
{
throw new UnsupportedOperationException("Not yet implemented");
}
//--------- attribute management --------
/**
* Get an attribute value of an object.
* @param object The identifier of the object.
* @param attribute The attribute identifier.
* @return The value (basic, object id or java object).
*/
public Object getAttributeValue(Object object, OAVAttributeType attribute)
{
return ((Map)copy.get(object)).get(attribute);
}
/**
* Set an attribute of an object to the given value.
* @param object The identifier of the object.
* @param attribute The attribute identifier.
* @param value The value (basic, object id or java object).
*/
// todo: What about earlier value (if any)?
public void setAttributeValue(Object object, OAVAttributeType attribute, Object value)
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Get the values of an attribute of an object.
* @param object The identifier of the object.
* @param attribute The attribute identifier.
* @return The values (basic, object ids or java objects).
*/
public Collection getAttributeValues(Object object, OAVAttributeType attribute)
{
// Todo: map attribute?
return (Collection)((Map)copy.get(object)).get(attribute);
}
/**
* Get the keys of an attribute of an object.
* @param object The identifier of the object.
* @param attribute The attribute identifier.
* @return The keys for which values are stored.
*/
public Collection getAttributeKeys(Object object, OAVAttributeType attribute)
{
// Todo: map attribute?
return ((Map)((Map)copy.get(object)).get(attribute)).keySet();
}
/**
* Get an attribute value of an object. Method only applicable for
* map attribute type.
* @param object The identifier of the object.
* @param attribute The attribute identifier.
* @param key The key.
* @return The value (basic, object id or java object).
*/
public Object getAttributeValue(Object object, OAVAttributeType attribute, Object key)
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Test if a key is contained in the map attribute.
* @param object The identifier of the object.
* @param attribute The attribute identifier.
* @param key The key.
* @return True if key is available.
*/
public boolean containsKey(Object object, OAVAttributeType attribute, Object key)
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Add an attribute of an object to the given value.
* @param object The identifier of the object.
* @param attribute The attribute identifier.
* @param value The value (basic, object id or java object).
*/
public void addAttributeValue(Object object, OAVAttributeType attribute, Object value)
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Remove an attribute of an object to the given value.
* @param object The identifier of the object.
* @param attribute The attribute identifier.
* @param value The value (basic, object id or java object).
*/
public void removeAttributeValue(Object object, OAVAttributeType attribute, Object value)
{
throw new UnsupportedOperationException("Not yet implemented");
}
//-------- state observers --------
/**
* Add a new state listener.
* @param listener The state listener.
* @param bunch True, for adding a bunch listener.
*/
public void addStateListener(IOAVStateListener listener, boolean bunch)
{
if(bunch)
throw new UnsupportedOperationException("Bunch mode not supported.");
if(listeners==null)
listeners = new ArrayList();
listeners.add(listener);
}
/**
* Remove a state listener.
* @param listener The state listener.
*/
public void removeStateListener(IOAVStateListener listener)
{
if(listeners!=null)
if(listeners.remove(listener) && listeners.isEmpty())
listeners = null;
}
/**
* Throw collected events and notify the listeners.
* Necessary if in event collecting mode.
*/
public void notifyEventListeners()
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Expunge stale objects.
*/
public void expungeStaleObjects()
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Set the synchronizator.
* For the copy state, setting a synchronizator is required,
* as it is used to forward changes of the original state
* to the copy.
*/
public void setSynchronizator(ISynchronizator synchronizator)
{
this.synchronizator = synchronizator;
}
/**
* Get the synchronizator (if any).
* The synchronizator (if available) can be used to synchronize
* access to the state with internal and external modifications.
*/
public ISynchronizator getSynchronizator()
{
return this.synchronizator;
}
/**
* Get the profiler.
*/
// Hack!!! Make accessible from somewhere else?
public IProfiler getProfiler()
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Set the profiler.
*/
// Hack!!! Make accessible from somewhere else?
public void setProfiler(IProfiler profiler)
{
throw new UnsupportedOperationException("Not yet implemented");
}
//-------- nested states --------
/**
* Add a substate.
* Read accesses will be transparently mapped to substates.
* Write accesses to substates need not be supported and
* may generate UnsupportedOperationException.
* Also it can not be assumed that addition of substates
* will generate object added events.
*/
public void addSubstate(IOAVState substate)
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Get the substates.
*/
public IOAVState[] getSubstates()
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Test if two values are equal
* according to current identity/equality
* settings.
*/
public boolean equals(Object a, Object b)
{
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Flag indicating that java objects are
* stored by identity instead of equality.
*/
public boolean isJavaIdentity()
{
throw new UnsupportedOperationException("Not yet implemented");
}
}