class RuntimeClassBase(object):
    __metaclass__  = abc.ABCMeta
    
    def __init__(self):
        self.active = False
        self.state_changed = False
        self.events = EventQueue();
        self.timers = None;
        
    def addEvent(self, event, time_offset = 0.0):
        self.events.add(event, time_offset);
        
    def getEarliestEventTime(self) :
        if self.timers :
            return min(self.events.getEarliestTime(), min(self.timers.itervalues()))
        return self.events.getEarliestTime();

    def step(self, delta):
        if not self.active :
            return
        
        self.events.decreaseTime(delta);
        
        if self.timers :
            next_timers = {}
            for (key,value) in self.timers.iteritems() :
                time = value - delta
                if time <= 0.0 :
                    self.addEvent( Event("_" + str(key) + "after"), time);
                else :
                    next_timers[key] = time
            self.timers = next_timers;

        self.microstep()
        while (self.state_changed) :
            self.microstep()
            
    def microstep(self):
        due = self.events.popDueEvents()
        if (len(due) == 0) :
            self.transition()
        else :
            for event in due :
                self.transition(event);
    
    @abc.abstractmethod
    def transition(self, event = None):
        pass
    
    def start(self):
        self.active = True
    
    def stop(self):
        self.active = False
        
        
class ControllerBase(object):

    def __init__(self, object_manager, keep_running):
        self.object_manager = object_manager
        self.keep_running = keep_running

        # Keep track of input ports
        self.input_ports = []
        self.input_queue = EventQueue();

        # Keep track of output ports
        self.output_ports = []
        self.output_listeners = []

        # Let statechart run one last time before stopping
        self.done = False
            
    def addInputPort(self, port_name):
        self.input_ports.append(port_name)
        
    def addOutputPort(self, port_name):
        self.output_ports.append(port_name)

    def broadcast(self, new_event):
        self.object_manager.broadcast(new_event)
        
    def start(self):
        self.object_manager.start()
    
    def stop(self):
        pass
    
    def addInput(self, input_event, time_offset = 0.0):
        if input_event.getName() == ""  :
            raise InputException("Input event can't have an empty name.")
        
        if input_event.getPort() not in self.input_ports :
            raise InputException("Input port mismatch.")
        
        self.input_queue.add(input_event, time_offset)

    def outputEvent(self, event):
        for listener in self.output_listeners :
            listener.add(event)
        
    def addOutputListener(self, ports):
        listener = OutputListener(ports)
        self.output_listeners.append(listener)
        return listener
    
    def addEventList(self, event_list):
        for (event, time_offset) in event_list :
            self.addInput(event, time_offset)
            
    def getObjectManager(self):
        return self.object_manager;
class ObjectManagerBase(object):
    __metaclass__  = abc.ABCMeta
    
    def __init__(self, controller):
        self.controller = controller
        self.events = EventQueue()
        self.instances_map = {} #a dictionary that maps RuntimeClassBase to InstanceWrapper
        
    def addEvent(self, event, time_offset = 0.0):
        self.events.add(event, time_offset)
        
    # Broadcast an event to all instances
    def broadcast(self, new_event):
        for i in self.instances_map:
            i.addEvent(new_event)
        
    def getWaitTime(self):  
        #first get waiting time of the object manager's events
        smallest_time = self.events.getEarliestTime();
        #check all the instances
        for instance in self.instances_map.iterkeys() :
            smallest_time = min(smallest_time, instance.getEarliestEventTime())
        return smallest_time;
    
    def stepAll(self, delta):
        self.step(delta)
        for i in self.instances_map.iterkeys():
            i.step(delta)

    def step(self, delta):
        self.events.decreaseTime(delta);
        for event in self.events.popDueEvents() :
            self.handleEvent(event)
               
    def start(self):
        for i in self.instances_map:
            i.start()           
               
    def handleEvent(self, e):   
        if e.getName() == "narrow_cast" :
            self.handleNarrowCastEvent(e.getParameters())
            
        elif e.getName() == "broad_cast" :
            self.handleBroadCastEvent(e.getParameters())
            
        elif e.getName() == "create_instance" :
            self.handleCreateEvent(e.getParameters())
            
        elif e.getName() == "associate_instance" :
            self.handleAssociateEvent(e.getParameters())
            
        elif e.getName() == "start_instance" :
            self.handleStartInstanceEvent(e.getParameters())
            
        elif e.getName() == "delete_instance" :
            self.handleDeleteInstanceEvent(e.getParameters())
            
    def processAssociationReference(self, input_string):
        if len(input_string) == 0 :
            raise AssociationReferenceException("Empty association reference.")
        regex_pattern = re.compile("^([a-zA-Z_]\w*)(?:\[(\d+)\])?$");
        path_string =  input_string.split("/")
        result = []
        for piece in path_string :
            match = regex_pattern.match(piece)
            if match :
                name = match.group(1)
                index = match.group(2)
                if index is None :
                    index = -1
                result.append((name,int(index)))
            else :
                raise AssociationReferenceException("Invalid entry in association reference.")
        return result
    
    def handleStartInstanceEvent(self, parameters):
        if len(parameters) != 2 :
            raise ParameterException ("The start instance event needs 2 parameters.")  
        else :
            source = parameters[0]
            traversal_list = self.processAssociationReference(parameters[1])
            for i in self.getInstances(source, traversal_list) :
                i.instance.start()
            source.addEvent(Event("instance_started", parameters = [parameters[1]]))
        
    def handleBroadCastEvent(self, parameters):
        if len(parameters) != 1 :
            raise ParameterException ("The broadcast event needs 1 parameter.")
        self.broadcast(parameters[0])

    def handleCreateEvent(self, parameters):
        if len(parameters) < 2 :
            raise ParameterException ("The create event needs at least 2 parameters.")
        else :
            source = parameters[0]
            association_name = parameters[1]
            
            association = self.instances_map[source].getAssociation(association_name)
            if association.allowedToAdd() :
                ''' allow subclasses to be instantiated '''
                class_name = association.class_name if len(parameters) == 2 else parameters[2]
                new_instance_wrapper = self.createInstance(class_name, parameters[3:])
                idx = association.addInstance(new_instance_wrapper)
                try:
                    new_instance_wrapper.getAssociation('parent').addInstance(self.instances_map[source])
                except AssociationReferenceException:
                    pass
                source.addEvent(Event("instance_created", parameters = ['%s[%i]' % (association_name, idx)]))
            else :
                source.addEvent(Event("instance_creation_error", parameters = [association_name]))

    def handleDeleteInstanceEvent(self, parameters):
        if len(parameters) < 2 :
            raise ParameterException ("The delete event needs at least 2 parameters.")
        else :
            source = parameters[0]
            association_name = parameters[1]
            traversal_list = self.processAssociationReference(association_name)
            instances = self.getInstances(source, traversal_list)
            association = self.instances_map[source].getAssociation(traversal_list[0][0])
            for i in instances:
                association.removeInstance(i)
                i.getInstance().stop()
                if hasattr(i.instance, '__del__'):
                    i.instance.__del__()
            source.addEvent(Event("instance_deleted", parameters = [parameters[1]]))
                
    def handleAssociateEvent(self, parameters):
        if len(parameters) != 3 :
            raise ParameterException ("The associate_instance event needs 3 parameters.");
        else :
            source = parameters[0]
            to_copy_list = self.getInstances(source,self.processAssociationReference(parameters[1]))
            if len(to_copy_list) != 1 :
                raise AssociationReferenceException ("Invalid source association reference.")
            wrapped_to_copy_instance = to_copy_list[0]
            dest_list = self.processAssociationReference(parameters[2])
            if len(dest_list) == 0 :
                raise AssociationReferenceException ("Invalid destination association reference.")
            last = dest_list.pop()
            if last[1] != -1 :
                raise AssociationReferenceException ("Last association name in association reference should not be accompanied by an index.")
                
            for i in self.getInstances(source, dest_list) :
                i.getAssociation(last[0]).addInstance(wrapped_to_copy_instance)
        
    def handleNarrowCastEvent(self, parameters):
        if len(parameters) != 3 :
            raise ParameterException ("The associate_instance event needs 3 parameters.")
        source = parameters[0]
        traversal_list = self.processAssociationReference(parameters[1])
        cast_event = parameters[2]
        for i in self.getInstances(source, traversal_list) :
            i.instance.addEvent(cast_event)
        
    def getInstances(self, source, traversal_list):
        currents = [self.instances_map[source]]
        for (name, index) in traversal_list :
            nexts = []
            for current in currents :
                association = current.getAssociation(name)
                if (index >= 0 ) :
                    nexts.append ( association.getInstance(index) );
                elif (index == -1) :
                    nexts.extend ( association.instances.values() );
                else :
                    raise AssociationReferenceException("Incorrect index in association reference.")
            currents = nexts
        return currents
            
    @abc.abstractmethod
    def instantiate(self, class_name, construct_params):
        pass
        
    def createInstance(self, class_name, construct_params = []):
        instance_wrapper = self.instantiate(class_name, construct_params)
        if instance_wrapper:
            self.instances_map[instance_wrapper.getInstance()] = instance_wrapper
        return instance_wrapper
class RuntimeClassBase(object):
    __metaclass__ = abc.ABCMeta

    def __init__(self, controller):
        self.active = False
        self.is_stable = True
        self.events = EventQueue()

        self.controller = controller

        self.timers = None
        self.inports = {}

        self.semantics = StatechartSemantics()

    def start(self):
        self.current_state = {}
        self.history_state = {}
        self.timers = {}

        self.big_step = BigStepState()
        self.combo_step = ComboStepState()
        self.small_step = SmallStepState()

        self.active = True
        self.is_stable = False

        self.initializeStatechart()
        self.processBigStepOutput()

    def stop(self):
        self.active = False

    def addEvent(self, event_list, time_offset=0.0):
        if not isinstance(event_list, list):
            event_list = [event_list]
        self.events.add(event_list, time_offset)

    def getEarliestEventTime(self):
        if not self.active:
            return INFINITY
        if not self.is_stable:
            return 0.0
        if self.timers:
            return min(self.events.getEarliestTime(),
                       min(self.timers.itervalues()))
        return self.events.getEarliestTime()

    def processBigStepOutput(self):
        for e in self.big_step.getOutputEvents():
            self.controller.outputEvent(e)
        for e in self.big_step.getOutputEventsOM():
            self.controller.object_manager.addEvent(e)

    def step(self, delta):
        if not self.active:
            return

        # decrease event queue time
        self.events.decreaseTime(delta)

        # decrease timers time
        next_timers = {}
        for (key, value) in self.timers.iteritems():
            time = value - delta
            if time <= 0.0:
                self.addEvent(Event("_" + str(key) + "after"), time)
            else:
                next_timers[key] = time
        self.timers = next_timers

        # execute big step(s)
        due = self.events.popDueEvents()
        if not due and not self.is_stable:
            due = [[]]
        for input_events in due:
            # perform 1 big step per slot in 'due'
            self.is_stable = not self.bigStep(input_events)
            self.processBigStepOutput()

    def inState(self, nodes):
        for c in self.current_state.itervalues():
            new_nodes = []
            for n in nodes:
                if not (n in c):
                    new_nodes.append(n)
            nodes = new_nodes
            if len(nodes) == 0:
                return True
        return False

    def bigStep(self, input_events):
        #print "new big step"
        self.big_step.next(input_events)
        self.small_step.reset()
        self.combo_step.reset()
        while self.comboStep():
            self.big_step.setStepped()
            if self.semantics.big_step_maximality == StatechartSemantics.TakeOne:
                break  # Take One -> only one combo step allowed
        return self.big_step.hasStepped()

    def comboStep(self):
        #print "new combo step"
        self.combo_step.next()
        while self.smallStep():
            self.combo_step.setStepped()
        return self.combo_step.hasStepped()

    def smallStep(self):
        if self.small_step.hasStepped():
            self.small_step.next()
        self.generateCandidates()
        if self.small_step.hasCandidates():
            #print "new small step, have " + str(len(self.small_step.getCandidates())) + " candidates"
            if self.semantics.concurrency == StatechartSemantics.Single:
                transition, parameters = self.small_step.getCandidates()[
                    0]  # execute first of candidates
                transition(parameters)
            elif self.semantics.concurrency == StatechartSemantics.Many:
                pass  # TODO: implement
            self.small_step.setStepped()
        return self.small_step.hasStepped()

    def getEnabledEvents(self):
        result = self.small_step.getCurrentEvents(
        ) + self.combo_step.getCurrentEvents()
        if self.semantics.input_event_lifeline == StatechartSemantics.Whole or (
                not self.big_step.hasStepped() and
            (self.semantics.input_event_lifeline
             == StatechartSemantics.FirstComboStep or
             (not self.combo_step.hasStepped()
              and self.semantics.input_event_lifeline
              == StatechartSemantics.FirstSmallStep))):
            result += self.big_step.getInputEvents()
        return result

    def raiseInternalEvent(self, event):
        if self.semantics.internal_event_lifeline == StatechartSemantics.NextSmallStep:
            self.small_step.addNextEvent(event)
        elif self.semantics.internal_event_lifeline == StatechartSemantics.NextComboStep:
            self.combo_step.addNextEvent(event)
        elif self.semantics.internal_event_lifeline == StatechartSemantics.Queue:
            self.events.add([event], 0.0)

    @abc.abstractmethod
    def initializeStatechart(self):
        pass

    @abc.abstractmethod
    def generateCandidates(self):
        pass
class ControllerBase(object):
    def __init__(self, object_manager):
        self.object_manager = object_manager

        self.private_port_counter = 0

        # Keep track of input ports
        self.input_ports = {}
        self.input_queue = EventQueue()

        # Keep track of output ports
        self.output_ports = []
        self.output_listeners = []

        # Let statechart run one last time before stopping
        self.done = False

    def addInputPort(self, virtual_name, instance=None):
        if instance == None:
            port_name = virtual_name
        else:
            port_name = "private_" + str(
                self.private_port_counter) + "_" + virtual_name
            self.private_port_counter += 1
        self.input_ports[port_name] = InputPortEntry(virtual_name, instance)
        return port_name

    def addOutputPort(self, port_name):
        self.output_ports.append(port_name)

    def broadcast(self, new_event):
        self.object_manager.broadcast(new_event)

    def start(self):
        self.object_manager.start()

    def stop(self):
        pass

    def addInput(self, input_event_list, time_offset=0.0):
        if not isinstance(input_event_list, list):
            input_event_list = [input_event_list]

        for e in input_event_list:
            if e.getName() == "":
                raise InputException("Input event can't have an empty name.")

            if e.getPort() not in self.input_ports:
                raise InputException("Input port mismatch, no such port: " +
                                     e.getPort() + ".")

        self.input_queue.add(input_event_list, time_offset)

    def getWaitTime(self):
        return min(self.object_manager.getWaitTime(),
                   self.input_queue.getEarliestTime())

    def handleInput(self, delta):
        self.input_queue.decreaseTime(delta)
        for events in self.input_queue.popDueEvents():
            for e in events:
                input_port = self.input_ports[e.getPort()]
                e.port = input_port.virtual_name
                target_instance = input_port.instance
                if target_instance == None:
                    self.broadcast(e)
                else:
                    target_instance.addEvent(e)

    def outputEvent(self, event):
        for listener in self.output_listeners:
            listener.add(event)

    def addOutputListener(self, ports):
        listener = OutputListener(ports)
        self.output_listeners.append(listener)
        return listener

    def addMyOwnOutputListener(self, listener):
        self.output_listeners.append(listener)

    # deprecated, to add multiple events, use addInput instead
    def addEventList(self, event_list):
        for (event, time_offset) in event_list:
            self.addInput(event, time_offset)

    def getObjectManager(self):
        return self.object_manager
class ObjectManagerBase(object):
    __metaclass__ = abc.ABCMeta

    def __init__(self, controller):
        self.controller = controller
        self.events = EventQueue()
        self.instances = [
        ]  #a dictionary that maps RuntimeClassBase to InstanceWrapper

    def addEvent(self, event, time_offset=0.0):
        self.events.add(event, time_offset)

    # Broadcast an event to all instances
    def broadcast(self, new_event):
        for i in self.instances:
            i.addEvent(new_event)

    def getWaitTime(self):
        #first get waiting time of the object manager's events
        smallest_time = self.events.getEarliestTime()
        #check all the instances
        for instance in self.instances:
            smallest_time = min(smallest_time, instance.getEarliestEventTime())
        return smallest_time

    def stepAll(self, delta):
        self.step(delta)
        for i in self.instances:
            i.step(delta)

    def step(self, delta):
        self.events.decreaseTime(delta)
        for event in self.events.popDueEvents():
            self.handleEvent(event)

    def start(self):
        for i in self.instances:
            i.start()

    def handleEvent(self, e):
        if e.getName() == "narrow_cast":
            self.handleNarrowCastEvent(e.getParameters())

        elif e.getName() == "broad_cast":
            self.handleBroadCastEvent(e.getParameters())

        elif e.getName() == "create_instance":
            self.handleCreateEvent(e.getParameters())

        elif e.getName() == "associate_instance":
            self.handleAssociateEvent(e.getParameters())

        elif e.getName() == "start_instance":
            self.handleStartInstanceEvent(e.getParameters())

        elif e.getName() == "delete_instance":
            self.handleDeleteInstanceEvent(e.getParameters())

    def processAssociationReference(self, input_string):
        if len(input_string) == 0:
            raise AssociationReferenceException("Empty association reference.")
        regex_pattern = re.compile("^([a-zA-Z_]\w*)(?:\[(\d+)\])?$")
        path_string = input_string.split("/")
        result = []
        for piece in path_string:
            match = regex_pattern.match(piece)
            if match:
                name = match.group(1)
                index = match.group(2)
                if index is None:
                    index = -1
                result.append((name, int(index)))
            else:
                raise AssociationReferenceException(
                    "Invalid entry in association reference. Input string: " +
                    input_string)
        return result

    def handleStartInstanceEvent(self, parameters):
        if len(parameters) != 2:
            raise ParameterException(
                "The start instance event needs 2 parameters.")
        else:
            source = parameters[0]
            traversal_list = self.processAssociationReference(parameters[1])
            for i in self.getInstances(source, traversal_list):
                i["instance"].start()
            source.addEvent(
                Event("instance_started", parameters=[parameters[1]]))

    def handleBroadCastEvent(self, parameters):
        if len(parameters) != 1:
            raise ParameterException("The broadcast event needs 1 parameter.")
        self.broadcast(parameters[0])

    def handleCreateEvent(self, parameters):
        if len(parameters) < 2:
            raise ParameterException(
                "The create event needs at least 2 parameters.")

        source = parameters[0]
        association_name = parameters[1]

        association = source.associations[association_name]
        #association = self.instances_map[source].getAssociation(association_name)
        if association.allowedToAdd():
            ''' allow subclasses to be instantiated '''
            class_name = association.to_class if len(
                parameters) == 2 else parameters[2]
            new_instance = self.createInstance(class_name, parameters[3:])
            if not new_instance:
                raise ParameterException("Creating instance: no such class: " +
                                         class_name)
            #index = association.addInstance(new_instance)
            try:
                index = association.addInstance(new_instance)
            except AssociationException as exception:
                raise RuntimeException(
                    "Error adding instance to association '" +
                    association_name + "': " + str(exception))
            p = new_instance.associations.get("parent")
            if p:
                p.addInstance(source)
            source.addEvent(
                Event("instance_created", None,
                      [association_name + "[" + str(index) + "]"]))
        else:
            source.addEvent(
                Event("instance_creation_error", None, [association_name]))

    def handleDeleteInstanceEvent(self, parameters):
        if len(parameters) < 2:
            raise ParameterException(
                "The delete event needs at least 2 parameters.")
        else:
            source = parameters[0]
            association_name = parameters[1]
            traversal_list = self.processAssociationReference(association_name)
            instances = self.getInstances(source, traversal_list)
            #association = self.instances_map[source].getAssociation(traversal_list[0][0])
            association = source.associations[traversal_list[0][0]]
            for i in instances:
                try:
                    association.removeInstance(i["instance"])
                except AssociationException as exception:
                    raise RuntimeException(
                        "Error removing instance from association '" +
                        association_name + "': " + str(exception))
                i["instance"].stop()
                #if hasattr(i.instance, 'user_defined_destructor'):
                i["instance"].user_defined_destructor()
            source.addEvent(
                Event("instance_deleted", parameters=[parameters[1]]))

    def handleAssociateEvent(self, parameters):
        if len(parameters) != 3:
            raise ParameterException(
                "The associate_instance event needs 3 parameters.")
        else:
            source = parameters[0]
            to_copy_list = self.getInstances(
                source, self.processAssociationReference(parameters[1]))
            if len(to_copy_list) != 1:
                raise AssociationReferenceException(
                    "Invalid source association reference.")
            wrapped_to_copy_instance = to_copy_list[0]["instance"]
            dest_list = self.processAssociationReference(parameters[2])
            if len(dest_list) == 0:
                raise AssociationReferenceException(
                    "Invalid destination association reference.")
            last = dest_list.pop()
            if last[1] != -1:
                raise AssociationReferenceException(
                    "Last association name in association reference should not be accompanied by an index."
                )

            for i in self.getInstances(source, dest_list):
                i["instance"].associations[last[0]].addInstance(
                    wrapped_to_copy_instance)

    def handleNarrowCastEvent(self, parameters):
        if len(parameters) != 3:
            raise ParameterException(
                "The associate_instance event needs 3 parameters.")
        source = parameters[0]
        traversal_list = self.processAssociationReference(parameters[1])
        cast_event = parameters[2]
        for i in self.getInstances(source, traversal_list):
            i["instance"].addEvent(cast_event)

    def getInstances(self, source, traversal_list):
        currents = [{
            "instance": source,
            "ref": None,
            "assoc_name": None,
            "assoc_index": None
        }]
        #currents = [source]
        for (name, index) in traversal_list:
            nexts = []
            for current in currents:
                association = current["instance"].associations[name]
                if (index >= 0):
                    nexts.append({
                        "instance": association.instances[index],
                        "ref": current["instance"],
                        "assoc_name": name,
                        "assoc_index": index
                    })
                elif (index == -1):
                    for i in association.instances:
                        nexts.append({
                            "instance": association.instances[i],
                            "ref": current["instance"],
                            "assoc_name": name,
                            "assoc_index": index
                        })
                    #nexts.extend( association.instances.values() )
                else:
                    raise AssociationReferenceException(
                        "Incorrect index in association reference.")
            currents = nexts
        return currents

    @abc.abstractmethod
    def instantiate(self, class_name, construct_params):
        pass

    def createInstance(self, to_class, construct_params=[]):
        instance = self.instantiate(to_class, construct_params)
        self.instances.append(instance)
        return instance
Exemple #7
0
class ObjectManagerBase(object):
	__metaclass__  = abc.ABCMeta
	
	def __init__(self, controller):
		self.controller = controller
		self.events = EventQueue()
		self.instances = [] #a dictionary that maps RuntimeClassBase to InstanceWrapper
		
	def addEvent(self, event, time_offset = 0.0):
		self.events.add(event, time_offset)
		
	# Broadcast an event to all instances
	def broadcast(self, new_event):
		for i in self.instances:
			i.addEvent(new_event)
		
	def getWaitTime(self):  
		#first get waiting time of the object manager's events
		smallest_time = self.events.getEarliestTime()
		#check all the instances
		for instance in self.instances:
			smallest_time = min(smallest_time, instance.getEarliestEventTime())
		return smallest_time
	
	def stepAll(self, delta):
		self.step(delta)
		for i in self.instances:
			i.step(delta)

	def step(self, delta):
		self.events.decreaseTime(delta)
		for event in self.events.popDueEvents() :
			self.handleEvent(event)
			   
	def start(self):
		for i in self.instances:
			i.start()		   
			   
	def handleEvent(self, e):   
		if e.getName() == "narrow_cast" :
			self.handleNarrowCastEvent(e.getParameters())
			
		elif e.getName() == "broad_cast" :
			self.handleBroadCastEvent(e.getParameters())
			
		elif e.getName() == "create_instance" :
			self.handleCreateEvent(e.getParameters())
			
		elif e.getName() == "associate_instance" :
			self.handleAssociateEvent(e.getParameters())
			
		elif e.getName() == "start_instance" :
			self.handleStartInstanceEvent(e.getParameters())
			
		elif e.getName() == "delete_instance" :
			self.handleDeleteInstanceEvent(e.getParameters())
			
	def processAssociationReference(self, input_string):
		if len(input_string) == 0 :
			raise AssociationReferenceException("Empty association reference.")
		regex_pattern = re.compile("^([a-zA-Z_]\w*)(?:\[(\d+)\])?$")
		path_string =  input_string.split("/")
		result = []
		for piece in path_string :
			match = regex_pattern.match(piece)
			if match :
				name = match.group(1)
				index = match.group(2)
				if index is None :
					index = -1
				result.append((name,int(index)))
			else :
				raise AssociationReferenceException("Invalid entry in association reference. Input string: " + input_string)
		return result
	
	def handleStartInstanceEvent(self, parameters):
		if len(parameters) != 2 :
			raise ParameterException ("The start instance event needs 2 parameters.")  
		else :
			source = parameters[0]
			traversal_list = self.processAssociationReference(parameters[1])
			for i in self.getInstances(source, traversal_list) :
				i["instance"].start()
			source.addEvent(Event("instance_started", parameters = [parameters[1]]))
		
	def handleBroadCastEvent(self, parameters):
		if len(parameters) != 1 :
			raise ParameterException ("The broadcast event needs 1 parameter.")
		self.broadcast(parameters[0])

	def handleCreateEvent(self, parameters):
		if len(parameters) < 2 :
			raise ParameterException ("The create event needs at least 2 parameters.")

		source = parameters[0]
		association_name = parameters[1]
		
		association = source.associations[association_name]
		#association = self.instances_map[source].getAssociation(association_name)
		if association.allowedToAdd() :
			''' allow subclasses to be instantiated '''
			class_name = association.to_class if len(parameters) == 2 else parameters[2]
			new_instance = self.createInstance(class_name, parameters[3:])
			if not new_instance:
				raise ParameterException("Creating instance: no such class: " + class_name)
			#index = association.addInstance(new_instance)
			try:
				index = association.addInstance(new_instance)
			except AssociationException as exception:
				raise RuntimeException("Error adding instance to association '" + association_name + "': " + str(exception))
			p = new_instance.associations.get("parent")
			if p:
				p.addInstance(source)
			source.addEvent(Event("instance_created", None, [association_name+"["+str(index)+"]"]))
		else :
			source.addEvent(Event("instance_creation_error", None, [association_name]))

	def handleDeleteInstanceEvent(self, parameters):
		if len(parameters) < 2 :
			raise ParameterException ("The delete event needs at least 2 parameters.")
		else :
			source = parameters[0]
			association_name = parameters[1]
			traversal_list = self.processAssociationReference(association_name)
			instances = self.getInstances(source, traversal_list)
			#association = self.instances_map[source].getAssociation(traversal_list[0][0])
			association = source.associations[traversal_list[0][0]]
			for i in instances:
				try:
					association.removeInstance(i["instance"])
				except AssociationException as exception:
					raise RuntimeException("Error removing instance from association '" + association_name + "': " + str(exception))
				i["instance"].stop()
				#if hasattr(i.instance, 'user_defined_destructor'):
				i["instance"].user_defined_destructor()
			source.addEvent(Event("instance_deleted", parameters = [parameters[1]]))
				
	def handleAssociateEvent(self, parameters):
		if len(parameters) != 3 :
			raise ParameterException ("The associate_instance event needs 3 parameters.")
		else :
			source = parameters[0]
			to_copy_list = self.getInstances(source,self.processAssociationReference(parameters[1]))
			if len(to_copy_list) != 1 :
				raise AssociationReferenceException ("Invalid source association reference.")
			wrapped_to_copy_instance = to_copy_list[0]["instance"]
			dest_list = self.processAssociationReference(parameters[2])
			if len(dest_list) == 0 :
				raise AssociationReferenceException ("Invalid destination association reference.")
			last = dest_list.pop()
			if last[1] != -1 :
				raise AssociationReferenceException ("Last association name in association reference should not be accompanied by an index.")
				
			for i in self.getInstances(source, dest_list) :
				i["instance"].associations[last[0]].addInstance(wrapped_to_copy_instance)
		
	def handleNarrowCastEvent(self, parameters):
		if len(parameters) != 3 :
			raise ParameterException ("The associate_instance event needs 3 parameters.")
		source = parameters[0]
		traversal_list = self.processAssociationReference(parameters[1])
		cast_event = parameters[2]
		for i in self.getInstances(source, traversal_list) :
			i["instance"].addEvent(cast_event)
		
	def getInstances(self, source, traversal_list):
		currents = [{
			"instance" : source,
			"ref" : None,
			"assoc_name" : None,
			"assoc_index" : None
		}]
		#currents = [source]
		for (name, index) in traversal_list :
			nexts = []
			for current in currents :
				association = current["instance"].associations[name]
				if (index >= 0 ) :
					nexts.append({
						"instance" : association.instances[index],
						"ref" : current["instance"],
						"assoc_name" : name,
						"assoc_index" : index
					})
				elif (index == -1) :
					for i in association.instances:
						nexts.append({
							"instance" : association.instances[i],
							"ref" : current["instance"],
							"assoc_name" : name,
							"assoc_index" : index
						})
					#nexts.extend( association.instances.values() )
				else :
					raise AssociationReferenceException("Incorrect index in association reference.")
			currents = nexts
		return currents
			
	@abc.abstractmethod
	def instantiate(self, class_name, construct_params):
		pass
		
	def createInstance(self, to_class, construct_params = []):
		instance = self.instantiate(to_class, construct_params)
		self.instances.append(instance)
		return instance
Exemple #8
0
class RuntimeClassBase(object):
	__metaclass__  = abc.ABCMeta
	
	def __init__(self, controller):
		self.active = False
		self.is_stable = True
		self.events = EventQueue()

		self.controller = controller

		self.timers = None
		self.inports = {}

		self.semantics = StatechartSemantics()

	def start(self):
		self.current_state = {}
		self.history_state = {}
		self.timers = {}

		self.big_step = BigStepState()
		self.combo_step = ComboStepState()
		self.small_step = SmallStepState()

		self.active = True
		self.is_stable = False

		self.initializeStatechart()
		self.processBigStepOutput()
	
	def stop(self):
		self.active = False
		
	def addEvent(self, event_list, time_offset = 0.0):
		if not isinstance(event_list, list):
			event_list = [event_list]
		self.events.add(event_list, time_offset)
		
	def getEarliestEventTime(self) :
		if not self.active:
			return INFINITY
		if not self.is_stable:
			return 0.0
		if self.timers:
			return min(self.events.getEarliestTime(), min(self.timers.itervalues()))
		return self.events.getEarliestTime()

	def processBigStepOutput(self):
		for e in self.big_step.getOutputEvents():
			self.controller.outputEvent(e)
		for e in self.big_step.getOutputEventsOM():
			self.controller.object_manager.addEvent(e)

	def step(self, delta):
		if not self.active :
			return
		
		# decrease event queue time
		self.events.decreaseTime(delta)

		# decrease timers time
		next_timers = {}
		for (key,value) in self.timers.iteritems() :
			time = value - delta
			if time <= 0.0 :
				self.addEvent( Event("_" + str(key) + "after"), time)
			else :
				next_timers[key] = time
		self.timers = next_timers

		# execute big step(s)
		due = self.events.popDueEvents()
		if not due and not self.is_stable:
			due = [[]]
		for input_events in due:
			# perform 1 big step per slot in 'due'
			self.is_stable = not self.bigStep(input_events)
			self.processBigStepOutput()

	def inState(self, nodes):
		for c in self.current_state.itervalues():
			new_nodes = []
			for n in nodes:
				if not (n in c):
					new_nodes.append(n)
			nodes = new_nodes
			if len(nodes) == 0:
				return True
		return False

	def bigStep(self, input_events):
		#print "new big step"
		self.big_step.next(input_events)
		self.small_step.reset()
		self.combo_step.reset()
		while self.comboStep():
			self.big_step.setStepped()
			if self.semantics.big_step_maximality == StatechartSemantics.TakeOne:
				break # Take One -> only one combo step allowed
		return self.big_step.hasStepped()

	def comboStep(self):
		#print "new combo step"
		self.combo_step.next()
		while self.smallStep():
			self.combo_step.setStepped()
		return self.combo_step.hasStepped()

	def smallStep(self):
		if self.small_step.hasStepped():
			self.small_step.next()
		self.generateCandidates()
		if self.small_step.hasCandidates():
			#print "new small step, have " + str(len(self.small_step.getCandidates())) + " candidates"
			if self.semantics.concurrency == StatechartSemantics.Single:
				transition, parameters = self.small_step.getCandidates()[0] # execute first of candidates
				transition(parameters)
			elif self.semantics.concurrency == StatechartSemantics.Many:
				pass # TODO: implement
			self.small_step.setStepped()
		return self.small_step.hasStepped()

	def getEnabledEvents(self):
		result = self.small_step.getCurrentEvents() + self.combo_step.getCurrentEvents()
		if self.semantics.input_event_lifeline == StatechartSemantics.Whole or (
			not self.big_step.hasStepped() and
				(self.semantics.input_event_lifeline == StatechartSemantics.FirstComboStep or (
				not self.combo_step.hasStepped() and
					self.semantics.input_event_lifeline == StatechartSemantics.FirstSmallStep))):
			result += self.big_step.getInputEvents()
		return result

	def raiseInternalEvent(self, event):
		if self.semantics.internal_event_lifeline == StatechartSemantics.NextSmallStep:
			self.small_step.addNextEvent(event)
		elif self.semantics.internal_event_lifeline == StatechartSemantics.NextComboStep:
			self.combo_step.addNextEvent(event)
		elif self.semantics.internal_event_lifeline == StatechartSemantics.Queue:
			self.events.add([event], 0.0)

	@abc.abstractmethod
	def initializeStatechart(self):
		pass

	@abc.abstractmethod
	def generateCandidates(self):
		pass
Exemple #9
0
class ControllerBase(object):

	def __init__(self, object_manager):
		self.object_manager = object_manager

		self.private_port_counter = 0

		# Keep track of input ports
		self.input_ports = {}
		self.input_queue = EventQueue()

		# Keep track of output ports
		self.output_ports = []
		self.output_listeners = []

		# Let statechart run one last time before stopping
		self.done = False
			
	def addInputPort(self, virtual_name, instance = None):
		if instance == None :
			port_name = virtual_name
		else:
			port_name = "private_" + str(self.private_port_counter) + "_" + virtual_name
			self.private_port_counter += 1
		self.input_ports[port_name] = InputPortEntry(virtual_name, instance)
		return port_name
		
	def addOutputPort(self, port_name):
		self.output_ports.append(port_name)

	def broadcast(self, new_event):
		self.object_manager.broadcast(new_event)
		
	def start(self):
		self.object_manager.start()
	
	def stop(self):
		pass

	def addInput(self, input_event_list, time_offset = 0.0):
		if not isinstance(input_event_list, list):
			input_event_list = [input_event_list]

		for e in input_event_list:
			if e.getName() == ""  :
				raise InputException("Input event can't have an empty name.")
		
			if e.getPort() not in self.input_ports :
				raise InputException("Input port mismatch, no such port: " + e.getPort() + ".")		

		self.input_queue.add(input_event_list, time_offset)

	def getWaitTime(self):
		return min(self.object_manager.getWaitTime(), self.input_queue.getEarliestTime())

	def handleInput(self, delta):
		self.input_queue.decreaseTime(delta)
		for events in self.input_queue.popDueEvents():
			for e in events:
				input_port = self.input_ports[e.getPort()]
				e.port = input_port.virtual_name
				target_instance = input_port.instance
				if target_instance == None:
					self.broadcast(e)
				else:
					target_instance.addEvent(e)

	def outputEvent(self, event):
		for listener in self.output_listeners :
			listener.add(event)

	def addOutputListener(self, ports):
		listener = OutputListener(ports)
		self.output_listeners.append(listener)
		return listener

	def addMyOwnOutputListener(self, listener):
		self.output_listeners.append(listener)

	# deprecated, to add multiple events, use addInput instead
	def addEventList(self, event_list):
		for (event, time_offset) in event_list :
			self.addInput(event, time_offset)
			
	def getObjectManager(self):
		return self.object_manager