【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

相关文章

MySQL的JDBC编程详解

《MySQL的JDBC编程详解》:本文主要介绍MySQL的JDBC编程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、前置知识1. 引入依赖2. 认识 url二、JDBC 操作流程1. JDBC 的写操作2. JDBC 的读操作总结前言本文介绍了mysq

Java实现复杂查询优化的7个技巧小结

《Java实现复杂查询优化的7个技巧小结》在Java项目中,复杂查询是开发者面临的“硬骨头”,本文将通过7个实战技巧,结合代码示例和性能对比,手把手教你如何让复杂查询变得优雅,大家可以根据需求进行选择... 目录一、复杂查询的痛点:为何你的代码“又臭又长”1.1冗余变量与中间状态1.2重复查询与性能陷阱1.

Spring创建Bean的八种主要方式详解

《Spring创建Bean的八种主要方式详解》Spring(尤其是SpringBoot)提供了多种方式来让容器创建和管理Bean,@Component、@Configuration+@Bean、@En... 目录引言一、Spring 创建 Bean 的 8 种主要方式1. @Component 及其衍生注解

Python异步编程之await与asyncio基本用法详解

《Python异步编程之await与asyncio基本用法详解》在Python中,await和asyncio是异步编程的核心工具,用于高效处理I/O密集型任务(如网络请求、文件读写、数据库操作等),接... 目录一、核心概念二、使用场景三、基本用法1. 定义协程2. 运行协程3. 并发执行多个任务四、关键

AOP编程的基本概念与idea编辑器的配合体验过程

《AOP编程的基本概念与idea编辑器的配合体验过程》文章简要介绍了AOP基础概念,包括Before/Around通知、PointCut切入点、Advice通知体、JoinPoint连接点等,说明它们... 目录BeforeAroundAdvise — 通知PointCut — 切入点Acpect — 切面

MySQL 数据库表操作完全指南:创建、读取、更新与删除实战

《MySQL数据库表操作完全指南:创建、读取、更新与删除实战》本文系统讲解MySQL表的增删查改(CURD)操作,涵盖创建、更新、查询、删除及插入查询结果,也是贯穿各类项目开发全流程的基础数据交互原... 目录mysql系列前言一、Create(创建)并插入数据1.1 单行数据 + 全列插入1.2 多行数据

MySQL 临时表创建与使用详细说明

《MySQL临时表创建与使用详细说明》MySQL临时表是存储在内存或磁盘的临时数据表,会话结束时自动销毁,适合存储中间计算结果或临时数据集,其名称以#开头(如#TempTable),本文给大家介绍M... 目录mysql 临时表详细说明1.定义2.核心特性3.创建与使用4.典型应用场景5.生命周期管理6.注

C#异步编程ConfigureAwait的使用小结

《C#异步编程ConfigureAwait的使用小结》本文介绍了异步编程在GUI和服务器端应用的优势,详细的介绍了async和await的关键作用,通过实例解析了在UI线程正确使用await.Conf... 异步编程是并发的一种形式,它有两大好处:对于面向终端用户的GUI程序,提高了响应能力对于服务器端应

MySQL的触发器全解析(创建、查看触发器)

《MySQL的触发器全解析(创建、查看触发器)》MySQL触发器是与表关联的存储程序,当INSERT/UPDATE/DELETE事件发生时自动执行,用于维护数据一致性、日志记录和校验,优点包括自动执行... 目录触发器的概念:创建触www.chinasem.cn发器:查看触发器:查看当前数据库的所有触发器的定

创建springBoot模块没有目录结构的解决方案

《创建springBoot模块没有目录结构的解决方案》2023版IntelliJIDEA创建模块时可能出现目录结构识别错误,导致文件显示异常,解决方法为选择模块后点击确认,重新校准项目结构设置,确保源... 目录创建spChina编程ringBoot模块没有目录结构解决方案总结创建springBoot模块没有目录