Пример #1
0
	def serialize(self):
		"""
		 Serializes the given resource to triple statements from the Redland RDF library.
		 This is done by using the model manager and its attribute wrapper.

		@return  :
		@author
		"""
		#First set yourself the class type if it is not Resource or already set
		if(type(self).__name__ != "Resource"):
			if(not hasattr(self, "type")):
				self.type = ListenerList([], self, "type")
			ownClassUri = self.modelManager.classMapper.getClassResource(type(self).__name__)
			#Do this typing stuff and check if the type is not a resource
			found = False
			for r in self.type:
				try:
					if(r.uri == ownClassUri):
						found = True
						break
				except:
					#Do nothing
					pass
			if(not found):
				#Add your own class type
				self.type.append(Resource(self.modelManager, uri = ownClassUri))
		
		#Initialize an array to store the results in
		results = []
		
		#Iterate over all variables and store the values
		for (key, value) in list(self.__dict__.items()):
			#Only store the values of "public" variables
			if(not key.startswith("_")):
				#Subject and attribute are always the of normal type resource
				if(not self.isBlank):
					subjectNode = RDF.Uri(self.uri)
				else:
					subjectNode = RDF.Node(blank=self.blankIdentifier)
				attributeNode = RDF.Uri(self.modelManager.attrMapper.getAttributeUri(key))
				#Object node might be a list or a skalar
				if(value is None):
					#Do nothing
					pass
				elif(isinstance(value, list)):
					for subValue in value:
						results.append(self._generateStatement(subjectNode, attributeNode, subValue))
				else:
					results.append(Resource._generateStatement(subjectNode, attributeNode, value))
		
		#Now return the results
		return results
Пример #2
0
    def __init__(self, manager, uri=None, isBlank=False, blankNodeId=None):
        PASSProcessModelElement.__init__(self, manager, uri, isBlank,
                                         blankNodeId)
        self.hasModelComponent = ListenerList([], self, "hasModelComponent")

        self._fireChangeEvents = True
        self.fireChangeEvent()
Пример #3
0
	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")
Пример #4
0
    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()
Пример #5
0
	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")
Пример #6
0
	def __init__(self, manager, uri = None, isBlank = False, blankNodeId = None):
		"""
		 Constructor - defines whether this instance represents a blank node or not. -
		 This cannot be changed later on!

		@param ModelManager manager : The manager that is responsible for this resource.
		@param string uri : The uri this Resource should represent.
		@param bool isBlank : Boolean to dertermine whether the node is a blank node
		@param string blankNodeId : The identifier for the blank node if this resource is a blank node.
		@return  :
		@author
		"""
		#By default a resource does not fire change events
		self._fireChangeEvents = False
		
		#Import it just here because it is not needed before
		from ModelManager import *
		#Check the type of the manager object
		if(not isinstance(manager, ModelManager)):
			raise Exception("Paramter \"manager\" has to be of type ModelManager!")
		self._modelManager = manager
		self._modelManager.registerResource(self)
		self.type = ListenerList([], self, "type")
		#Now check whether to create a normal or a blank resource
		self._isBlank = isBlank
		if(not self._isBlank):
			#Create a normal resource
			if(uri is not None):
				self.uri = uri
			else:
				self._uri = None
		else:
			#Create a blank resource
			if(blankNodeId is not None):
				self._blankIdentifier = blankNodeId
			else:
				raise Exception("If a Resource is defined as a blank node it must also define the \"blankNodeId\" parameter")
Пример #7
0
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]]
Пример #8
0
    def _convertTriples(self, result, ownClasses, alternativeAttrUri=None):
        """
		Internal method to make loading from file easier!
		
		@return  :
		@author
		"""
        #Rest subject string
        subjectString = None

        #Attribute is always a node with uris => Automatically get the attribute name
        if (("a" in result) and (result["a"] is not None)):
            attrName = self.attrMapper.getAttributeName(str(result["a"].uri))
        else:
            attrName = self.attrMapper.getAttributeName(alternativeAttrUri)

        #Now check of what type the subject is
        if (result["s"].is_resource()):
            subjectString = str(result["s"].uri)
        elif (result["s"].is_blank()):
            subjectString = str(result["s"].blank_identifier)
        else:
            raise Exception(
                "Received a RDFNode that is a subject and neither of type normal nor blank!"
            )

        #Insert the subject if not already in class list
        if (not (subjectString in ownClasses)):
            #Do a dynamic import of the missing class
            exec(str("from " + ClassMapper.DEFAULT_CLASS + " import *"))
            classConstructor = globals()[ClassMapper.DEFAULT_CLASS]
            if (subjectString.startswith("http://")):
                ownClasses[subjectString] = classConstructor(self,
                                                             uri=subjectString)
            else:
                ownClasses[subjectString] = classConstructor(
                    self, isBlank=True, blankNodeId=subjectString)
        #Get the subject class
        subjectClass = ownClasses[subjectString]

        #Now check of what type the object is
        objectIsLiteral = False
        if (result["o"].is_resource()):
            objectString = str(result["o"].uri)
        elif (result["o"].is_blank()):
            objectString = str(result["o"].blank_identifier)
        else:
            #It is a literal
            objectIsLiteral = True
            literalValues = result["o"].literal_value
            if (literalValues["datatype"] is not None):
                dt = str(literalValues["datatype"])
            else:
                dt = None
            objectClass = Resource.castLiteralToType(literalValues["string"],
                                                     dt)
        #Now go on depending the object type
        if (not objectIsLiteral):
            #Insert the object if not already in class list
            if (not (objectString in ownClasses)):
                #Do a dynamic import of the missing class
                exec(str("from " + ClassMapper.DEFAULT_CLASS + " import *"))
                classConstructor = globals()[ClassMapper.DEFAULT_CLASS]
                if (objectString.startswith("http://")):
                    ownClasses[objectString] = classConstructor(
                        self, uri=objectString)
                else:
                    ownClasses[objectString] = classConstructor(
                        self, isBlank=True, blankNodeId=objectString)
            #Get the object class
            objectClass = ownClasses[objectString]

        #Now take the classes and reference the object in the subjects attribute depending on the multiplicity
        multiplicity = subjectClass.getAttrMultiplicity(attrName)
        if (multiplicity == AttributeMultiplicity.UNKNOWN):
            if (not hasattr(subjectClass, attrName)):
                setattr(subjectClass, attrName,
                        ListenerList([], subjectClass, str(attrName)))
            getattr(subjectClass, attrName).append(objectClass)
        elif (multiplicity == AttributeMultiplicity.UNIQUE):
            setattr(subjectClass, attrName, objectClass)
        else:
            raise Exception(
                "Unknown attribute multiplicity set to attribute " + attrName)
Пример #9
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]]
Пример #10
0
class Resource(object):

	"""
	Resource is a class to represent the idea of a rdf resource in our object model. It is superclass
	for all model classes that contain persitent data.

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

	""" ATTRIBUTES

	 The uri for this resource - is a property, thus the input is checked against a
	 start with "http://". Can only be set if this resource is not blank.

	uri  (public)

	 Reference to the model manager
	 Is a property - only get is allowed

	modelManager  (public)



	_modelManager  (private)



	_uri  (private)



	_blankIdentifier  (private)

	 Property for _blankIdentifier - Only get is allowed!

	blankIdentifier  (public)

	 Property - Only get is allowed here

	isBlank  (public)

	"""

	def __init__(self, manager, uri = None, isBlank = False, blankNodeId = None):
		"""
		 Constructor - defines whether this instance represents a blank node or not. -
		 This cannot be changed later on!

		@param ModelManager manager : The manager that is responsible for this resource.
		@param string uri : The uri this Resource should represent.
		@param bool isBlank : Boolean to dertermine whether the node is a blank node
		@param string blankNodeId : The identifier for the blank node if this resource is a blank node.
		@return  :
		@author
		"""
		#By default a resource does not fire change events
		self._fireChangeEvents = False
		
		#Import it just here because it is not needed before
		from ModelManager import *
		#Check the type of the manager object
		if(not isinstance(manager, ModelManager)):
			raise Exception("Paramter \"manager\" has to be of type ModelManager!")
		self._modelManager = manager
		self._modelManager.registerResource(self)
		self.type = ListenerList([], self, "type")
		#Now check whether to create a normal or a blank resource
		self._isBlank = isBlank
		if(not self._isBlank):
			#Create a normal resource
			if(uri is not None):
				self.uri = uri
			else:
				self._uri = None
		else:
			#Create a blank resource
			if(blankNodeId is not None):
				self._blankIdentifier = blankNodeId
			else:
				raise Exception("If a Resource is defined as a blank node it must also define the \"blankNodeId\" parameter")
		
	@property
	def modelManager(self):
		return self._modelManager
		
	@property
	def uri(self):
		return self._uri

	@uri.setter
	def uri(self, value):
		if(self.isBlank):
			raise Exception("Cannot set a URI to a blank resource!")
		elif((not isinstance(value, str)) or (not value.startswith("http://"))):
			raise Exception("The uri must be of type str and start with \"http://\" !")
		else:
			self._uri = value
	
	@property
	def isBlank(self):
		return self._isBlank
		
	@property
	def blankIdentifier(self):
		return self._blankIdentifier

	def serialize(self):
		"""
		 Serializes the given resource to triple statements from the Redland RDF library.
		 This is done by using the model manager and its attribute wrapper.

		@return  :
		@author
		"""
		#First set yourself the class type if it is not Resource or already set
		if(type(self).__name__ != "Resource"):
			if(not hasattr(self, "type")):
				self.type = ListenerList([], self, "type")
			ownClassUri = self.modelManager.classMapper.getClassResource(type(self).__name__)
			#Do this typing stuff and check if the type is not a resource
			found = False
			for r in self.type:
				try:
					if(r.uri == ownClassUri):
						found = True
						break
				except:
					#Do nothing
					pass
			if(not found):
				#Add your own class type
				self.type.append(Resource(self.modelManager, uri = ownClassUri))
		
		#Initialize an array to store the results in
		results = []
		
		#Iterate over all variables and store the values
		for (key, value) in list(self.__dict__.items()):
			#Only store the values of "public" variables
			if(not key.startswith("_")):
				#Subject and attribute are always the of normal type resource
				if(not self.isBlank):
					subjectNode = RDF.Uri(self.uri)
				else:
					subjectNode = RDF.Node(blank=self.blankIdentifier)
				attributeNode = RDF.Uri(self.modelManager.attrMapper.getAttributeUri(key))
				#Object node might be a list or a skalar
				if(value is None):
					#Do nothing
					pass
				elif(isinstance(value, list)):
					for subValue in value:
						results.append(self._generateStatement(subjectNode, attributeNode, subValue))
				else:
					results.append(Resource._generateStatement(subjectNode, attributeNode, value))
		
		#Now return the results
		return results

	def getAttrMultiplicity(self, attributeName):
		"""
		 Function to determine what attribute multiplicity should be used for a special
		 attribute. Uses _attrMultiplicity variable for that.

		@param string attributeName : The name of the attribute to obtain the multiplicity from.
		@return AttributeMultiplicity :
		@author
		"""
		#Import it just here because it is not needed before
		from AttributeMultiplicity import *
		return AttributeMultiplicity.UNKNOWN

	def isValid(self):
		"""
		 Checks whether the element is in a valid state (all required variables are set
		 and of right type).

		@return bool :
		@author
		"""
		#A resource is always valid even if no uri has been set
		return True

	@staticmethod
	def castLiteralToType(literalString, datatypeUri):
		#Possible extension: Take care of language tags
		"""
		 Cast a given literal to a python value using the specificed type uri. Currently
		 implemented are the XMLSchema-Types double, float, int, string, boolean.

		@param string literalString : The literal containg the specific value to cast to a python type.
		@param string datatypeUri : The uri of the datatype the literal string is from.
		@return undef :
		@author
		"""
		#Import it just here because it is not needed before
		from PlainLiteral import *
		#Now check for type
		if(datatypeUri == "http://www.w3.org/2001/XMLSchema#int"):
			#Int
			return int(literalString.encode('utf-8'))
		elif(datatypeUri == "http://www.w3.org/2001/XMLSchema#long"):
			#Long
			return long(literalString.encode('utf-8'))
		elif((datatypeUri == "http://www.w3.org/2001/XMLSchema#double") or (datatypeUri == "http://www.w3.org/2001/XMLSchema#float")):
			#Double or float
			return float(literalString.encode('utf-8'))
		elif(datatypeUri == "http://www.w3.org/2001/XMLSchema#string"):
			return str(literalString.encode('utf-8'))
		elif(datatypeUri == "http://www.w3.org/2001/XMLSchema#boolean"):
			return bool(literalString.encode('utf-8'))
		else:
			return PlainLiteral(literalString.encode('utf-8'))

	@staticmethod
	def castTypeToLiteral(pythonVar):
		#Possible extension: Take care of language tags
		"""
		 Converts a python variable to a RDF literal. The return value is an array of
		 type [literalString, datatypeUri].  Currently implemented are the
		 XMLSchema-Types double, float, int, string, boolean.

		@param undef pythonVar : The variable that should be typed to a literal including the literals string and literal uri.
		@return string[] :
		@author
		"""
		#The resulting array (first index = string representation, second index = uri to xml schema type)
		result = []
		
		#Import it just here because it is not needed before
		from PlainLiteral import *
		
		#Check of which type the variable is and return the information
		if(isinstance(pythonVar, int)):
			#Int
			result.append(str(pythonVar))
			result.append("http://www.w3.org/2001/XMLSchema#int")
		elif(isinstance(pythonVar, long)):
			#Long
			result.append(str(pythonVar))
			result.append("http://www.w3.org/2001/XMLSchema#long")
		elif(isinstance(pythonVar, float)):
			#Float
			result.append(str(pythonVar))
			result.append("http://www.w3.org/2001/XMLSchema#double")
		elif(isinstance(pythonVar, str)):
			#String
			result.append(pythonVar)
			result.append("http://www.w3.org/2001/XMLSchema#string")
		elif(isinstance(pythonVar, bool)):
			#Boolean
			result.append(str(pythonVar).lower())
			result.append("http://www.w3.org/2001/XMLSchema#boolean")
		elif(isinstance(pythonVar, PlainLiteral)):
			#Plain literal
			result.append(str(pythonVar.content.encode('utf-8')))
			result.append(None)
		else:
			raise Exception("Unknown literal \"" + type(pythonVar).__name__ + "\" type that cannot be deserialized!")
			
		#Retrun the result
		return result
			

	@staticmethod
	def _generateStatement(subjectNode, attributeNode, objectValue):
		"""
		 Internal function to generate a statement from its own attributes!

		@param RDFNode subjectNode : The subject node for this statement.
		@param RDFNode attributeNode : The attribute node for this statement.
		@param undef object : The object where the type should be determined!
		@return Statement :
		@author
		"""
		#Object node might be another resource or a literal
		if(isinstance(objectValue, Resource)):
			if(objectValue.isBlank):
				#It is a blank resource
				objectNode = RDF.Node(blank = objectValue.blankIdentifier)
			else:
				#It is a normal resource with uri
				objectNode = RDF.Uri(objectValue.uri)
		else:
			#It is a literal - Get info about it
			literalValues = Resource.castTypeToLiteral(objectValue)
			#Check what the datatype is (might be None for plain literals)
			if(literalValues[1] is not None):
				dt = RDF.Uri(literalValues[1])
				objectNode = RDF.Node(literal = literalValues[0], datatype = dt)
			else:
				objectNode = RDF.Node(literal = literalValues[0])
			
		#Now return the newly created statement
		return RDF.Statement(subjectNode, attributeNode, objectNode)
		
	def __setattr__(self, name, value):
		"""
		 Override to fire change events

		@param undef name : Override
		@param undef value : Override
		@return undef :
		@author
		"""
		#Fire the event change event if try to set any variable (Except the one setting whether we should fire the change events or not!)
		if(name != "_fireChangeEvents"):
			object.__setattr__(self, name, value)
			self.fireChangeEvent(name)
		else:
			object.__setattr__(self, name, value)
		
	def fireChangeEvent(self, attrName = None):
		if(self._fireChangeEvents):
			self.modelManager.fireChangeEvent(self, attrName)
			
	@property
	def childResources(self):
		#Result array
		results = []
		
		#Iterate over all variables and store the values if they are of type Resource
		for (key, value) in list(self.__dict__.items()):
			#Only store the values of "public" variables
			if(not key.startswith("_")):
				if(isinstance(value, list)):
					for subValue in value:
						if(isinstance(subValue, Resource)):
							results.append(subValue)
				elif(isinstance(value, Resource)):
					results.append(value)
					
		return results
		
	def getParent(self, classType = None, recursionDepth = 1):
		"""
		Returns the parent of this Resource by using ModelManager.getParent(...). Refer to this function for further information.
		
		@return  :
		@author
		"""
		
		return self.modelManager.getParent(self, classType, recursionDepth)
		
		
	def __copy__(self):
		#Create the new class
		classType = self.__class__
		result = classType.__new__(classType)
		#Make a shallow copy of the dictionary
		result.__dict__.update(self.__dict__)
		return result
		
	def __deepcopy__(self, memo):
		#Create the new class
		classType = self.__class__
		result = classType.__new__(classType)
		memo[id(self)] = result
		
		#Register at model manager
		self.modelManager.registerResource(result)
		
		#Problems may arise here with change listener, so just ignore it and set it later on
		result._fireChangeEvents = False
		tmpChangeEvent = False
		
		#Load all variable names that should no be deepcopied
		shallowAttr = self._shallowAttr();
		#Start deepcopy of whole dictionary
		for k, v in self.__dict__.items():
			if(k != "_fireChangeEvents"):
				if k in shallowAttr:
					print("Shallow: " + k)
					setattr(result, k, v)
				elif k in self._uniqueAttr():
					print("Unique: " + k)
					setattr(result, k, self._uniqueAttr()[k])
				else:
					print("Deeps: " + k)
					setattr(result, k, deepcopy(v, memo))
			else:
				tmpChangeEvent = v
		
		#Now set the change event to the right resource and potentially fire it
		result._fireChangeEvents = tmpChangeEvent
		if(result._fireChangeEvents == True):
			result.fireChangeEvent()
		return result
		
	def _shallowAttr(self):
		"""
		Returns a list of attribute names as a string that should not be deepcopied
		
		@return  :
		@author
		"""
		return ["_modelManager"];
		
	def _uniqueAttr(self):
		"""
		Returns a dictionary of attribute names as keys and undef as values that replace the new value
		
		@return  :
		@author
		"""
		return {}
Пример #11
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