【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 异步编程 asyncio简介及基本用法

《Python异步编程asyncio简介及基本用法》asyncio是Python的一个库,用于编写并发代码,使用协程、任务和Futures来处理I/O密集型和高延迟操作,本文给大家介绍Python... 目录1、asyncio是什么IO密集型任务特征2、怎么用1、基本用法2、关键字 async1、async

Java 如何创建和使用ExecutorService

《Java如何创建和使用ExecutorService》ExecutorService是Java中用来管理和执行多线程任务的一种高级工具,可以有效地管理线程的生命周期和任务的执行过程,特别是在需要处... 目录一、什么是ExecutorService?二、ExecutorService的核心功能三、如何创建

使用Python创建一个功能完整的Windows风格计算器程序

《使用Python创建一个功能完整的Windows风格计算器程序》:本文主要介绍如何使用Python和Tkinter创建一个功能完整的Windows风格计算器程序,包括基本运算、高级科学计算(如三... 目录python实现Windows系统计算器程序(含高级功能)1. 使用Tkinter实现基础计算器2.

CentOS和Ubuntu系统使用shell脚本创建用户和设置密码

《CentOS和Ubuntu系统使用shell脚本创建用户和设置密码》在Linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设置密码,本文写了一个shell... 在linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

使用Python和Pyecharts创建交互式地图

《使用Python和Pyecharts创建交互式地图》在数据可视化领域,创建交互式地图是一种强大的方式,可以使受众能够以引人入胜且信息丰富的方式探索地理数据,下面我们看看如何使用Python和Pyec... 目录简介Pyecharts 简介创建上海地图代码说明运行结果总结简介在数据可视化领域,创建交互式地

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

resultMap如何处理复杂映射问题

《resultMap如何处理复杂映射问题》:本文主要介绍resultMap如何处理复杂映射问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录resultMap复杂映射问题Ⅰ 多对一查询:学生——老师Ⅱ 一对多查询:老师——学生总结resultMap复杂映射问题

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.