ProM 6 Plug-in Development; Part 1: Basics

ProM 6 is one of the if not the most prominent research tool for process mining.  ProM has an extensible architecture which makes it easy to extend for third parties.  Alas the documentation for doing so is years out of date.  As I have a nagging suspicion I may have to supervise a lot of people on doing exactly this, I decided to write a short introduction to plug-in development in ProM.

Development Environment

Start by installing Java and a recent version of Eclipse.  Make sure you either install one of the (1, 2) Eclipse Subversion plug-ins or install one for your operating system.

Check out the GettingStarted ProM package from https://svn.win.tue.nl/repos/prom/Packages/GettingStarted/Trunk/.  We are going to do out development in this package.  When the package is ready for prime time, it is easy to move it to a separate package.  You can check out the package directly from Eclipse or using your operating system and subsequently import it in Eclipse.

Basic ProM Overview

The first thing to notice is that ProM is not an editor.  It is a model transformer and viewer.  At the basic level, we need to worry about three kinds of elements: objects, plug-ins, and visualizers.  For those familiar with the model-view-controller design pattern, objects constitute the model of the design pattern, and visualizers the views.  As ProM is not an editor, we have no controller.

ProM plug-ins have to live in a package.  ProM gets confused if they do not.  It is a good idea to use the package org.processmining.plugins.<name>, where <name> is an all-lowercase version of the name of your package.  Even if you do development in the GettingStarted package, it is a good idea to think about another name for you package, so you don’t have to move it later.  In the following, we shall use HelloWorld as package name, and hence org.processmining.plugins.helloworld as package name.

Objects

Objects are the basic data type in ProM.  They are used as regular objects and are created as just regular Java objects.

One very important feature is that ProM automatically serializes objects to disk, so they must support that.  ProM does not require that objects implement the Serializable interface, but there are a few things you should ensure.  The most important thing is that objects do not contain references to unserializable or run-time objects.  This means that your objects should not contain references to Threads or user interface objects.

Objects should never be changed once created.  They do not have to be strictly immutable, but it is not a bad idea to make them.  One way to do so is to make all mutator methods package visible only.

Note that objects should not use the standard Java Observable class as anything adding itself as an observer will be serialized along with the object.  This should also not be necessary as – as already mentioned – ProM is not an editor and objects should never be changed.

Other than that, there are no restrictions: simply make your objects as a standard object model using all the regular collection classes, though observe that the main object should be public and not use any generics parameters.

Here is an example of a simple object model:
[java] package org.processmining.plugins.helloworld;

public class Person {
private Name name;
private int age

public Person() {
age = 0;
}

public Name getName() {
return name;
}

setName(Name name) {
this.name = name;
}

public int getAge() {
return age;
}

setAge(int age) {
this.age = age;
}
}

class Name {
private String first, last;

public Name(String first, String last) {
this.first = first;
this.last = last;
}

public String getFirst() {
return first;
}

public String getLast() {
return last;
}
}
[/java]

Plug-ins

Plug-ins are the basic mechanism of ProM.  The main idea of a plug-in is that it transforms one object into another.  Note that the original objects should never be changed and the newly created objects should not be altered once a plug-in terminates.

Plug-ins are basically just methods.  You can create plug-ins in many ways, but here I only describe one, which is my preferred way.  Basically, a plug-in has a number of parameters (input objects) and a configuration.  The configuration describes how exactly a plug-in should operate.  A plug-in just exposes a method for ProM to call.  The method needs to be annotated using an Java annotation.

Here is a very simple plug-in allowing two persons to have a child:
[java] package org.processmining.plugins.helloworld;

import org.processmining.framework.plugin.annotations.*;
import org.processmining.framework.plugin.*;
import org.processmining.contexts.uitopia.*;
import org.processmining.contexts.uitopia.annotations.*;

@Plugin(name = “Procreate”,
parameterLabels = { “Father”, “Mother”, “Procreation Configuration” },
returnLabels = { “Child” },
returnTypes = { Person.class })
public class ProcreatePlugin {
@UITopiaVariant(affiliation = “University of Life”,
author = “Britney J. Spears”,
email = “britney@westergaard.eu”,
uiLabel = UITopiaVariant.USEPLUGIN)
@PluginVariant(requiredParameterLabels = { 0, 1, 2 })
public static Person procreate(final PluginContext context,
final Person father,
final Person mother,
final ProcreationConfiguration config) {
Person child = new Person();
child.setAge(0);
child.setName(new Name(config.getName(), father.getLast()));
return child;
}

@UITopiaVariant(affiliation = “University of Life”,
author = “Britney J. Spears”,
email = “britney@westergaard.eu”,
uiLabel = UITopiaVariant.USEPLUGIN)
@PluginVariant(requiredParameterLabels = { 0, 1 })
public static Person procreate(final UIPluginContext context,
final Person father,
final Person mother) {
ProcreationConfiguration config = new ProcreationConfiguration();
populate(context, config);
return procreate(context, father, mother, config);
}
}

public class ProcreationConfiguration {
String name;

public ProcreationConfiguration(String name) {
this.name = name;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
[/java] The configuration is encapsulated as a separate object (ll. 40-54).  Here is may seem like overkill as we have just one setting, but in general in objects with many settings, creating such an object is a major relief, especially if parameters have default settings and we only need to customize a subset.

The main idea of the plug-in is to expose two variants: one does the actual work and one populates the configurations.  The variant doing the actual work (ll. 11-24 in the example), takes all parameters and the configuration and the other (ll. 26-37) takes all parameters except the configuration.  The innards of the methods should be fairly self-explanatory; we assume the existence of a populate method for populating the configuration according to user wishes.  Here, we have implemented the logic directly in the plug-in methods, but it is often better to specify that in a separate class to decouple it completely from the ProM user-interface code.

The interesting part is the annotations.  In this example, we use three different annotations, Plugin, PluginVariant, and UITopiaVariant.  They specify that a class is a plug-in, that a method is a variant of said plug-in, and that a plug-in should be exposed in the user interface, respectively.

The Plugin annotation of the class (ll. 6-9), specifies the name of the plug-in (l. 6), the names of all parameters (l. 7), and the names of all return types (l. 8).  It also specifies the types of the return types (l. 9).  Here, this may seem superfluous, but if a plug-in returns multiple parameters, they should be returned in an Object array, which does not exhibit this information.  This annotation is placed on the class representing the plug-in.

A PluginVariant annotation is applied to a method.  We use static methods here, and that is a good idea to avoid accidentally storing state information in the plug-in class.  We have two instances in our example (ll. 15 and 30).  This annotation specifies which of the parameters are actually used by the variant.  This is list of indexes in the list of parameter names from the Plugin annotation.  The indexes start at zero.  In line 15 we specify that we require all parameters, and in line 30 we specify that we only need the Father and Mother parameters.

Each implementation should take parameters corresponding to the parameter list specified in the PluginVariant annotation and an additional context parameter.  We get to the details of the context parameter later, but for now just make sure that the context parameter to the variant taking a configuration is a PluginContext and the context parameter to the variant not taking a configuration is a UIPluginContext.  The types of parameters should be objects in ProM.  In the example, we only use our type Person and our configuration class.

The UITopiaVariant specifies extra information exposed in the ProM user interface, including name, affiliation and e-mail address of the author (e.g., ll. 11-13).  It also specifies a label used to display the plug-in in the user interface.  In this case (l. 14), we just specify that the plug-in name should be used.  This is typically fine.  In our example, we have exposed both the variant taking a configuration and the one which does not.  We always need to expose the latter, but do not necessarily need to specify the variant taking a configuration, though that can be useful for executing the plug-in several times with the same configuration but different parameters, as we shall see later.

Visualizers

Visualizers are just a special kind of plug-in.  They always return a single parameter of type JComponent, and have an additional Visualizer annotation.  A simple visualizer for Person objects can be seen below.  It should be fairly self-explanatory by now:
[java] package org.processmining.plugins.helloworld;

import org.processmining.framework.plugin.*;
import org.processmining.framework.plugin.annotations.*;
import org.processmining.contexts.uitopia.annotations.*;

@Plugin(name = “Show Person”,
parameterLabels = { “Person” },
returnLabels = { “Person Viewer” },
returnTypes = { JComponent.class },
userAccessible = false)
@Visualizer
public class PersonVisualizer {
@PluginVariant(requiredParameterLabels = { 0 })
public static JComponent visualize(final PluginContext context,
final Person person) {
return new JLabel(person.getFirst() + ” ” + person.getLast());
}
[/java] We notice that we set the optional parameter userAccessible of the Plugin annotation to false (l. 11) to make sure users cannot execute this plug-in (as the JComponent returned object violates several rules for ProM objects). We also add the Visualizer annotation to the plug-in class (l. 12) and do not expose the plug-in in the GUI.

Here, we just return a passive JComponent object, but it is perfectly ok for a visualizer to include active elements including event handlers. Visualizers can present different views of the same object (e.g., zooming in or making various projections) and are allowed to contain a reference to the original object. Visualizers should not, however, ever change the provided object. Visualizers are allowed to create new objects based on the input.

Again, we have made the visualizer static as a single visualizer may display multiple objects, and may even be instantiated multiple times for the same object. As mentioned before, visualizers should not add themselves as observers of the objects they display. ProM is not an editor and doing so will yield errors, as visualizers cannot be serialized.

Conclusion

This concludes part 1 of my ProM 6 plug-in development tutorial.  In the next part, we shall look at more advanced topics, including loading and saving objects, populating settings objects using the user-interface, and integrating with the ProM user-interface using the PluginContext.

43 thoughts on “ProM 6 Plug-in Development; Part 1: Basics

  1. Michael Westergaard,

    Enjoyed the tutorial, if you could send me links to other related issues I would be very grateful.

  2. This article helped me a lot to understand basic concepts. Please continue writing on ProM Plug-in Development process.
    Thank you.

    1. Glad you found it useful 🙂 As the name suggests, this just part 1. If you select Tutorials at the top menu, you can find the entire series under ProM Tutorial.

      1. Yes sir, I have went through different issues of this series.
        In the tutorial 4 of prom development series, you have discussed about writing a code about “automatically testing plugins”.

        As the plugin development resources for prom are hardly available on internet, please write focussing on almost every elements of plugin development sir. It will definitely help many people like me.

        Please write and share the info sir.

        Thank you.

        1. I’m glad you find it useful – your line of reasoning is exactly why I started the introductory series.

          In addition to that series, I’ve also written a large number of much less structured posts on ProM, mostly about things that amused me or gave me problems doing development on ProM. Everything related to ProM can be found here: https://westergaard.eu/tag/prom/

  3. Hi,

    Can you please further explain wht is the role of Visualizers? I didn’t understand the concept clearly.

    Where the JComponent returned from the visualiser can be used.

    Thank you.

    1. Visualizers are the V of the MVC or model-view-controller design pattern. They are intended to show model objects. They are called automatically by ProM either when a user clicks on the eye button to view an object in the workspace or automatically after running a plug-in producing an object. For example, when you load a log, you get a view with all kinds of statistics about that log (# traces, lengths of traces etc). This is produced by a visualizer. It is possible to have multiple visualizers for each model object, and users can then view the object in different ways.

  4. Hi,

    I have checked-out the project “GettingStarted ProM package” and started working and learnt lot of stuff. But my question is, if I want to create new plugin, Shall I modify the existing “GettingStarted ProM package” which I have downloaded or shall I have to create everything from scratch.

    If I have to create everything from scratch, how do I need to start?

    Thank you
    -Manoj

    1. Definitely use the getting started package as a starting point, but i suggest copying everything to a new project before you start (it is a much bigger hassle afterwards), even though I don’t do that in this intro for simplicity. Just start by using SVN relocate to nice it to another repisitory location, rename the project, change the plugin.xml, and move classes to a suitable package to get started .

      1. Where is this plugin.xml file is located? I have searched for this file but I didn’t get any file by this name.

        Thank you.

  5. Hi! I’m Nufaisa. I’ve read your article about adding plug-in to ProM 6. And I want to adding plug-in on ProM to complete my final task (TA). I’ve download ProM 6, but ProM 6 can’t opened like Prom 5.2. So, that’s matter or not if I follow your step to adding plug-in but for ProM 5.2? I hope you can answered my question. Thank you!

    1. Hi,

      ProM 6 and ProM 5.2 are completely different and not compatible at all. The easier way to test your plug-in is to use the template from Subversion in the tutorial and just run the package manager launcher + ProM from within Eclipse. That will start ProM with your new plug-in included.

  6. Hi, I’m trying to creat a plug-in to add it to ProM 6. So I started by checking out the GettingStrated package. I tried to run it using ProM from eclipse. ProM started without the plugin on it, and i’ve got this error message : “Exception in thread “main” java.lang.Exception: Cannot find release package defined in ProM.ini file: AllPackages. Continuing to load ProM. at org.processmining.contexts.uitopia.UI.main(UI.java:62)”
    Can you please help. Thank you.

    1. You don’t process files directly in ProM 6. Instead create a plug-in that takes an XLog as input; users can then import logs using their favorite means and use your plug-in afterwards.

      1. okey now i import the mxml file with import then i go to my plug but then when i clic on the input to select the mxml file that i import earlier the file doesn’t show up. what should i add in the method
        public static String helloWorld(PluginContext context,File Xlog){}

        1. The log is no longer a file but and object of type XLog, so you’d need a signature like public static String helloWorld(PluginContext context, XLog log) {}

          1. well when i did this public static String helloWorld(PluginContext context, XLog log) it worked thank you for guiding me

      2. Just one more question if i may, can i import an ontology file with OWL extension to prom and can i have it as an input

        1. Jan-Martijn made a plug-in for doing things with ontologies. I think it can import in OWL. If not, it should be fairly easy to make an importer by embedding a standard library for parsing and representing ontologies. After that, using them in your plug-ins should be easy.

          1. Yes i’m using ProtegeOWL API, i just wanted to have the file as an input.
            Thank you so much for your answers

    1. You can just return an XLog object; it can then be exported by ProM to either XES or MXML. It is a bit (a lot) cumbersome to create XLog objects, but there is a factory you can use for it.

      1. I tried this returnTypes = { Object.class }, and to return the MXML FILE as output this public static Object helloWorld(PluginContext context,XLog log)
        {
        return log;
        }
        i just enter the MXML file as input and have it as output i’m just testing
        I really appreciate it if you could guide me more i’m really interested in this field thank you so much

        1. In your example, the declared type of the result is Object, which is not XLog. This means ProM concludes it knows nothing of the type of the object. You should declare the type to be XLog (both in returnTypes and as the actual return type of the method, though the first is more important) and all will work.

          1. But when i tried returnTypes = {XLog.class }, i have a compilation error is there any import that i should add and in the suggestin box i have create interface XLog,create Class Xlog, Create enum XLog.

            in the reurn type of the metode i tried this
            public static XLog helloWorld(PluginContext context,XLog log)

            And i don’t have compilation error.

  7. Hello,
    thank you for your excellent tutorial! It is very useful, as there is not much documentation on ProM plugin development out there. I was going through it and understood everything! I really appreciate your work.

    I have a question though. I am planning on developing an extension for an existing package (ProcessTree). I already have the sources and made simple changes, but I can’t manage to compile it and execute it with UITopia. What can I do? Does this have anything to do with plugin development in the first place?

  8. Hello sir, please i want to know how should i do to choose a good repository for my subversion version.

  9. Hello,
    if I start with checking out the package, does the location matters? Do I have to install ProM first? My problem is, that the imports aren’t working. or.processmining.context cannot be reasolved. I am running eclipse with an up to date JDK, but where do i get the jar files from?

  10. Hello,
    Does it matter, where i check out the gettingstarted repository? Do I have to install ProM first or is the repository doing this?
    My Problem is, that after checking out, i got lots of errors, telling me that the imports cannot be resolved (org.processmining.context for example). My Eclipse runs with an up to date JDK, but it seems that these jar files are comming from somewhere else. What do I have to do that the imports work and the jars are in the library?

    1. Hey,

      It shouldn’t matter where you check it out, but as a precaution, I would avoid locations with spaces/non-ASCII characters if possible.

      The repository should pull in everything using externals so you should not have to install ProM yourself, but might benefit from running the package manager from the repository once before starting ProM itself.

      Depending on what you mean by an up-to-date JDK, consider downgrading; most Java applications do not play nicely with Java 9/10/18.9, so staying on Java 8 might be better.

      That said, this post is a couple of years, and the procedure may have changed subtly. I have not really kept up-to-date with ProM lately, so if the ProM documentation contradicts this post, the documentation is probably right.

  11. There are several errors.

    1.)

    public class Name {

    As it is public, it has to be in a separate java file.

    2.)

    setName(Name name) {
    setAge(int age) {

    The return type has to be void.

    3.)

    ProcreationConfiguration config = new ProcreationConfiguration();

    This is not possible as the constructor demands a name.

    4.)

    person.getFirst()
    person.getLast()
    father.getLast()

    You mean
    person.getName().getFirst()
    person.getName().getLast()
    father.getName().getLast()

    5.)

    You have to import JComponent and JLabel.

    import javax.swing.JComponent;
    import javax.swing.JLabel;

  12. Hi Michael

    Thank you for the tutorial. I’m new to ProM and it helped me a lot.
    I am going to write a plugin in which Inductive miner has to be invoked.
    More precisely, in the user interface the Inductive Miner has to be called for the input log and user must be able to choose some of the transitions in the resulting petrinet. Then some analysis are done on the log based on the chosen parts of the petrinet.
    I think it is hard to explain me who to do that.
    Is there any source that I can use to find out
    -how to invoke one plugin from another one,
    -how to specify which parts (for example arcs or places) of the resulting petrinet is chosen
    by the user?

    1. Hi Mahnaz,

      The ProM framework supports looking up other plugins if you want to make the connection declarative. You can also directly depend on the other plugin and hope the author has written it in a way so you can just invoke a Java method to get the effect of applying the plugin (my tutorials propose coding in this way).

      But all in all, this is all very ProM internal and unless it is very important, I would propose just having the user invoke the plugins by hand; it also allows them the freedom to select another algorithm accomplishing the same in a different way down the line.

      Regards,
      Michael

  13. Sorry to bother you, but can you show me about the development environment of project Getstarted?Like Java versions, etc.

    1. The post is over 6 years old; I don’t remember exactly what I used then, but it would most likely not be relevant today. I no longer actively develop ProM, so I can unfortunately not help you there. Maybe promtools.org has more information?

  14. Hi, please i tried using the getting started package but i can’t find this class that was imported in the Yourplugin.java: “import org.processmining.framework.plugin.*;”

    Essentially, I can’t find the framework classes. Can you tell me what to do please?

    1. Hi, I’m sorry, but I can unfortunately not help you there. This tutorial was written 8 years ago, and I am no longer involved in ProM development, so it is possible that things have changed since then. Maybe Erik or somebody else from the ProM team knows what is up?

Leave a Reply to Manoj Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.