【ProM编程2】context--上下文

本文详细介绍了ProM框架中PluginContext的使用,包括日志记录、进度指示器、Future的概念、对象管理和连接管理。PluginContext提供了与框架、其他插件及用户通信的接口,支持多线程执行,并允许插件在不同上下文中运行。同时,文章讲解了如何创建和管理连接,以及插件生命周期中的关键操作。
摘要由CSDN通过智能技术生成

ProM中的关于PluginContext的一些使用。

 

目录

1. 前言回顾

2. Logging

3.进度指示器(Progress Indicator )

4. 未来(Futures)

5. 提供对象管理

6. 连接管理

6.1 Connections 连接

6.2 正在查找连接Finding connections

6.3 连接工厂   Connection factory

7. Multi-threaded execution 

8.Plug-in management 

9. Specific contexts

 10.Plug-in life-cycle


1. 前言回顾

      在上一节的示例插件中,我们看到每个插件都使用PluginContext参数进行调用。PluginContext的理念是,它提供了所有必要的接口来进行通信:框架,其他插件,以及用户在本节中,我们首先讨论所有上下文中可用的一般功能。然后,我们讨论上下文的具体实现,以及如何定义需要特定上下文的插件。。插件可以在各种上下文中执行,例如GUI或脚本上下文。

        具体可参考上一讲内容:【ProM编程1】创建一个Hello World!_北冥有鱼zsp的博客-CSDN博客

2. Logging

        上下文最重要的特性之一是日志记录功能。为此,有两种方法可用:

void log(String message);
void log(String message, MessageLevel level);

        这些方法允许用户记录信息。消息级别指示信息的类型,可以是“正常(Normal)”、“警告(Warning)”、“错误(Error)”、“测试(Test)”或“调试(Debug)”。如果未指定消息级别,则假定为“正常(Normal)”。

        每个上下文都有许多与之相关的日志侦听器。这些侦听器接收每个记录的消息,并决定如何处理它们。例如,GUI确保它被注册为框架中所有插件上下文的日志侦听器。默认情况下,调试和测试消息是关闭的,但用户可以打开这些消息。
        下面的代码 显示了hello-world插件,该插件记录有关其执行的信息:

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;
import org.processmining.framework.plugin.events.Logger.MessageLevel;

public class HelloWorld4 {
        @Plugin(
                name = "My 3rd 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 static String helloWorld(PluginContext context) {
                context.log("Started hello world plug-in", MessageLevel.DEBUG);
                return "Hello World";
        }
}

     可以看出,上述的context.log()函数打印了调试信息"Started hello world plug-in"

3.进度指示器(Progress Indicator )

        尽管日志记录提供了一种向插件用户发出进度信号的方法,但更好的方法是使用进度指示器。特别是如果插件包含许多需要一些时间的步骤,这是一个好主意。下面的代码显示了一个插件,该插件指示了框架的进展:

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 HelloWorld5 {
        @Plugin(
                name = "My 2nd Combine Worlds Plug-in", 
                parameterLabels = { "First string", "Number", "Second string" }, 
                returnLabels = { "First string several second strings" }, 
                returnTypes = { String.class }, 
                userAccessible = true, 
                help = "Produces one string consisting of the first and a number of times the third parameter."
        )
        @UITopiaVariant(
                affiliation = "My company", 
                author = "My name", 
                email = "My e-mail address"
        )
        public static Object helloWorlds(PluginContext context, String first, Integer number, String second) {
                context.getProgress().setMinimum(0);
                context.getProgress().setMaximum(number);
                context.getProgress().setCaption("Constructing hello worlds string");
                context.getProgress().setIndeterminate(false);
                String s = first;
                for (int i = 0; i < number; i++) {
                        s += "," + second;
                        try {
                                Thread.sleep(1000);
                        } catch (InterruptedException e) {
                                // don't care
                        }
                        context.getProgress().inc();
                }
                return s;
        }
}

        首先,设置存在进度的步骤数(在这种情况下,与参数号提供的步骤数一样多)。然后,对进展情况进行说明。最后,进度增加了,也可以使用setValue(getValue()+1)来完成。为了在GUI中观察进度,这个插件包括睡眠。
当执行此插件时,将显示一个进程指示器:

4. 未来(Futures)

        对象的未来是一个概念,它允许用户在尚未可用的输入上启动插件。回想一下,插件在@Plugin注释中指定了其方法的返回类型。这使框架能够知道在开始执行插件时需要什么类型的对象,即使对象本身不可用

        当一个插件被执行时,框架首先实例化该插件的插件上下文。然后,根据所有预期结果创建期货。这些未来由一个标签和一种类型组成类型是从@Plugin注释中指定的returnTypes读取的,标签最初是从@Plugin注释中规定的returnLabels读取的

但是,在执行过程中,插件可以通过调用context.getFutureResult(int number)与其未来的结果进行通信。这里,作为参数给定的整数表示请求哪个future,即在多个返回类型的情况下,创建多个future。

        尽管从技术上讲,插件可以取消对其未来的计算,但这通常是不可取的。相反,与未来的通信应该仅限于调用context.getFutureResult(x).setLabel(newLabel),在这种情况下,结果的标签会被更新。

考虑以下代码:

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 HelloWorld6 {
        @Plugin(
                name = "My 3rd Combine Worlds Plug-in", 
                parameterLabels = { "First string", "Number", "Second string" }, 
                returnLabels = { "First string several second strings" }, 
                returnTypes = { String.class }, 
                userAccessible = true, 
                help = "Produces one string consisting of the first and a number of times the third parameter."
        )
        @UITopiaVariant(
                affiliation = "My company", 
                author = "My name", 
                email = "My e-mail address"
        )
        public static Object helloWorlds(PluginContext context, String first, Integer number, String second) {
                context.getProgress().setMinimum(0);
                context.getProgress().setMaximum(number);
                context.getProgress().setCaption("Constructing hello worlds string");
                context.getProgress().setIndeterminate(false);
                String s = first;
                for (int i = 0; i < number; i++) {
                        s += "," + second;
                        context.getFutureResult(0).setLabel("Hello " + i + " worlds string");

                        try {
                                Thread.sleep(1000);
                        } catch (InterruptedException e) {
                                // don't care
                        }
                        context.getProgress().inc();
                }
                context.getFutureResult(0).setLabel("Hello " + number + " worlds string");
                return s;
        }
}

        有了这段代码,“My 3rd Combine Worlds Plug-in”插件会不断更新未来结果的标签,以显示添加world的频率。
        请注意,方法context.getFutureResult(intx)只能从插件中调用。插件一完成,该方法就会抛出一个类强制转换异常。
        除了改变表示插件的未来结果的所提供对象的标签之外,插件还可以访问所提供的对象管理系统,以对所提供的物体进行完全控制。

5. 提供对象管理

        通常,只要调用插件,它们的结果就可以作为所提供的对象使用。起初,这些对象是future,但一旦插件完成执行,future就会被实际对象所取代。
        框架中的所有对象都由提供的对象管理器处理,可以通过上下文访问对象管理器。然而,插件通常只需要一点可用的功能,即创建和更新所提供的对象
        尽管该框架确保插件返回的所有结果都可以作为所提供的对象使用,但插件有时需要更多。例如,考虑the genetic mining插件,此插件在完成时返回一个模型列表。然而,与此同时,构建了几个可能对用户感兴趣的模型。框架显然不知道这些中间对象。因此,插件可以创建自己提供的对象。所提供的对象由一个标签和一个对象组成。要创建提供的对象,应调用ProvidedObjectManager的createProvidedObject方法。这种方法不仅需要标签和对象,还需要上下文。此上下文是必需的,以便侦听器可以被通知所提供对象的创建。
        一旦创建了所提供的对象,它就会获得一个ID,该ID可以用于以后引用该对象,例如更新或删除它。

        考虑以下代码:

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;
import org.processmining.framework.providedobjects.ProvidedObjectDeletedException;
import org.processmining.framework.providedobjects.ProvidedObjectID;

public class HelloWorld7 {
        @Plugin(
                name = "My 4th Combine Worlds Plug-in", 
                parameterLabels = { "First string", "Number", "Second string" }, 
                returnLabels = { "First string several second strings" }, 
                returnTypes = { String.class }, 
                userAccessible = true, 
                help = "Produces one string consisting of the first and anumber of times the third parameter."
        )
        @UITopiaVariant(
                affiliation = "My company", 
                author = "My name", 
                email = "My e-mail address"
        )
        public static Object helloWorlds(PluginContext context, String first, Integer number, String second) {
                context.getProgress().setMinimum(0);
                context.getProgress().setMaximum(number);
                context.getProgress().setCaption("Constructing hello worlds string");
                context.getProgress().setIndeterminate(false);
                String s = first;
                ProvidedObjectID id = context.getProvidedObjectManager()
                                .createProvidedObject("intermediate string", s, context);
                for (int i = 0; i < number; i++) {
                        context.getFutureResult(0).setLabel("Hello " + i + " worlds string");
                        try {
                                context.getProvidedObjectManager().changeProvidedObjectObject(id, s);
                                Thread.sleep(1000);
                        } catch (ProvidedObjectDeletedException e1) {
                                // if the user deleted this object,
                                // then we create it again
                                id = context.getProvidedObjectManager().createProvidedObject("intermediate string", s, context);
                        } catch (InterruptedException e) {
                                // don't care
                        }
                        s += "," + second;
                        context.getProgress().inc();
                }
                context.getFutureResult(0).setLabel("Hello " + number + " worlds string");
                // The intermediate object is no longer necessary.
                try {
                        context.getProvidedObjectManager().deleteProvidedObject(id);
                } catch (ProvidedObjectDeletedException e) {
                        // Don't care
                }
                return s;
        }
}

        对“My 3rd Combine Worlds Plug-in”的更改显示了如何创建、更新和删除中间提供的对象。首先创建对象,并保留id以备将来参考。然后,所提供的对象被更新为新的字符串。但是,如果用户删除了对象(通过在GUI中单击鼠标右键),则会引发异常。在这种情况下,会捕获异常并创建一个新的提供对象。最后,所提供的对象被删除。

6. 连接管理

        到目前为止,我们引入的插件将许多参数作为输入,并生成许多结果对象。然而,在大多数情况下,输入和输出对象是相互关联的,例如,当与另一个Petri网组合时,Petri网的标记没有意义。相反,Marking和Petri网有一个连接,表示Marking标记了Petri网的位置。
        在ProM框架中,对象之间的关系存储在连接中。通过连接管理器再次添加连接或检查连接是否存在,可以通过调用context.getConnectionManager()来访问连接管理器。
        我们首先解释如何添加连接,在连接管理器中可以使用一种方法。此方法需要指定上下文,因此PluginContext还提供了一个addConnection方法,该方法以自身为参数调用连接管理器的addConnection。

6.1 Connections 连接

        连接是从一组标签到对象的映射。每个标签表示连接中附着对象的角色。此外,连接本身有一个标签。
一旦将连接添加到连接管理器中,它们就存在于框架中。然而,当连接中的一个对象对用户不再可用时(例如,因为提供的对象被删除),则该连接将不存在。换句话说,对连接中对象的引用被存储为弱引用,也就是说,如果框架中不再需要该对象,那么连接就不会将其保存在内存中。每次要求连接管理器获取连接时,都要检查连接是否仍然存在。
通常,连接不需要显式表示连接的方法,例如,在标记和Petri网的情况下,如果存在连接,则标记中包含的位置也包含在网中。
插件源文件夹的org.processmining.plugins.connections包中提供了几个连接。
考虑以下行代码,取自TpnImport:

Connection c = new MarkedNetConnection(petrinet, new Marking(state));
  context.addConnection(c);

        在第一行中,一个连接被实例化。在这种情况下,MarkedNetConnection被实例化,它假设(但不验证)给定标记中包含的位置也包含在网络中。重要的是要认识到,连接应该尽可能标准化,也就是说,如果标记和网络被连接,它们应该使用MarkedNetConnection来存储这个连接。在第二行中,通过上下文将连接添加到框架中。显示的代码是

context.getConnectionManager().addConnection(context, c);


6.2 正在查找连接Finding connections

        除了注册连接之外,当然也可以向连接管理器查询现有的连接。有几种方法可用。
        getConnections方法返回指定对象之间的连接,这样连接的类型就可以从给定的connectionType中赋值。如果给定的类型等于null,则返回给定对象之间的所有连接。
        如果不存在正确类型的连接,那么连接管理器将搜索具有ConnectionObjectFactory注释的所有可用插件,该注释可以在给定PluginContext的子插件中执行,并接受给定对象作为输入。如果存在这样的插件,则会选择这些插件中的第一个,并对给定的对象进行调用。结果是从插件中获得的,并作为连接添加到框架中。然后返回此连接。有关ConnectionObjectFactory注释的更多信息,请参阅下一节。
要获得涉及某个对象的连接列表,只需在连接管理器中查询涉及该对象的所有连接,其中类型参数等于null。

6.3 连接工厂   Connection factory

@ConnectionFactory注释可以在插件上使用,以向框架发出此插件返回连接对象的信号。插件不必在框架中注册连接。相反,插件返回的单个对象必须是Connection is的实现,并且连接管理器将处理ProM中连接的注册。

7. Multi-threaded execution 

         为了方便多线程执行,ProM具有一些内置功能。每个PluginContext携带一个所谓的Executor,可通过getExecutor()方法访问。这个Executor是一个标准的java.util.concurrent.Executor。其想法是,插件可以将接口Runnable的实现提供给执行器,以便并发执行。有关更多信息,请参阅Executor的javadoc。

8.Plug-in management 

               有些插件需要执行其他插件。如果他们事先知道在哪些类中调用哪些方法,那么可以用标准的Java方法来完成。然而,ProM还提供了一个插件管理器,可以查询具有某些财产的插件。

9. Specific contexts

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;

public class HelloWorld8 {
        @Plugin(
                name = "My 5th Combine Worlds Plug-in", 
                parameterLabels = { "First string", "Number" }, 
                returnLabels = { "First string several second strings" }, 
                returnTypes = { String.class }, 
                userAccessible = true, 
                help = "Produces one string consisting of the first and a number of times a string given as input in a dialog."
        )
        @UITopiaVariant(
                affiliation = "My company", 
                author = "My name", 
                email = "My e-mail address"
        )
        public static Object helloWorlds(UIPluginContext context, String first, Integer number) {
                // Ask the user for his world
                String w = JOptionPane.showInputDialog(null, "What's the name of your world?",
                                "Enter your world", JOptionPane.QUESTION_MESSAGE);
                // change your result label
                context.getFutureResult(0).setLabel("Hello " + w + " string");
                // return the combined string
                return helloWorlds(context, first, number, w);
        }

        @Plugin(
                name = "My 4th Hello World Plug-in", 
                parameterLabels = {}, 
                returnLabels = { "Hello string", "Number", "Worlds string" }, 
                returnTypes = { String.class, Integer.class, String.class }, 
                userAccessible = true, 
                help = "Produces three objects: 'Hello', number, 'world'"
        )
        @UITopiaVariant(
                affiliation = "My company", 
                author = "My name", 
                email = "My e-mail address"
        )
        public static Object helloWorlds(PluginContext context, String first, Integer number, String second) {
                String s = first;
                for (int i = 0; i < number; i++) {
                        s += "," + second;
                }
                return s;
        }
}

 10.Plug-in life-cycle

        当ProM框架启动时,会自动创建一个主插件上下文。这个主插件上下文用于从派生新的上下文,以便执行插件。
        当插件由框架执行时,框架首先实例化一个PluginContext对象。该上下文的实现类型可以是例如GUI上下文或命令行上下文。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北冥有鱼zsp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值