package jadex.bdi.runtime.interpreter; import jadex.rules.state.IOAVState; import jadex.rules.state.IOAVStateListener; import jadex.rules.state.OAVAttributeType; import jadex.rules.state.OAVJavaType; import jadex.rules.state.OAVObjectType; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * This object is responsible for inserting changeevent * objects into the state that represent (i.e. reify) * state changes (such as new fact value of belief). * */ public class EventReificator implements IOAVStateListener { //-------- attributes -------- /** The state. */ protected IOAVState state; /** The agent. */ protected Object agent; /** The model/runtime elements, which are observed (element -> cnt). */ protected Map observed; //-------- constructors -------- /** * Create and register an event reificator. */ public EventReificator(IOAVState state, Object agent) { this.state = state; this.agent = agent; this.observed = new HashMap(); state.addStateListener(this, false); } //-------- IOAVStateListener interface -------- /** * Notification when an attribute value of an object has been set. * @param id The object id. * @param type The object type. * @param attr The attribute type. * @param oldvalue The oldvalue. * @param newvalue The newvalue. */ public void objectModified(Object id, OAVObjectType type, OAVAttributeType attr, Object oldvalue, Object newvalue) { // Push bean changes up to referring belief(set)s and/or parameter(set)s if(type instanceof OAVJavaType) { Collection refs = state.getReferencingObjects(id); for(Iterator it=refs.iterator(); it.hasNext(); ) { Object ref = it.next(); // System.err.println("id: "+id); type = state.getType(ref); if(type.isSubtype(OAVBDIRuntimeModel.belief_type) || type.isSubtype(OAVBDIRuntimeModel.beliefset_type)) { // Hack!!! Use belief_has_fact for beliefsets also, to create FACTCHANGED (instead added/removed). objectModified(ref, type, OAVBDIRuntimeModel.belief_has_fact, id, id); } else if(type.isSubtype(OAVBDIRuntimeModel.parameter_type)) { objectModified(ref, type, OAVBDIRuntimeModel.parameter_has_value, id, id); } else if(type.isSubtype(OAVBDIRuntimeModel.parameterset_type)) { objectModified(ref, type, OAVBDIRuntimeModel.parameterset_has_values, id, id); } } } // Handle OAV object change. else { if(attr.equals(OAVBDIRuntimeModel.agent_has_state)) { if(OAVBDIRuntimeModel.AGENTLIFECYCLESTATE_TERMINATING.equals(newvalue)) { // System.out.println("agent dying: "+newvalue+" "+id); createChangeEvent(id, id, OAVBDIRuntimeModel.CHANGEEVENT_AGENTTERMINATING, null); } else if(OAVBDIRuntimeModel.AGENTLIFECYCLESTATE_TERMINATED.equals(newvalue)) { // System.out.println("agent died: "+newvalue+" "+id); createChangeEvent(id, id, OAVBDIRuntimeModel.CHANGEEVENT_AGENTTERMINATED, null); } } else if(OAVBDIRuntimeModel.belief_has_fact.equals(attr)) { // System.out.println("fact changed: "+id+", "+newvalue); createChangeEvent(id, null, OAVBDIRuntimeModel.CHANGEEVENT_FACTCHANGED, newvalue); } else if(OAVBDIRuntimeModel.beliefset_has_facts.equals(attr)) { if(oldvalue==null) { // System.out.println("fact added: "+id+", "+newvalue); createChangeEvent(id, null, OAVBDIRuntimeModel.CHANGEEVENT_FACTADDED, newvalue); } else if(newvalue==null) { // System.out.println("fact removed: "+id+", "+oldvalue); createChangeEvent(id, null, OAVBDIRuntimeModel.CHANGEEVENT_FACTREMOVED, oldvalue); } else { // System.out.println("fact removed: "+id+", "+oldvalue); createChangeEvent(id, null, OAVBDIRuntimeModel.CHANGEEVENT_FACTCHANGED, newvalue); } } else if(OAVBDIRuntimeModel.capability_has_internalevents.equals(attr) && newvalue!=null) { // System.out.println("internal event occurred: "+newvalue); createChangeEvent(newvalue, id, OAVBDIRuntimeModel.CHANGEEVENT_INTERNALEVENTOCCURRED, null); } else if(OAVBDIRuntimeModel.capability_has_messageevents.equals(attr) && newvalue!=null) { // System.out.println("message event received: "+newvalue); createChangeEvent(newvalue, id, OAVBDIRuntimeModel.CHANGEEVENT_MESSAGEEVENTRECEIVED, null); } else if(OAVBDIRuntimeModel.capability_has_outbox.equals(attr) && newvalue!=null) { // System.out.println("message event sent: "+newvalue); createChangeEvent(newvalue, id, OAVBDIRuntimeModel.CHANGEEVENT_MESSAGEEVENTSENT, null); } else if(OAVBDIRuntimeModel.capability_has_goals.equals(attr)) { if(newvalue!=null) { // System.out.println("goal added: "+newvalue+" "+state.getAttributeValue(newvalue, OAVBDIRuntimeModel.element_has_model)); createChangeEvent(newvalue, id, OAVBDIRuntimeModel.CHANGEEVENT_GOALADDED, null); } else { // System.out.println("goal finished: "+id+" "+attr+" "+oldvalue+" "+state.getAttributeValue(oldvalue, OAVBDIRuntimeModel.element_has_model)); createChangeEvent(oldvalue, id, OAVBDIRuntimeModel.CHANGEEVENT_GOALDROPPED, null); } } else if(OAVBDIRuntimeModel.capability_has_plans.equals(attr)) { if(newvalue!=null) { // System.out.println("plan added: "+newvalue); createChangeEvent(newvalue, id, OAVBDIRuntimeModel.CHANGEEVENT_PLANADDED, null); } else { // System.out.println("plan finished: "+oldvalue); createChangeEvent(oldvalue, id, OAVBDIRuntimeModel.CHANGEEVENT_PLANREMOVED, null); } } } } // only for debugging // protected int objcnt=0; // protected OAVObjectType objtype=OAVBDIRuntimeModel.plan_type; // protected Set unrefs = new LinkedHashSet(); /** * Notification when an object has been added to the state. * @param id The object id. * @param type The object type. */ public void objectAdded(Object id, OAVObjectType type, boolean root) { // ignored for now... // // only for debugging // if(type.isSubtype(objtype)) // { // objcnt++; // System.err.println(objtype.toString()+" added: "+objcnt); // } } /** * Notification when an object has been removed from state. * @param id The object id. * @param type The object type. */ public void objectRemoved(Object id, OAVObjectType type) { // ignored for now... // // only for debugging // if(type.isSubtype(objtype)) // { //// objcnt--; //// System.err.println(objtype.toString()+" removed: "+objcnt); // boolean test = state.containsObject(id); // assert test==false; // if(!test && state.getReferencingObjects(id)!=null // && !state.getReferencingObjects(id).isEmpty()) // { // final Object fid = id; // new Thread(new Runnable() // { // public void run() // { // synchronized(unrefs) // { // unrefs.add(fid); // BDIInterpreter bdii = BDIInterpreter.getInterpreter(state); // if(bdii!=null) // System.out.println("+ext.referenced plans("+bdii.getAgentAdapter().getComponentIdentifier().getLocalName()+"): "+unrefs); // } // while(state.getReferencingObjects(fid)!=null // && !state.getReferencingObjects(fid).isEmpty()) // { // try // { // Thread.sleep(1000); // } // catch(InterruptedException e) // { // } // } // synchronized(unrefs) // { // unrefs.remove(fid); // BDIInterpreter bdii = BDIInterpreter.getInterpreter(state); // if(bdii!=null) // System.out.println("-ext.referenced plans("+bdii.getAgentAdapter().getComponentIdentifier().getLocalName()+"): "+unrefs); // } // } // }).start(); // } // } } /** * Create a change event. * @param element The element source. * @param type The event type. * @param value The optional value. * @return The event. */ protected void createChangeEvent(Object element, Object scope, String type, Object value) { assert element!=null; boolean create; // Hack! Special case for message events. if(state.getType(element).isSubtype(OAVBDIRuntimeModel.messageevent_type) && state.getAttributeValue(element, OAVBDIRuntimeModel.messageevent_has_original)!=null) { create = observed.containsKey(state.getAttributeValue(element, OAVBDIRuntimeModel.messageevent_has_original)); } else { create = observed.containsKey(element); } if(!create) { Object melement = state.getAttributeValue(element, OAVBDIRuntimeModel.element_has_model); create = observed.containsKey(melement); } if(create) { Object ce = state.createObject(OAVBDIRuntimeModel.changeevent_type); state.setAttributeValue(ce, OAVBDIRuntimeModel.changeevent_has_element, element); state.setAttributeValue(ce, OAVBDIRuntimeModel.changeevent_has_type, type); if(scope!=null) state.setAttributeValue(ce, OAVBDIRuntimeModel.changeevent_has_scope, scope); if(value!=null) state.setAttributeValue(ce, OAVBDIRuntimeModel.changeevent_has_value, value); state.addAttributeValue(agent, OAVBDIRuntimeModel.agent_has_changeevents, ce); } } /** * Add an element to the list of observed elements. * Only for observed elements, change events will be generated. */ public void addObservedElement(Object element) { Integer cnt = (Integer)observed.get(element); if(cnt==null) cnt = new Integer(1); else cnt = new Integer(cnt.intValue()+1); observed.put(element, cnt); } /** * Remove an element from the list of observed elements. */ public void removeObservedElement(Object element) { Integer cnt = (Integer)observed.get(element); if(cnt.intValue()>1) cnt = new Integer(cnt.intValue()-1); else observed.remove(element); } }