def cache_extension(uri): """Downloads and caches an extension from its remote definition file. The extension is subsequently placed in the local cache, so that future loading is accelerated. :param uri: Unique URI of the extension which is to be cached. :type uri: urllib.parse.ParseResult or urllib.parse.SplitResult """ uri_str = uri.geturl() if uri_str[-1] == "/": uri_str = uri_str[(0, len(uri_str) - 1)] filename = uri_str[uri_str.rindex(chr(47)):] if not filename.endswith(".xesext"): filename += ".xesext" cache_file = XRuntimeUtils().get_extension_cache_folder( ) + os.path.sep + filename try: bis = request.urlopen(uri.geturl()) bos = open(cache_file, "w") file = bis.read(1024) while file != b"": bos.write(file) file = bis.read(1024) bos.close() XLogging().log("Cached XES extension \\'" + uri.geturl() + "\\'", XLogging.Importance.DEBUG) except IOError as e: print("I/O error({0}): {1}".format(e.errno, e.strerror))
def load_extension_cache(self): """Loads all extensions stored in the local cache. Cached extensions which exceed the maximum caching age are discarded, and downloaded freshly. """ min_modified = (lambda: int(round(time.time() * 1000)))() - 2592000000 ext_folder = XRuntimeUtils().get_extension_cache_folder() ext_files = list(filter(os.path.isfile, os.listdir(ext_folder))) if len(ext_files) == 0: XLogging().log( "Extension caching disabled (Could not access cache" " directory)!", XLogging.Importance.WARNING) return for i in range(len(ext_files)): ext_file = ext_files[i] if ext_file.lower().endswith(".xesext"): file_name = ext_folder + os.path.sep + ext_file if os.path.getmtime(file_name) * 1000 < min_modified: if os.path.exists(file_name): os.remove(file_name) else: try: extension = XExtensionParser.parse(file_name) if extension.get_uri() not in self.__extension_map: self.__extension_map[ extension.get_uri()] = extension self.__extension_list.append(extension) XLogging().log( "Loaded XES extension \'" + extension.get_uri().geturl() + "\' from cache", XLogging.Importance.DEBUG) else: XLogging().log( "Skipping cached XES extension \'" + extension.get_uri().geturl() + "\' (already defined)", XLogging.Importance.DEBUG) except Exception as e: print("Exception error: {}".format(e))
def endElement(self, local_name): """ Overrides endElement in class ContentHandler :param local_name: The name of the element type, just as with the startElement event :type local_name: str """ tag_name = local_name if tag_name == "WorkflowLog": if self.__numUnorderedEntries > 0: XLogging().log( "LogData: Log contains " + str(self.__numUnorderedEntries) + " audit trail entries in non-natural order!", XLogging.Importance.ERROR) XLogging().log( "LogData: The log file you have loaded is not MXML compliant! (error compensated transparently)", XLogging.Importance.ERROR) elif tag_name == "Process": self.__currentProcess.get_classifiers().extend( XMxmlParser.MXML_CLASSIFIERS) self.__currentProcess.get_global_trace_attributes().append( XConceptExtension().ATTR_NAME.clone()) self.__currentProcess.get_global_event_attributes().append( XConceptExtension().ATTR_NAME.clone()) self.__currentProcess.get_global_event_attributes().append( XLifecycleExtension().ATTR_TRANSITION.clone()) self.__logs.append(self.__currentProcess) self.__currentProcess = None elif tag_name == "Process": self.__sourceOpen = False elif tag_name == "ProcessInstance": if len(self.__currentInstance) > 0: self.__currentProcess.append(self.__currentInstance) self.__currentInstance = None self.__lastTimestamp = None elif tag_name == "AuditTrailEntry": if self.__timestamp is None: self.__currentInstance.append(self.__entry) elif self.__lastTimestamp is None: self.__currentInstance.append(self.__entry) self.__lastTimestamp = self.__timestamp elif self.__timestamp > self.__lastTimestamp: self.__currentInstance.append(self.__entry) self.__lastTimestamp = self.__timestamp else: self.__currentInstance.append(self.__entry) self.__entry = None else: if tag_name == "Attribute": originator = "".join(self.__buffer).strip() if len(originator) > 0: self.__genericAttribute.set_value("".join( self.__buffer).strip()) if self.__entry: self.__entry.get_attributes()[ self.__genericAttribute.get_key( )] = self.__genericAttribute elif self.__currentInstance: self.__currentInstance.get_attributes()[ self.__genericAttribute.get_key( )] = self.__genericAttribute elif self.__currentProcess: self.__currentProcess.get_attributes()[ self.__genericAttribute.get_key( )] = self.__genericAttribute elif self.__sourceOpen: self.__sourceAttribute.get_attributes()[ self.__genericAttribute.get_key( )] = self.__genericAttribute self.__genericAttribute = None elif tag_name == "EventType": if self.__eventTypeAttribute.get_value() == "UNKNOWN": originator = "".join(self.__buffer).strip() if len(originator) > 0: self.__eventTypeAttribute.set_value(originator) self.__entry.get_attributes()[ self.__eventTypeAttribute.get_key( )] = self.__eventTypeAttribute else: self.__entry.get_attributes()[ self.__eventTypeAttribute.get_key( )] = self.__eventTypeAttribute self.__eventTypeAttribute = None elif tag_name == "WorkflowModelElement": XConceptExtension().assign_name( self.__entry, "".join(self.__buffer).strip()) elif tag_name == "Timestamp": originator = "".join(self.__buffer).strip() self.__timestamp = parse_date_time(originator) if self.__timestamp: timestamp_attribute = XTimeExtension( ).ATTR_TIMESTAMP.clone() timestamp_attribute.set_value(self.__timestamp) self.__entry.get_attributes( )[timestamp_attribute.get_key()] = timestamp_attribute elif tag_name == "Originator": originator = "".join(self.__buffer).strip() if len(originator) > 0: self.__originatorAttribute.set_value(originator) self.__entry.get_attributes()[ self.__originatorAttribute.get_key( )] = self.__originatorAttribute self.__originatorAttribute = None self.__buffer.clear()
def serialize(self, log, out, in_bytes=False): """Serializes a given log to the given output stream. :param log: Log to be serialized. :type log: `XLog` :param out: TextIOWrapper for serialization. :type out: _io.TextIOWrapper :param in_bytes: Private argument to decide if serialized in bytes or in string :type in_bytes: bool """ XLogging().log("start serializing log to MXML", XLogging.Importance.DEBUG) start = time.time() * 1000 root = Et.Element("WorkflowLog") source = Et.SubElement(root, "Source") source.set("program", "XES MXML serialization") source.set("openxes.version", "1.0RC7") process = Et.SubElement(root, "Process") identity = XConceptExtension().extract_name(log) if identity is None: process.set("id", "none") else: process.set("id", identity) name = XConceptExtension().extract_name(log) if name is None: name = "None" process.set("description", "process with id " + name) self.add_model_reference(log, process) self.add_attribute(process, log.get_attributes().values()) for trace in log: instance = Et.SubElement(process, "ProcessInstance") identity = XConceptExtension().extract_name(trace) if identity is None: identity = "None" instance.set("id", identity) name = XConceptExtension().extract_name(trace) if name is None: name = "None" instance.set("description", "instance with id " + name) self.add_model_reference(trace, instance) self.add_attribute(instance, trace.get_attributes().values()) for event in trace: ate = Et.SubElement(instance, "AuditTrailEntry") self.add_attribute(ate, event.get_attributes().values()) workflow_mode = Et.SubElement(ate, "WorkflowModelElement") self.add_model_reference(event, workflow_mode) workflow_mode.text = XConceptExtension().extract_name(event) type_ = Et.SubElement(ate, "EventType") type_attr = event.get_attributes().get("lifecycle:transition") if type_attr: self.add_model_reference(type_attr, type_) originator_attr = type_attr.get_value().strip().lower() if originator_attr in self.__known_types: type_.text = originator_attr else: type_.set("unknownType", type_attr.get_value()) type_.text = "unknown" else: type_.text = "complete" originator_attr_1 = event.get_attributes().get("org:resource") if originator_attr_1 is None: originator_attr_1 = event.get_attributes().get("org:role") if originator_attr_1 is None: originator_attr_1 = event.get_attributes().get("org:group") if originator_attr_1 is not None: timestamp_attr = Et.SubElement(ate, "originator") self.add_model_reference(originator_attr_1, timestamp_attr) timestamp_attr.text = (originator_attr_1.get_value()) timestamp_attr_1 = event.get_attributes().get("time:timestamp") if timestamp_attr_1: timestamp = Et.SubElement(ate, "timestamp") self.add_model_reference(timestamp_attr_1, timestamp) date = timestamp_attr_1.get_value() timestamp.text = str(date) text = minidom.parseString(Et.tostring(root, "utf-8")) c1 = text.createComment( "This file has been generated with the OpenXES library. It conforms" ) c2 = text.createComment( "to the legacy MXML standard for log storage and management.") c3 = text.createComment("OpenXES library version: 1.0RC7") c4 = text.createComment( "OpenXES is available from http://www.xes-standard.org/") text.insertBefore(c4, text.childNodes[0]) text.insertBefore(c3, text.childNodes[0]) text.insertBefore(c2, text.childNodes[0]) text.insertBefore(c1, text.childNodes[0]) if in_bytes: out.write(text.toprettyxml("\t").encode()) else: out.write(text.toprettyxml("\t")) duration1 = " (" + str(time.time() * 1000 - start) + " msec.)" XLogging().log("finished serializing log" + duration1, XLogging.Importance.DEBUG)
def serialize(self, log, out, in_bytes=False): """Serializes a given log to the given output stream. :param log: Log to be serialized. :type log: XLog :param out: TextIOWrapper for serialization. :type out: _io.TextIOWrapper :param in_bytes: Private argument to decide if serialized as bytes or as string :type in_bytes: bool """ XLogging().log("Start serializing log to XES.XML", XLogging.Importance.DEBUG) start = time.time() * 1000 log_xml = Et.Element("log") log_xml.set("xes.version", "1.0") log_xml.set("xes.features", "nested-attributes") log_xml.set("openxes.version", "1.0RC7") for extension in log.get_extensions(): extension_xml = Et.SubElement(log_xml, "extension") extension_xml.set("name", extension.get_name()) extension_xml.set("prefix", extension.get_prefix()) extension_xml.set("uri", extension.get_uri().geturl()) self.add_global_attributes(log_xml, "trace", log.get_global_trace_attributes()) self.add_global_attributes(log_xml, "event", log.get_global_event_attributes()) for classifier in log.get_classifiers(): if isinstance(classifier, XEventAttributeClassifier): classifier_xml = Et.SubElement(log_xml, "classifier") classifier_xml.set("name", classifier.name()) classifier_xml.set( "keys", XTokenHelper.format_token( classifier.get_defining_attribute_keys())) self.add_attributes(log_xml, log.get_attributes().values()) for trace in log: trace_xml = Et.SubElement(log_xml, "trace") self.add_attributes(trace_xml, trace.get_attributes().values()) for event in trace: event_xml = Et.SubElement(trace_xml, "event") self.add_attributes(event_xml, event.get_attributes().values()) text = minidom.parseString(Et.tostring(log_xml, "utf-8")) c1 = text.createComment( "This file has been generated with the OpenXES library. It conforms" ) c2 = text.createComment( "to the XML serialization of the XES standard for log storage and") c3 = text.createComment("management.") c4 = text.createComment("XES standard version: 1.0") c5 = text.createComment("OpenXES library version: 1.0RC7") c6 = text.createComment( "OpenXES is available from http://www.openxes.org/") text.insertBefore(c6, text.childNodes[0]) text.insertBefore(c5, text.childNodes[0]) text.insertBefore(c4, text.childNodes[0]) text.insertBefore(c3, text.childNodes[0]) text.insertBefore(c2, text.childNodes[0]) text.insertBefore(c1, text.childNodes[0]) if in_bytes: out.write(text.toprettyxml("\t").encode()) else: out.write(text.toprettyxml("\t")) duration1 = " (" + str(time.time() * 1000 - start) + " msec.)" XLogging().log("finished serializing log" + duration1, XLogging.Importance.DEBUG)