package jadex.bdi.runtime.impl.flyweights;
import jadex.bdi.model.IMElement;
import jadex.bdi.model.OAVBDIMetaModel;
import jadex.bdi.model.impl.flyweights.MParameterFlyweight;
import jadex.bdi.runtime.IParameter;
import jadex.bdi.runtime.interpreter.BDIInterpreter;
import jadex.bdi.runtime.interpreter.BeliefRules;
import jadex.bdi.runtime.interpreter.MessageEventRules;
import jadex.bdi.runtime.interpreter.OAVBDIRuntimeModel;
import jadex.bridge.MessageType;
import jadex.bridge.MessageType.ParameterSpecification;
import jadex.commons.Tuple;
import jadex.rules.state.IOAVState;
import java.util.Collection;
/**
* Flyweight for a parameter on instance level.
*/
public class ParameterFlyweight extends ElementFlyweight implements IParameter
{
/** Parameter name. */
// Used only when handle is null, because no parameter value stored in state, yet.
protected String name;
/** Parameter element handle. */
protected Object parameterelement;
//-------- constructors --------
/**
* Create a new parameter flyweight.
* @param state The state.
* @param scope The scope handle.
* @param handle The parameter handle (or null if no value yet).
* @param name The parameter name (used, if no value yet).
* @param parameterelement The handle for the parameter element to which this parameter belongs.
*/
private ParameterFlyweight(IOAVState state, Object scope,
Object handle, String name, Object parameterelement)
{
super(state, scope, handle);
this.name = name;
this.parameterelement = parameterelement;
assert parameterelement!=null;
if(parameterelement!=null)
state.addExternalObjectUsage(parameterelement, this);
}
/**
* Get or create a flyweight.
* @return The flyweight.
*/
public static ParameterFlyweight getParameterFlyweight(IOAVState state, Object scope, Object handle, String name, Object parameterelement)
{
BDIInterpreter ip = BDIInterpreter.getInterpreter(state);
ParameterFlyweight ret = (ParameterFlyweight)ip.getFlyweightCache(IParameter.class, new Tuple(IParameter.class, parameterelement, name));
if(ret==null)
{
ret = new ParameterFlyweight(state, scope, handle, name, parameterelement);
ip.putFlyweightCache(IParameter.class, new Tuple(IParameter.class, parameterelement, name), ret);
}
return ret;
}
/**
* Actual cleanup code.
* When overriding this method, super.doCleanup() has to be called.
*/
protected void doCleanup()
{
if(parameterelement!=null)
{
getState().removeExternalObjectUsage(parameterelement, this);
parameterelement = null;
}
super.doCleanup();
}
//-------- IParameter interface --------
/**
* Set a value of a parameter.
* @param value The new value.
*/
public void setValue(final Object value)
{
if(getInterpreter().isExternalThread())
{
new AgentInvocation()
{
public void run()
{
if(!hasHandle())
{
setHandle(getState().getAttributeValue(parameterelement,
OAVBDIRuntimeModel.parameterelement_has_parameters, name));
}
if(!hasHandle())
{
Object mparamelem = getState().getAttributeValue(parameterelement, OAVBDIRuntimeModel.element_has_model);
Object mparam = getState().getAttributeValue(mparamelem, OAVBDIMetaModel.parameterelement_has_parameters, name);
Class clazz = resolveClazz(getState(), mparamelem, name);
setHandle(BeliefRules.createParameter(getState(), name, null, clazz, parameterelement, mparam, getScope()));
}
String direction = resolveDirection();
if(OAVBDIMetaModel.PARAMETER_DIRECTION_FIXED.equals(direction)
|| OAVBDIMetaModel.PARAMETER_DIRECTION_IN.equals(direction) && inprocess(getState(), parameterelement, getScope())
|| OAVBDIMetaModel.PARAMETER_DIRECTION_OUT.equals(direction) && !inprocess(getState(), parameterelement, getScope()))
throw new RuntimeException("Write access not allowed to parameter: "
+direction+" "+getName());
BeliefRules.setParameterValue(getState(), getHandle(), value);
}
};
}
else
{
if(!hasHandle())
{
setHandle(getState().getAttributeValue(parameterelement,
OAVBDIRuntimeModel.parameterelement_has_parameters, name));
}
if(!hasHandle())
{
Object mparamelem = getState().getAttributeValue(parameterelement, OAVBDIRuntimeModel.element_has_model);
Object mparam = getState().getAttributeValue(mparamelem, OAVBDIMetaModel.parameterelement_has_parameters, name);
Class clazz = resolveClazz(getState(), mparamelem, name);
setHandle(BeliefRules.createParameter(getState(), name, null, clazz, parameterelement, mparam, getScope()));
}
String direction = resolveDirection();
if(OAVBDIMetaModel.PARAMETER_DIRECTION_FIXED.equals(direction)
|| OAVBDIMetaModel.PARAMETER_DIRECTION_IN.equals(direction) && inprocess(getState(), parameterelement, getScope())
|| OAVBDIMetaModel.PARAMETER_DIRECTION_OUT.equals(direction) && !inprocess(getState(), parameterelement, getScope()))
throw new RuntimeException("Write access not allowed to parameter: "
+direction+" "+getName());
getInterpreter().startMonitorConsequences();
BeliefRules.setParameterValue(getState(), getHandle(), value);
getInterpreter().endMonitorConsequences();
}
}
/**
* Get the value of a parameter.
* @return The value.
*/
public Object getValue()
{
if(getInterpreter().isExternalThread())
{
AgentInvocation invoc = new AgentInvocation()
{
public void run()
{
if(!hasHandle() && getState().containsKey(parameterelement,
OAVBDIRuntimeModel.parameterelement_has_parameters, name))
{
setHandle(getState().getAttributeValue(parameterelement,
OAVBDIRuntimeModel.parameterelement_has_parameters, name));
}
if(hasHandle())
{
object = getState().getAttributeValue(getHandle(), OAVBDIRuntimeModel.parameter_has_value);
}
}
};
return invoc.object;
}
else
{
Object ret = null;
if(!hasHandle() && getState().containsKey(parameterelement,
OAVBDIRuntimeModel.parameterelement_has_parameters, name))
{
setHandle(getState().getAttributeValue(parameterelement,
OAVBDIRuntimeModel.parameterelement_has_parameters, name));
}
if(hasHandle())
{
ret = getState().getAttributeValue(getHandle(), OAVBDIRuntimeModel.parameter_has_value);
}
return ret;
}
}
/**
* Get the name.
* @return The name.
*/
public String getName()
{
if(getInterpreter().isExternalThread())
{
AgentInvocation invoc = new AgentInvocation()
{
public void run()
{
string = (String)getState().getAttributeValue(getHandle(), OAVBDIRuntimeModel.parameter_has_name);
}
};
return invoc.string;
}
else
{
return (String)getState().getAttributeValue(getHandle(), OAVBDIRuntimeModel.parameter_has_name);
}
}
//-------- IElement interface --------
/**
* Get the model element.
* @return The model element.
*/
public IMElement getModelElement()
{
if(getInterpreter().isExternalThread())
{
AgentInvocation invoc = new AgentInvocation()
{
public void run()
{
Object mpe = getState().getAttributeValue(parameterelement, OAVBDIRuntimeModel.element_has_model);
Object mparameter = getState().getAttributeValue(mpe, OAVBDIMetaModel.parameterelement_has_parameters, name);
Object mscope = getState().getAttributeValue(getScope(), OAVBDIRuntimeModel.element_has_model);
object = new MParameterFlyweight(getState(), mscope, mparameter);
}
};
return (IMElement)invoc.object;
}
else
{
IMElement ret = null;
Object mpe = getState().getAttributeValue(parameterelement, OAVBDIRuntimeModel.element_has_model);
Object mparameter = getState().getAttributeValue(mpe, OAVBDIMetaModel.parameterelement_has_parameters, name);
Object mscope = getState().getAttributeValue(getScope(), OAVBDIRuntimeModel.element_has_model);
ret = new MParameterFlyweight(getState(), mscope, mparameter);
return ret;
}
}
/**
* Resolve the parameter class.
*/
public static Class resolveClazz(IOAVState state, Object mparamelem, String name)
{
Class clazz = null;
// Object mparamelem = state.getAttributeValue(parameterelement, OAVBDIRuntimeModel.element_has_model);
Object mparam = state.getAttributeValue(mparamelem, OAVBDIMetaModel.parameterelement_has_parameters, name);
if(mparam!=null)
{
clazz = (Class)state.getAttributeValue(mparam, OAVBDIMetaModel.typedelement_has_class);
}
else if(state.getType(mparamelem).isSubtype(OAVBDIMetaModel.messageevent_type))
{
MessageType mt = MessageEventRules.getMessageEventType(state, mparamelem);
ParameterSpecification ps = mt.getParameter(name);
clazz = ps.getClazz();
}
if(clazz==null)
clazz = Object.class;
return clazz;
}
/**
* Resolve the parameter direction.
*/
protected String resolveDirection()
{
String direction = null;
Object mparamelem = getState().getAttributeValue(parameterelement, OAVBDIRuntimeModel.element_has_model);
Object mparam = getState().getAttributeValue(mparamelem, OAVBDIMetaModel.parameterelement_has_parameters, name);
if(mparam!=null)
{
direction = (String)getState().getAttributeValue(mparam, OAVBDIMetaModel.parameter_has_direction);
}
if(direction==null)
direction = OAVBDIMetaModel.PARAMETER_DIRECTION_IN;
return direction;
}
/**
* Check if the parameterelement is in process (for parameter write protection).
*/
protected static boolean inprocess(IOAVState state, Object parameterelement, Object scope)
{
boolean ret;
if(state.getType(parameterelement).isSubtype(OAVBDIRuntimeModel.plan_type))
{
ret = OAVBDIRuntimeModel.PLANPROCESSINGTATE_RUNNING.equals(state.getAttributeValue(parameterelement, OAVBDIRuntimeModel.plan_has_processingstate));
}
else if(state.getType(parameterelement).isSubtype(OAVBDIRuntimeModel.goal_type))
{
// For goals, "inprocess" actually means adopted (i.e. active/option/suspended).
ret = OAVBDIRuntimeModel.GOALLIFECYCLESTATE_ACTIVE.equals(state.getAttributeValue(parameterelement, OAVBDIRuntimeModel.goal_has_lifecyclestate))
|| OAVBDIRuntimeModel.GOALLIFECYCLESTATE_OPTION.equals(state.getAttributeValue(parameterelement, OAVBDIRuntimeModel.goal_has_lifecyclestate))
|| OAVBDIRuntimeModel.GOALLIFECYCLESTATE_SUSPENDED.equals(state.getAttributeValue(parameterelement, OAVBDIRuntimeModel.goal_has_lifecyclestate));
}
else // if(getState().getType(parameterelement).isSubtype(OAVBDIRuntimeModel.processableelement_type))
{
// Event is in process, when reasoning is finished.
ret = OAVBDIRuntimeModel.PROCESSABLEELEMENT_CANDIDATESSELECTED.equals(state.getAttributeValue(parameterelement, OAVBDIRuntimeModel.processableelement_has_state))
|| OAVBDIRuntimeModel.PROCESSABLEELEMENT_NOCANDIDATES.equals(state.getAttributeValue(parameterelement, OAVBDIRuntimeModel.processableelement_has_state));
// When reasoning not done, event is also in process, when dispatched (i.e. in capability).
if(!ret && state.getType(parameterelement).isSubtype(OAVBDIRuntimeModel.messageevent_type))
{
Collection events = state.getAttributeValues(scope, OAVBDIRuntimeModel.capability_has_messageevents);
ret = events!=null && events.contains(parameterelement);
}
else if(!ret && state.getType(parameterelement).isSubtype(OAVBDIRuntimeModel.internalevent_type))
{
Collection events = state.getAttributeValues(scope, OAVBDIRuntimeModel.capability_has_internalevents);
ret = events!=null && events.contains(parameterelement);
}
}
return ret;
}
}