예제 #1
0
class Layer(PASSProcessModelElement):

	"""
	A superclass for all layers in a PASS process model. A layer is an abstract definition of a model.

	:version: 2015-12-07
	:author: Kai Hartung & Lukas Block
	"""

	""" ATTRIBUTES

	 See definition in ontology. Exactly one reference is given!

	belongsTo  (public)

	 See definition in ontology

	hasModelComponent  (public)

	 Is a property - Returns all message exchanges that are assigned by has model
	 component. See documentation MessageExchange.

	messageExchanges  (public)

	 Is a property - Returns all ActiveProcessComponents that are assigned to this
	 layer by hasModelComponent. See ActiveProcessDocumentation documentation for
	 further information.

	activeComponents  (public)

	 Is a property - Returns all the Behavior classes that are assigned to this lyer
	 via hasModelComponent. For further information see the Behavior documentation.

	behaviors  (public)

	 Is a property - Returns all Subjects that are assigned to this layer by
	 hasModelComponent. See Subject documentation for further information.

	subjects  (public)

	 Is a property - Returns all ExternalSubjects that are assigned to this layer by
	 hasModelComponent. See ExternalSubject documentation for further information.

	externalSubjects  (public)

	"""

	def __init__(self, manager, uri = None, isBlank = False, blankNodeId = None, parentModel = None):
		"""
		 Constructor - Should never be called directly from outside the model framwork.

		@param ModelManager manger : The parent element (if one exists).
		@param string uri :
		@param bool isBlank :
		@param string blankNodeId :
		@return  :
		@author
		"""
		PASSProcessModelElement.__init__(self, manager, uri, isBlank, blankNodeId)
		
		if((parentModel is not None) and (not isinstance(parentModel, PASSProcessModel))):
			raise Exception("ParentModel parameter must be of type PASSProcessModel!")
		self.belongsTo = parentModel
		self.hasModelComponent = ListenerList([], self, "hasModelComponent")
		
	def getAttrMultiplicity(self, attributeName):
		if(attributeName == "belongsTo"):
			AttributeMultiplicity.UNIQUE
		else:
			return PASSProcessModelElement.getAttrMultiplicity(self, attributeName)
		
	@property
	def messageExchanges(self):
		result = []
		for c in self.hasModelComponent:
			if (isinstance(c, MessageExchange)):
				result.append(c)
		return result
		
	@property
	def activeComponents(self):
		result = []
		for c in self.hasModelComponent:
			if (isinstance(c, ActiveProcessComponent)):
				result.append(c)
		return result
		
	@property
	def behaviors(self):
		result = []
		for c in self.hasModelComponent:
			if (isinstance(c, Behavior)):
				result.append(c)
		return result
		
	@property
	def subjects(self):
		result = []
		for c in self.hasModelComponent:
			if (isinstance(c, Subject)):
				result.append(c)
		return result
		
	@property
	def externalSubjects(self):
		result = []
		for c in self.hasModelComponent:
			if (isinstance(c, ExternalSubject)):
				result.append(c)
		return result
		
	@property
	def activeProcessComponents(self):
		result = []
		for c in self.hasModelComponent:
			if (isinstance(c, ActiveProcessComponent)):
				result.append(c)
		return result

	def addSubject(self, behaviorToAssign = None):
		"""
		 Adds a new subject to this layer.

		@param Behavior behaviorToAssign : The behavior that should be assigned to the subject.
		@return Subject :
		@author
		"""
		if((behaviorToAssign is not None) and (not isinstance(behaviorToAssign, Behavior))):
			raise Exception("'BehaviorToAssign' must be of type Behavior!")
		if(behaviorToAssign is None):
			behaviorToAssign = self.addBehavior()
		newSubject = Subject(self.modelManager, behavior=behaviorToAssign)
		self.hasModelComponent.append(newSubject)
		return newSubject
		
	def addExternalSubject(self, uri):
		"""


		@param short uri : Uri where this process modell is stored.
		@return ExternalSubject :
		@author
		"""
		if(not isinstance(uri, str)):
			raise Exception("'Uri' must be of type string!")
		newExSub = ExternalSubject(self.modelManager, referenceUri = uri)
		self.hasModelComponent.append(newExSub)
		return newExSub

	def removeActiveComponent(self, componentToRemove, removeBehavior = True):
		"""


		@param ActiveProcessComponent componentToRemove : The subject, external subject, ... to remove from this layer
		@param bool removeBehavior : Tries to also delete the behavior of this active component, if it is of type subject.
		@return  :
		@author
		"""
		if(not isinstance(componentToRemove, ActiveProcessComponent)):
			raise Exception("'Uri' must be of type Behavior!")	
		if(not isinstance(removeBehavior, bool)):
			raise Exception("'removeBehavior' must be of type bool!")
		#Remove incident message exchanges
		for e in self.messageExchanges:
			if((e.sender is componentToRemove) or (e.receiver is componentToRemove)):
				self.removeMessageExchange(e)
		#Remove behavior if requested
		if((removeBehavior) and isinstance(componentToRemove, Actor)):
			behaviorToRemove = componentToRemove.hasBehavior
			self.removeBehavior(behaviorToRemove)
		#Remove process element
		self.hasModelComponent.remove(componentToRemove)

	def addMessageExchange(self, sender, receiver, messageType = None):
		"""
		 Adds a new message exchange to this layer.

		@param Actor sender : The sender of the message exchange
		@param Actor receiver : The receiver of this message exchange
		@param MessageType messageType : The type of the message this message exchanges should be of. If none is given a new message type is created.
		@return MessageExchange :
		@author
		"""
		if(not isinstance(sender, ActiveProcessComponent)):
			raise Exception("'Sender' must be of type Actor!")	
		if(not isinstance(receiver, ActiveProcessComponent)):
			raise Exception("'Receiver' must be of type Actor!")	
		if((messageType is not None) and (not isinstance(messageType, MessageType))):
			raise Exception("'MessageType' must be of type MessageType!")	
		if(messageType is None):
			messageType = MessageType(self.modelManager)
		newExchange = MessageExchange(self.modelManager, sender = sender, receiver = receiver, messageType = messageType)
		self.hasModelComponent.append(newExchange)
		return newExchange

	def removeMessageExchange(self, messageExchange):
		"""
		 Invers function of addMessageExchange - Removes a message exchange from this
		 layer.

		@param MessageExchange messageExchange : The messageExchange to remove from this layer
		@return  :
		@author
		"""
		if(not isinstance(messageExchange, MessageExchange)):
			raise Exception("'MessageExchange' must be of type MessageExchange!")	
		self.hasModelComponent.remove(messageExchange)

	def addBehavior(self):
		"""
		 Function to add a new Behavior to this layer and to directly assign it to an
		 actor, if needed.

		@param Actor asignToActor : The actor that should have this behavior.
		@return Behavior :
		@author
		"""
		newBehavior = Behavior(self.modelManager)
		self.hasModelComponent.append(newBehavior)
		return newBehavior

	def removeBehavior(self, behaviorToRemove):
		"""
		 Invers function of addBehavior. Removes a behavior from this layer and (if it
		 was assigned to one) also from the actor.

		@param Behavior behaviorToRemove : The behavior that should be removed from this layer.
		@return  :
		@author
		"""
		if(not isinstance(behaviorToRemove, Behavior)):
			raise Exception("BehaviorToRemove must be of type Behavior! Actual item: {}".format(behaviorToRemove))
		for a in self.activeComponents:
			if(isinstance(a, Actor) and (a.hasBehavior is behaviorToRemove)):
				a.hasBehavior = None
				print("WARNING! Behavior was removed that belonged to a subject!")
		self.hasModelComponent.remove(behaviorToRemove)
		
	def duplicateActiveProcessComponent(self, component):
		"""
		 Duplicates a given active process component and adds it again to this layer.

		@param ActiveProcessComponent component : The component to duplicate.
		@return  :
		@author
		"""
		result = deepcopy(component)
		self.hasModelComponent.append(result)
		return result
		
	def getBoundingBox2D(self):
		"""
		 Returns the bounding box of all active process elements in their 2D coordinate system.

		@return  :
		@author
		"""
		#Helper variables
		maxX = float("-inf")
		maxY = float("-inf")
		minX = float("inf")
		minY = float("inf")
		#Now iterate over all active process components
		for active in (self.activeProcessComponents + self.messageExchanges):
			if(hasattr(active, "hasAbstractVisualRepresentation")):
				point = active.hasAbstractVisualRepresentation.getPoint2D()
				#Max tests
				if(maxX < point[0]):
					maxX = point[0]
				if(maxY < point[1]):
					maxY = point[1]
				#Min tests
				if(minX > point[0]):
					minX = point[0]
				if(minY > point[1]):
					minY = point[1]
		#inf tests
		if(math.isinf(maxX)):
			maxX = 0
			minX = 0
		if(math.isinf(maxY)):
			maxY = 0
			minY = 0
		return [[minX, minY], [maxX, maxY]]
					
	def getBoundingBox3D(self):
		"""
		 Returns the bounding box of all active process elements in their 3D coordinate system.

		@return  :
		@author
		"""
		#Helper variables
		maxX = float("-inf")
		maxY = float("-inf")
		maxZ = float("-inf")
		minX = float("inf")
		minY = float("inf")
		minZ = float("inf")
		#Now iterate over all active process components
		for active in (self.activeProcessComponents + self.messageExchanges):
			if(hasattr(active, "hasAbstractVisualRepresentation")):
				point = active.hasAbstractVisualRepresentation.getPoint3D()
				#Max tests
				if(maxX < point[0]):
					maxX = point[0]
				if(maxY < point[1]):
					maxY = point[1]
				if(maxZ < point[2]):
					maxZ = point[2]
				#Min tests
				if(minX > point[0]):
					minX = point[0]
				if(minY > point[1]):
					minY = point[1]
				if(minZ > point[2]):
					minZ = point[2]
		#inf tests
		if(math.isinf(maxX)):
			maxX = 0
			minX = 0
		if(math.isinf(maxY)):
			maxY = 0
			minY = 0
		if(math.isinf(maxZ)):
			maxZ = 0
			minZ = 0
		return [[minX, minY, minZ], [maxX, maxY, maxZ]]
예제 #2
0
파일: Behavior.py 프로젝트: seb1b/S-BPM_VR
class Behavior(PASSProcessModelElement):
    """
	A behavior is a state diagram that defines how an subject reacts when it receives or sends messages.

	:version: 2015-12-07
	:author: Kai Hartung & Lukas Block
	"""
    """ ATTRIBUTES

	 All edges of this behavior description. Variable is defined by ontology.

	hasEdge  (public)

	 All states of this behavior description. Variable is defined by ontology.

	hasState  (public)

	"""
    def __init__(self, manager, uri=None, isBlank=False, blankNodeId=None):
        """
		 Constructor - Should never be called directly from outside the model framwork.

		@param ModelManager manger : The parent element (if one exists).
		@param string uri :
		@param bool isBlank :
		@param string blankNodeId :
		@return  :
		@author
		"""
        PASSProcessModelElement.__init__(self, manager, uri, isBlank,
                                         blankNodeId)
        self.hasEdge = ListenerList([], self, "hasEdge")
        self.hasState = ListenerList([], self, "hasState")

        self._fireChangeEvents = True
        self.fireChangeEvent()

    def addFunctionState(self):
        """
		 Adds a state of type function to this Behavior.

		@return  :
		@author
		"""
        newFunc = FunctionState(self.modelManager)
        self.hasState.append(newFunc)
        #Check if we should set the initial state
        if (len(self.hasState) == 1):
            self.setInitialState(newFunc)
        return newFunc

    def addReceiveState(self):
        """
		 Adds a state of type receive to this Behavior.

		@return  :
		@author
		"""
        newS = ReceiveState(self.modelManager)
        self.hasState.append(newS)
        #Check if we should set the initial state
        if (len(self.hasState) == 1):
            self.setInitialState(newS)
        return newS

    def addSendState(self):
        """
		 Adds a state of type send to this Behavior.

		@return  :
		@author
		"""
        newS = SendState(self.modelManager)
        self.hasState.append(newS)
        #Check if we should set the initial state
        if (len(self.hasState) == 1):
            self.setInitialState(newS)
        return newS

    def removeState(self, state):
        """
		 Removes a state from the current behavior.

		@param State state : The state to remove.
		@return  :
		@author
		"""
        if (not isinstance(state, State)):
            raise Exception("The state must be of type State!")
        #Delete incident edges
        tempEdges = list(self.hasEdge)
        for e in tempEdges:
            if ((e.hasSourceState is state) or (e.hasTargetState is state)):
                self.removeTransition(e)
        #Delete state
        self.hasState.remove(state)
        #Check if it was the initial state - if yes set another initial state if there are other states
        if (state.isInitialState and (len(self.hasState) > 0)):
            self.setInitialState(self.hasState[0])

    def addStandardTransition(self, from_, to):
        """
		 Adds a standard transtition to the behavior.

		@param FunctionState from : The function state the transition should start at.
		@param State to : The target state of the transition
		@return StandardTransition :
		@author
		"""
        if (not isinstance(from_, FunctionState)):
            raise Exception("'From' must be of type FunctionState!")
        if (not isinstance(to, State)):
            raise Exception("'To' must be of type State!")
        newT = StandardTransition(self.modelManager,
                                  sourceState=from_,
                                  targetState=to)
        self.hasEdge.append(newT)
        return newT

    def addReceiveTransition(self, from_, to, refersTo):
        """
		 Adds a receiving transition to the receive state.

		@param ReceiveState from : The start state of the transition
		@param State to : The target state of the transition.
		@param MessageExchange refersTo : The message exchange this transition should refer to.
		@return ReceiveTransition :
		@author
		"""
        if (not isinstance(from_, ReceiveState)):
            raise Exception("'From' must be of type ReceiveState!")
        if (not isinstance(to, State)):
            raise Exception("'To' must be of type State!")
        if (not isinstance(refersTo, MessageExchange)):
            raise Exception("'RefersTo' must be of type MessageExchange!")
        if (self.getParent(ActiveProcessComponent) != refersTo.receiver):
            raise Exception(
                "The MessageExchange that should be done must be start at the subject assigned to this Behavior!"
            )
        #Now create the transition
        newT = ReceiveTransition(self.modelManager,
                                 sourceState=from_,
                                 targetState=to,
                                 refersTo=refersTo)
        self.hasEdge.append(newT)
        return newT

    def addSendTransition(self, from_, to, refersTo):
        """
		 Adds a sending transition between the given states.

		@param SendState from : The send state the transition starts at.
		@param State to : The target state of the transition.
		@param MessageExchange refersTo : The message exchange this transition should refer to.
		@return SendTransition :
		@author
		"""
        if (not isinstance(from_, SendState)):
            raise Exception("'From' must be of type ReceiveState!")
        if (not isinstance(to, State)):
            raise Exception("'To' must be of type State!")
        if (not isinstance(refersTo, MessageExchange)):
            raise Exception("'RefersTos' must be of type MessageExchange!")
        if (self.getParent(ActiveProcessComponent) != refersTo.sender):
            raise Exception(
                "The MessageExchange that should be done must be start at the subject assigned to this Behavior!"
            )
        #Now create the transition
        newT = SendTransition(self.modelManager,
                              sourceState=from_,
                              targetState=to,
                              refersTo=refersTo)
        self.hasEdge.append(newT)
        return newT

    def removeTransition(self, transitionToRemove):
        """
		 Removes an existing transition.

		@param TransitionEdge transitionToRemove : The transition edge to remove.
		@return  :
		@author
		"""
        if (not isinstance(transitionToRemove, TransitionEdge)):
            raise Exception(
                "The transitionToRemove must be of type TransitionEdge!")
        self.hasEdge.remove(transitionToRemove)

    def setInitialState(self, state):
        """
		 Sets the initail state (= the state where the behavior automata starts). Only
		 one state can be of type initial state. A state is set to an initial state by
		 manipulating the rdfs:type variable.

		@param State state : The state that should be used to start the actor's behavior.
		@return  :
		@author
		"""
        #Variable for the initial state
        initState = "http://www.purl.org/s-scm-ont#InitialState"
        for eState in self.hasState:
            if (eState.isInitialState):
                #Remove current inital state
                eState.type.remove(initState)
            if (eState is state):
                #Set to initial state
                eState.type.append(initState)

    def duplicateState(self, state):
        """
		 Duplicates a given state and adds it again to this behavior.

		@param State state : The state to duplicate.
		@return  :
		@author
		"""
        result = deepcopy(state)
        self.hasState.append(result)
        return result

    def getBoundingBox2D(self):
        """
		 Returns the bounding box of all state elements in their 2D coordinate system.

		@return  :
		@author
		"""
        #Helper variables
        maxX = float("-inf")
        maxY = float("-inf")
        minX = float("inf")
        minY = float("inf")
        #Now iterate over all active process components
        for active in (self.hasState + self.hasEdge):
            if (hasattr(active, "hasAbstractVisualRepresentation")):
                point = active.hasAbstractVisualRepresentation.getPoint2D()
                #Max tests
                if (maxX < point[0]):
                    maxX = point[0]
                if (maxY < point[1]):
                    maxY = point[1]
                #Min tests
                if (minX > point[0]):
                    minX = point[0]
                if (minY > point[1]):
                    minY = point[1]
        #inf tests
        if (math.isinf(maxX)):
            maxX = 0
            minX = 0
        if (math.isinf(maxY)):
            maxY = 0
            minY = 0
        return [[minX, minY], [maxX, maxY]]

    def getBoundingBox3D(self):
        """
		 Returns the bounding box of all state elements in their 3D coordinate system.

		@return  :
		@author
		"""
        #Helper variables
        maxX = float("-inf")
        maxY = float("-inf")
        maxZ = float("-inf")
        minX = float("inf")
        minY = float("inf")
        minZ = float("inf")
        #Now iterate over all active process components
        for active in (self.hasState + self.hasEdge):
            if (hasattr(active, "hasAbstractVisualRepresentation")):
                point = active.hasAbstractVisualRepresentation.getPoint3D()
                #Max tests
                if (maxX < point[0]):
                    maxX = point[0]
                if (maxY < point[1]):
                    maxY = point[1]
                if (maxZ < point[2]):
                    maxZ = point[2]
                #Min tests
                if (minX > point[0]):
                    minX = point[0]
                if (minY > point[1]):
                    minY = point[1]
                if (minZ > point[2]):
                    minZ = point[2]
        #inf tests
        if (math.isinf(maxX)):
            maxX = 0
            minX = 0
        if (math.isinf(maxY)):
            maxY = 0
            minY = 0
        if (math.isinf(maxZ)):
            maxZ = 0
            minZ = 0
        return [[minX, minY, minZ], [maxX, maxY, maxZ]]
예제 #3
0
class PASSProcessModelElement(Resource):

	"""
	This class is the superclass for all Elements in a PASS process. It is responsible for their
	representation, their meta data and their linking.

	:version: 2015-12-04
	:author: Lukas Block
	"""

	""" ATTRIBUTES

	 Is a property so in fact returns the type of PASSProcessElement-subclass as a
	 string. Uses ClassMapper and rdfs:type property to determine own class type or
	 python's instance of.

	classType  (public)

	 See definition of hasComponentID in ontologie

	hasComponentID  (public)

	 Property - onyl get is allowed here. Returns the parent instance of this object.
	 The parent instance is the instance that is the next upper class in the visual
	 hierachy. Might be null!

	parent  (public)

	 The label should be uses to display itself to the outside. Might contain
	 different languages. For all ActiveProcessComponents, MessageTypes and all
	 states this label is also the words displayed on it.

	label  (public)

	 Represents all meta content this element has. The array contains the different
	 MetaContent instances with their keys and values. A key isn't secured to be
	 unique. Better use the getMetaContent or setMetaContant function.

	hasMetaContent  (public)

	 Links to a Visual Reperesentation object. See documentation of visual
	 representation for further reference.

	hasVisualRepresentation  (public)

	 Reference to an abstract visual representation that only shows the positions of
	 the elements. See AbstractVisualRepresentation for further reference.

	hasAbstractVisualRepresentation  (public)

	"""
	
	def __init__(self, manager, uri = None, isBlank = False, blankNodeId = None):
		"""
		 Constructor including the parent element

		@param ModelManager manger : The parent element (if one exists).
		@param string uri :
		@param bool isBlank :
		@param string blankNodeId :
		@param PASSProcessModelElement : The hierarchical parent of this process element.
		@return  :
		@author
		"""
		
		#Call super constructor
		Resource.__init__(self, manager, uri, isBlank, blankNodeId)
		
		#Generate the component id and the empty array for the meta content
		self.hasComponentID = randomXMLName()
		self.hasMetaContent = ListenerList([], self, "hasMetaContent")
		self.hasAbstractVisualRepresentation = None
		self.hasVisualRepresentation = None
		self.label = ListenerList([], self, "label")
		
	@property
	def uri(self):
		return self.modelManager.getBaseUri() + "#" + type(self).__name__ + "-" + self.hasComponentID
		
	@uri.setter
	def uri(self, value):
		print("WARNING! URI cannot be set for a PASSProcessModelElement!")
		
	@property
	def classType(self):
		type(self).__name__
	
	@property
	def parent(self):
		return self.getParent()
		
	def getAttrMultiplicity(self, attributeName):
		if(attributeName == "hasComponentID"):
			return AttributeMultiplicity.UNIQUE
		if(attributeName == "hasAbstractVisualRepresentation"):
			return AttributeMultiplicity.UNIQUE
		else:
			return Resource.getAttrMultiplicity(self, attributeName)

	def setMetaContent(self, key, value, override = True):
		"""
		 Sets a new meta content object or updates a given one.

		@param string key : The key of the meta content to set. If the key exists the override parameter specifies what to do. Otherwise a new MetaContent instance will be created and appended to hasMetaContent.
		@param undef value : The value of the meta content. Can be of any type that is specified in XMLLiteral.
		@param bool override : Determines if the current value should be overriden by the given one, if a MetaContent instance with the given key already exists (default behavior). If set to false a new isntance will be created and two meta content objects will exist now.
		@return  :
		@author
		"""
		for element in self.hasMetaContent:
			if(element.hasKey == key):
				if (override):
					element.hasValue = value
					#Now terminate
					return
				else:
					#Otherwise stop iterating, because we for sure must create a new one
					break
		#If not already terminated, we have to insert a new one
		self.hasMetaContent.append(MetaContent(self.modelManager, key, value))
		#No need to fire a change event beacause it is automatically fired by the newly created or the changed one.
				

	def getMetaContent(self, key):
		"""
		 Returns an array of XMLLiterals containing all values that belong to MetaContent
		 instances with this key. As Meta Content keys do not need to be unique, but
		 should be, the array normally has the size 1.

		@param string key : The key for which the MetaContent should be returned.
		@return  :
		@author
		"""
		results = []
		
		#Iterate over all meta content and add it to the list
		for value in self.hasMetaContent:
			if(value.hasKey == key):
				results.append(value.hasValue)
		
		return results
		
	def getMetaKeys(self):
		"""
		Function that returns all registered meta content keys.
		
		@return  :
		@author
		"""
		results = []
		
		for value in self.hasMetaContent:
			if(not value.hasKey in results):
				results.append(value.hasKey)
		
		return results
		
	def removeMetaContent(self, key, onlyFirst = False):
		"""
		Function that removes all registered meta content with that key.
		
		@return  :
		@author
		"""
		
		for content in self.hasMetaContent:
			if(content.hasKey == key):
				self.hasMetaContent.remove(content)
				#Stop deleting if we only want to delete the first occurence
				if(onlyFirst):
					break
					
	
	def _uniqueAttr(self):
		result = Resource._uniqueAttr(self)
		result["hasComponentID"] = randomXMLName()
		return result