【ProM编程3】如何创建一个复杂的Plug-in

2023-11-09 19:59
文章标签 创建 编程 复杂 plug prom

本文主要是介绍【ProM编程3】如何创建一个复杂的Plug-in,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本节在前两节的基础上,介绍如何创建一个复杂的Plug-in。

目录

1.本节介绍

2.基于非静态方法的插件

3.重载插件

3.1  可配置的输入

 3.2 多类型输入

4.总结


1.本节介绍

        到目前为止,本文介绍了简单的插件,其中所有的计算都是通过静态方法执行的。在本节中,我们将介绍两种更复杂的插件类型,即基于非静态方法的插件和重载插件

2.基于非静态方法的插件

        与基于静态方法的插件类似,您可以基于非静态方法定义插件。考虑以下代码, 这与早期的helloWorld示例非常相似,但现在helloworld方法不是静态的.

package org.processmining.plugins.gettingstarted;import org.processmining.contexts.uitopia.annotations.UITopiaVariant;
import org.processmining.framework.plugin.PluginContext;
import org.processmining.framework.plugin.annotations.Plugin;public class HelloWorld9 {@Plugin(name = "My 5th Hello World Plug-in", parameterLabels = {}, returnLabels = { "Hello world string" }, returnTypes = { String.class }, userAccessible = true, help = "Produces the string: 'Hello world'")@UITopiaVariant(affiliation = "My company", author = "My name", email = "My e-mail address")public String helloWorld(PluginContext context) {return "Hello World";}
}

        在ProM中使用此插件时,您会发现与静态版本在行为上没有任何区别。然而,存在一个重要的概念差异。如果用@Plugin注释注释的方法不是静态的,就像这里的情况一样,那么当被要求执行这个插件时,框架将调用该方法,就像在框架中的某个地方调用了以下代码一样:

HelloWorld9 hw9 = new HelloWorld9();
hw9.helloWorld(context);

        这里,首先创建类HelloWorld9的一个实例,并为此实例调用方法helloWorld。这意味着在方法主体中,类的所有私有成员都是可访问和实例化的。请注意,使用非静态方法作为插件需要存在默认构造函数,即不带参数的构造函数

3.重载插件

        到目前为止引入的基于方法的插件允许定义已知输入类型的插件。然而,在实践中,许多插件允许应用于多种类型的输入。例如,考虑一个构建Petri网可达性图的插件。这样的插件接受Petri网【a plug-in accepts Petri nets】,但也接受重置网(具有重置弧的Petri网)【Reset nets (Petri nets with reset arcs)】、约束网(具有约束弧的Petri网)【Inhibitor nets (Petri nets with inhibitor arcs)】和重置/约束网【Reset/Inhibitor nets】。

         此外,有时插件只需要m个参数中的n个。例如,考虑使用一个插件来打开一个文件。它的输入是文件名(可以是String、URI、File或FileInputStream类型)。然而,这个插件也可以在没有输入的情况下执行,在这种情况下,会向用户显示一个对话框,以提供指向要打开的文件的指针。但是请注意,只有在GUI中执行插件时,才能显示这样的对话框。

        过载的插件允许上面提到的场景。在本节中,我们将介绍带有变体的插件的概念,这就是这些场景的实现方式。在显示具有多种类型的参数之前,我们首先介绍了可选参数的概念。

3.1  可配置的输入

考虑以下代码:

package org.processmining.plugins.gettingstarted;import javax.swing.JOptionPane;import org.processmining.contexts.uitopia.UIPluginContext;
import org.processmining.contexts.uitopia.annotations.UITopiaVariant;
import org.processmining.framework.plugin.PluginContext;
import org.processmining.framework.plugin.annotations.Plugin;
import org.processmining.framework.plugin.annotations.PluginVariant;@Plugin(name = "My Overloaded Hello World Plugin", parameterLabels = { "First string", "Number", "Second string" }, returnLabels = { "Hello world string" }, returnTypes = { String.class }, userAccessible = true, help = "The plugin produces 'hello' concatenated with at least one world. If no world is given, it is requested from the user, provided that a GUI exists."
)
public class HelloWorld10 {private String getWorld(UIPluginContext context) {// Ask the user for his worldString w = JOptionPane.showInputDialog(null, "What's the name of your world?","Enter your world", JOptionPane.QUESTION_MESSAGE);// change your result labelcontext.getFutureResult(0).setLabel("Hello " + w + " string");return w;}@PluginVariant(variantLabel = "My original hello world", requiredParameterLabels = {})@UITopiaVariant(uiLabel = "My original hello world", affiliation = "My company", author = "My name", email = "My e-mail address")public String helloWorld(PluginContext context) {return "Hello World";}@PluginVariant(variantLabel = "My Hello unknown", requiredParameterLabels = {})@UITopiaVariant(uiLabel = "My Hello unknown", affiliation = "My company", author = "My name", email = "My e-mail address")public String helloUnknown(UIPluginContext context) {return "Hello " + getWorld(context);}@PluginVariant(variantLabel = "My Combine worlds", requiredParameterLabels = { 0, 1, 2 })@UITopiaVariant(uiLabel = "My Combine worlds", affiliation = "My company", author = "My name", email = "My e-mail address")public Object helloWorlds(PluginContext context, String first, Integer number, String second) {String s = first;for (int i = 0; i < number; i++) {s += "," + second;}return s;}@PluginVariant(variantLabel = "My Combine unknowns", requiredParameterLabels = { 0, 1 })@UITopiaVariant(uiLabel = "My Combine unknowns", affiliation = "My company", author = "My name", email = "My e-mail address")public Object helloWorlds(UIPluginContext context, String first, Integer number) {// return the combined string, after asking for the worldreturn helloWorlds(context, first, number, getWorld(context));}
}

        在本例中,@Plugin注释不再用于方法,而是用于类。这向框架发出信号,表明这是一个重载的插件,由几个变体组成。这意味着应该至少有一个方法带有@PluginVariant注释。在这种情况下有四个。
        这个类的@Plugin注释与我们之前使用过的方法相同。因此,这里必须指定参数的标签,以及所有变体的返回类型。因此,所有变体都必须返回相同类型的对象,即在本例中它们都应该返回一个String。复杂的返回类型是允许的,只要它们对于所有变体都是相同的。
        此示例代码提供的插件的四个变体由一个标签和该变体所需参数的列表定义。此外,它们需要执行不同的上下文。在下表中,对四种变体进行了简要概述:

 3.2 多类型输入

        在前面的例子中,插件变体都使用了相同类型的参数的不同组合,即“Combine”未知变量需要标记为“First string”和“Number”的参数,在方法定义中,这两个参数的类型分别为“string”和“Integer”。然而,这并不是框架强加的要求,如以下代码所示:

package org.processmining.plugins.gettingstarted;import javax.swing.JOptionPane;import org.processmining.contexts.uitopia.UIPluginContext;
import org.processmining.contexts.uitopia.annotations.UITopiaVariant;
import org.processmining.framework.plugin.PluginContext;
import org.processmining.framework.plugin.annotations.Plugin;
import org.processmining.framework.plugin.annotations.PluginVariant;@Plugin(name = "My Overloaded Hello Many Worlds", parameterLabels = { "First string", "Large Number", "Second string" }, returnLabels = { "Hello world string" }, returnTypes = { String.class }, userAccessible = true, help = "The plugin produces 'hello' concatenated with at least one world. If no world is given, it is requested from the user, provided that a GUI exists."
)
public class HelloWorld11 {private String getWorld(UIPluginContext context) {// Ask the user for his worldString w = JOptionPane.showInputDialog(null, "What's the name of your world?","Enter your world", JOptionPane.QUESTION_MESSAGE);// change your result labelcontext.getFutureResult(0).setLabel("Hello " + w + " string");return w;}@PluginVariant(variantLabel = "My Combine many worlds", requiredParameterLabels = { 0, 1, 2 })@UITopiaVariant(uiLabel = "My Combine many worlds", affiliation = "My company", author = "My name", email = "My e-mail address")public Object helloWorlds(PluginContext context, String first, Long number, String second) {String s = first;for (int i = 0; i < number; i++) {s += "," + second;}return s;}@PluginVariant(variantLabel = "My Combine few unknowns", requiredParameterLabels = { 0, 1 })@UITopiaVariant(uiLabel = "My Combine few unknowns", affiliation = "My company", author = "My name", email = "My e-mail address")public Object helloWorlds(UIPluginContext context, String first, Integer number) {// return the combined string, after asking for the worldreturn helloWorlds(context, first, Long.valueOf(number), getWorld(context));}@PluginVariant(variantLabel = "My Combine many unknowns", requiredParameterLabels = { 0, 1 })@UITopiaVariant(uiLabel = "My Combine many unknowns", affiliation = "My company", author = "My name", email = "My e-mail address")public Object helloWorlds(UIPluginContext context, String first, Long number) {// return the combined string, after asking for the worldreturn helloWorlds(context, first, number, getWorld(context));}
}

4.总结

        通过使用插件变体,可以定义复杂的插件来处理不同类型的参数。然而,有几点需要记住:
(1) 如果在确定上下文中不能执行任何变体,则该插件被框架忽略,
(2) 用@PluginVariant注释注释的插件变体的方法必须全部返回类的@Plugin注释中指定类型的对象。在执行插件之前,框架不会检查这一点,在这种情况下,如果返回类型不匹配,就会抛出异常。
(3) 插件变体既可以是静态的,也可以是非静态的
(4) 使用过多的插件变体可能会令人困惑(但有时是必要的)。通常,如果存在许多变体,那么将实际逻辑的实现推迟到(a)私有方法,并保持用@PluginVariant注释注释的方法代码尽可能干净,这是一种很好的编程实践。
(5) 插件变体可以在超类中定义,也就是说,可以定义一个包含许多变体的抽象类,这些变体都调用一个抽象保护方法,该方法在子类中实现。然而,@Plugin注释应该只在子类级别上使用,否则超类和子类都被视为插件。作为这种构造的一个例子,我们指的是以下各项的组合:
        org.processmining.plugins.abstractplugins.AbstractImportPlugin,它定义了打开由不同对象指定的文件的变体,但本身不是一个插件,以及
        org.processmining.plugins.etrinet.tpn.TpnImport,它实现了AbstractImportPlugin的抽象方法,并定义了@Plugin注释。
(6) 用@PluginVariant注释注释的类的方法也可以用@Plugin注释注释。在这种情况下,这些方法被框架视为单独的插件。然而,这种构造是不鼓励的,因为它会导致复杂的代码。
(7) @PluginVariant注释由子类继承。因此,任何用@Plugin注释注释的类都可以由另一个用@Plugine注释的类扩展。超类的变体也存在于子类中。这要求继承关系中的任何两个插件的结果类型都相同。同样,只有在执行了插件之后才会检查这一点。

这篇关于【ProM编程3】如何创建一个复杂的Plug-in的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/378210

相关文章

Python中Tkinter GUI编程详细教程

《Python中TkinterGUI编程详细教程》Tkinter作为Python编程语言中构建GUI的一个重要组件,其教程对于任何希望将Python应用到实际编程中的开发者来说都是宝贵的资源,这篇文... 目录前言1. Tkinter 简介2. 第一个 Tkinter 程序3. 窗口和基础组件3.1 创建窗

C#高效实现在Word文档中自动化创建图表的可视化方案

《C#高效实现在Word文档中自动化创建图表的可视化方案》本文将深入探讨如何利用C#,结合一款功能强大的第三方库,实现在Word文档中自动化创建图表,为你的数据呈现和报告生成提供一套实用且高效的解决方... 目录Word文档图表自动化:为什么选择C#?从零开始:C#实现Word文档图表的基本步骤深度优化:C

Python列表的创建与删除的操作指南

《Python列表的创建与删除的操作指南》列表(list)是Python中最常用、最灵活的内置数据结构之一,它支持动态扩容、混合类型、嵌套结构,几乎无处不在,但你真的会创建和删除列表吗,本文给大家介绍... 目录一、前言二、列表的创建方式1. 字面量语法(最常用)2. 使用list()构造器3. 列表推导式

JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)

《JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)》:本文主要介绍如何在IntelliJIDEA2020.1中创建和部署一个JavaWeb项目,包括创建项目、配置Tomcat服务... 目录简介:一、创建项目二、tomcat部署1、将tomcat解压在一个自己找得到路径2、在idea中添加

Java利用Spire.Doc for Java实现在模板的基础上创建Word文档

《Java利用Spire.DocforJava实现在模板的基础上创建Word文档》在日常开发中,我们经常需要根据特定数据动态生成Word文档,本文将深入探讨如何利用强大的Java库Spire.Do... 目录1. Spire.Doc for Java 库介绍与安装特点与优势Maven 依赖配置2. 通过替换

java创建xls文件放到指定文件夹中实现方式

《java创建xls文件放到指定文件夹中实现方式》本文介绍了如何在Java中使用ApachePOI库创建和操作Excel文件,重点是如何创建一个XLS文件并将其放置到指定文件夹中... 目录Java创建XLS文件并放到指定文件夹中步骤一:引入依赖步骤二:创建XLS文件总结Java创建XLS文件并放到指定文件

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

Linux创建服务使用systemctl管理详解

《Linux创建服务使用systemctl管理详解》文章指导在Linux中创建systemd服务,设置文件权限为所有者读写、其他只读,重新加载配置,启动服务并检查状态,确保服务正常运行,关键步骤包括权... 目录创建服务 /usr/lib/systemd/system/设置服务文件权限:所有者读写js,其他