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 __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()
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 __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 __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")
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")
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]]
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)
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]]
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 {}
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