├── .classpath ├── .github └── workflows │ └── ant.yml ├── .project ├── ProM.ini ├── build.xml ├── ivy.xml ├── ivysettings.xml ├── latestrelease ├── ProM-Framework-6.14.45-all.zip ├── ProM-Framework.jar ├── ProM.ini ├── ivy.xml ├── lib │ ├── TableLayout-20050920.jar │ ├── commons-compress-1.13.jar │ ├── commons-logging-1.1.3.jar │ ├── images │ │ └── logo_branding.png │ ├── jargs-latest.jar │ ├── jgraph-5.13.0.4.jar │ └── slickerbox-1.0rc1.jar └── packages.xml ├── lib └── images │ └── logo_branding.png ├── src └── org │ └── processmining │ └── framework │ ├── ProMID.java │ ├── abstractplugins │ ├── AbstractImportPlugin.java │ └── ImportPlugin.java │ ├── annotations │ ├── AuthoredType.java │ ├── Icon.java │ └── TestMethod.java │ ├── boot │ ├── AddJarsForPackageRunnable.java │ ├── Boot.java │ └── PathHackerRunnable.java │ ├── connections │ ├── Connection.java │ ├── ConnectionAnnotation.java │ ├── ConnectionCannotBeObtained.java │ ├── ConnectionID.java │ ├── ConnectionManager.java │ ├── DynamicConnection.java │ ├── annotations │ │ ├── ConnectionDoesntExistMessage.java │ │ └── ConnectionObjectFactory.java │ └── impl │ │ ├── AbstractConnection.java │ │ ├── AbstractStrongReferencingConnection.java │ │ ├── ConnectionIDImpl.java │ │ └── ConnectionManagerImpl.java │ ├── packages │ ├── CommandLineInterface.java │ ├── PackageDescriptor.java │ ├── PackageManager.java │ ├── PackageSet.java │ ├── PackageStateReport.java │ ├── PackageVersion.java │ ├── Repository.java │ ├── UnknownPackageException.java │ ├── UnknownPackageTypeException.java │ ├── events │ │ └── PackageManagerListener.java │ └── impl │ │ ├── CancelledException.java │ │ └── PackageConfigPerister.java │ ├── plugin │ ├── GlobalContext.java │ ├── InSufficientResultException.java │ ├── IncorrectReturnTypeException.java │ ├── ObjectConstructor.java │ ├── PluginContext.java │ ├── PluginContextID.java │ ├── PluginDescriptor.java │ ├── PluginDescriptorID.java │ ├── PluginExecutionResult.java │ ├── PluginManager.java │ ├── PluginParameterBinding.java │ ├── ProMCanceller.java │ ├── ProMFuture.java │ ├── Progress.java │ ├── RecursiveCallException.java │ ├── annotations │ │ ├── Bootable.java │ │ ├── CLI.java │ │ ├── KeepInProMCache.java │ │ ├── Plugin.java │ │ ├── PluginCategory.java │ │ ├── PluginLevel.java │ │ ├── PluginQuality.java │ │ └── PluginVariant.java │ ├── events │ │ ├── ConnectionObjectListener.java │ │ ├── FutureListener.java │ │ ├── Logger.java │ │ ├── NameChangeListener.java │ │ ├── PluginLifeCycleEventListener.java │ │ ├── ProMEventListenerList.java │ │ ├── ProgressEventListener.java │ │ └── ProvidedObjectLifeCycleListener.java │ └── impl │ │ ├── AbstractGlobalContext.java │ │ ├── AbstractPluginContext.java │ │ ├── AbstractPluginDescriptor.java │ │ ├── DependsOnUnknownException.java │ │ ├── FieldNotSetException.java │ │ ├── FieldSetException.java │ │ ├── PluginCacheEntry.java │ │ ├── PluginContextIDImpl.java │ │ ├── PluginDescriptorIDImpl.java │ │ ├── PluginDescriptorImpl.java │ │ ├── PluginExecutionResultImpl.java │ │ ├── PluginManagerImpl.java │ │ └── ProgressBarImpl.java │ ├── providedobjects │ ├── ContextAwareObject.java │ ├── ProvidedObject.java │ ├── ProvidedObjectDeletedException.java │ ├── ProvidedObjectID.java │ ├── ProvidedObjectManager.java │ ├── SubstitutionType.java │ └── impl │ │ ├── ProvidedObjectIDImpl.java │ │ ├── ProvidedObjectImpl.java │ │ └── ProvidedObjectManagerImpl.java │ └── util │ ├── ArrayUtils.java │ ├── AutoHelpCommandLineParser.java │ ├── Cast.java │ ├── Cleanable.java │ ├── CommandLineArgumentList.java │ ├── HTMLToString.java │ ├── IconLoader.java │ ├── LevenshteinDistance.java │ ├── OsUtil.java │ ├── Pair.java │ ├── PathHacker.java │ ├── ProMClassLoader.java │ ├── StringUtils.java │ ├── WeakValueHashMap.java │ ├── collection │ ├── AbstractMultiSet.java │ ├── AlphanumComparator.java │ ├── ComparablePair.java │ ├── HashMultiSet.java │ ├── LinkedHashMultiSet.java │ ├── MultiSet.java │ ├── SortedMultiSet.java │ ├── TreeMultiSet.java │ └── WeakKeyValueMap.java │ ├── progress │ ├── XMonitoredInputStream.java │ ├── XProgressBarListener.java │ └── XProgressListener.java │ ├── search │ ├── BreadthFirstExpandCollection.java │ ├── DepthFirstExpandCollection.java │ ├── ExpandCollection.java │ ├── MultiThreadedSearcher.java │ └── NodeExpander.java │ ├── socket │ ├── Service.java │ ├── ServiceEnvironment.java │ └── ServiceHandler.java │ └── ui │ ├── ExpandButton.java │ ├── SlickerConsole.java │ ├── SlickerMessageBar.java │ └── TypeToggleButton.java └── tests ├── build.xml ├── src-test └── org │ └── processmining │ └── tests │ └── framework │ └── FrameworkUtilCollectionsTest.java └── test.properties /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.github/workflows/ant.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Ant 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-ant 3 | 4 | name: Java CI 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | workflow_dispatch: 12 | 13 | jobs: 14 | build: 15 | 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v3 20 | with: 21 | fetch-depth: 0 22 | - name: Set up JDK 11 23 | uses: actions/setup-java@v3 24 | with: 25 | java-version: '11' 26 | distribution: 'temurin' 27 | - name: Build with Ant 28 | run: ant -noinput -buildfile build.xml buildHudson 29 | env: 30 | bytecode_format: ${{ vars.BYTECODE_FORMAT }} 31 | major_minor: ${{ vars.MAJOR_MINOR }} 32 | - name: Upload build result 33 | uses: actions/upload-artifact@v3 34 | with: 35 | name: release 36 | path: latestrelease/ 37 | - name: Commit files 38 | run: | 39 | git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" 40 | git config --local user.name "github-actions[bot]" 41 | git add latestrelease/ 42 | git commit -m "Add changes" 43 | - name: Push changes 44 | uses: ad-m/github-push-action@master 45 | with: 46 | branch: ${{ github.ref }} 47 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | ProM-Framework 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | org.apache.ivyde.eclipse.ivynature 17 | 18 | 19 | -------------------------------------------------------------------------------- /ProM.ini: -------------------------------------------------------------------------------- 1 | # This file contains information about this ProM release 2 | # it points ProM to the right packages and keeps version 3 | # information 4 | # 5 | # Folders should be separated using "/" (forward slash). 6 | # This will be replaced with File.Separator(). 7 | # 8 | # Specifies the ProM release version 9 | PROM_VERSION = NightlyBuild 10 | # 11 | # Specifies which package should be installed 12 | RELEASE_PACKAGE = RunnerUpPackages 13 | # 14 | # Specifies the URL to the default package repository 15 | # (default is "http://www.promtools.org/prom6/packages/packages.xml") 16 | PACKAGE_URL = http://www.promtools.org/prom6/packages/packages.xml 17 | # 18 | # Specifies whether ProM is Verbose 19 | # (possible: "ALL" / "ERROR" / "NONE", defaults to "ALL") 20 | VERBOSE = ALL 21 | # 22 | # The library folder is relative to the prom installation 23 | # folder (default is "lib") 24 | LIB_FOLDER = lib 25 | # 26 | # The images folder is relative to the prom library 27 | # folder (default is "=images") 28 | IMAGES_FOLDER = images 29 | # 30 | # The macro folder is relative to the prom library 31 | # folder (default is "macros") 32 | MACRO_FOLDER = macros 33 | # 34 | # The prom user folder is NOT relative to the 35 | # prom installation folder. The (default is empty, in 36 | # which case the OS handles the location) 37 | PROM_USER_FOLDER = . 38 | # 39 | # The package folder is relative to the 40 | # prom user folder. The (default is "packages") 41 | PACKAGE_FOLDER = packages 42 | # 43 | # The workspace folder is relative to the 44 | # prom user folder. The (default is "workspace") 45 | WORKSPACE_FOLDER = workspace 46 | # 47 | # Indicate whether or not ProM should serialize the 48 | # workspace. If switched off, the last serialized 49 | # workspace will be loaded on each start 50 | DO_SERIALIZATION = false 51 | # 52 | # Whether ProM should check the URL of a package archive. 53 | # If true, then the package will be ignored if the archive 54 | # cannot be opened. If false, the package will not be ignored. 55 | CHECK_PACKAGES = true 56 | # 57 | # Whether ProM should hide old version of a package. 58 | # If true, only the most recent version of the package will be 59 | # shown as being available. If false, all versions will be 60 | # shown. 61 | HIDE_OLD_PACKAGES = true 62 | 63 | PLUGIN_LEVEL_THRESHOLD = NightlyBuild 64 | 65 | # 66 | # Timeouts used when trying to get a file from the repository. 67 | # Setting a timeout to 0 means no timeout wil be set. 68 | CONNECT_TIMEOUT = 0 69 | READ_TIMEOUT = 0 -------------------------------------------------------------------------------- /ivy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Version VERSION 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /ivysettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /latestrelease/ProM-Framework-6.14.45-all.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/promworkbench/ProM-Framework/cb5c064b5e212e36363fb064cfa0f04cb85c23f8/latestrelease/ProM-Framework-6.14.45-all.zip -------------------------------------------------------------------------------- /latestrelease/ProM-Framework.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/promworkbench/ProM-Framework/cb5c064b5e212e36363fb064cfa0f04cb85c23f8/latestrelease/ProM-Framework.jar -------------------------------------------------------------------------------- /latestrelease/ProM.ini: -------------------------------------------------------------------------------- 1 | # This file contains information about this ProM release 2 | # it points ProM to the right packages and keeps version 3 | # information 4 | # 5 | # Folders should be separated using "/" (forward slash). 6 | # This will be replaced with File.Separator(). 7 | # 8 | # Specifies the ProM release version 9 | PROM_VERSION = NightlyBuild 10 | # 11 | # Specifies which package should be installed 12 | RELEASE_PACKAGE = RunnerUpPackages 13 | # 14 | # Specifies the URL to the default package repository 15 | # (default is "http://www.promtools.org/prom6/packages/packages.xml") 16 | PACKAGE_URL = http://www.promtools.org/prom6/packages/packages.xml 17 | # 18 | # Specifies whether ProM is Verbose 19 | # (possible: "ALL" / "ERROR" / "NONE", defaults to "ALL") 20 | VERBOSE = ALL 21 | # 22 | # The library folder is relative to the prom installation 23 | # folder (default is "lib") 24 | LIB_FOLDER = lib 25 | # 26 | # The images folder is relative to the prom library 27 | # folder (default is "=images") 28 | IMAGES_FOLDER = images 29 | # 30 | # The macro folder is relative to the prom library 31 | # folder (default is "macros") 32 | MACRO_FOLDER = macros 33 | # 34 | # The prom user folder is NOT relative to the 35 | # prom installation folder. The (default is empty, in 36 | # which case the OS handles the location) 37 | PROM_USER_FOLDER = . 38 | # 39 | # The package folder is relative to the 40 | # prom user folder. The (default is "packages") 41 | PACKAGE_FOLDER = packages 42 | # 43 | # The workspace folder is relative to the 44 | # prom user folder. The (default is "workspace") 45 | WORKSPACE_FOLDER = workspace 46 | # 47 | # Indicate whether or not ProM should serialize the 48 | # workspace. If switched off, the last serialized 49 | # workspace will be loaded on each start 50 | DO_SERIALIZATION = false 51 | # 52 | # Whether ProM should check the URL of a package archive. 53 | # If true, then the package will be ignored if the archive 54 | # cannot be opened. If false, the package will not be ignored. 55 | CHECK_PACKAGES = true 56 | # 57 | # Whether ProM should hide old version of a package. 58 | # If true, only the most recent version of the package will be 59 | # shown as being available. If false, all versions will be 60 | # shown. 61 | HIDE_OLD_PACKAGES = true 62 | 63 | PLUGIN_LEVEL_THRESHOLD = NightlyBuild 64 | 65 | # 66 | # Timeouts used when trying to get a file from the repository. 67 | # Setting a timeout to 0 means no timeout wil be set. 68 | CONNECT_TIMEOUT = 0 69 | READ_TIMEOUT = 0 -------------------------------------------------------------------------------- /latestrelease/ivy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Version 6.14.45 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /latestrelease/lib/TableLayout-20050920.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/promworkbench/ProM-Framework/cb5c064b5e212e36363fb064cfa0f04cb85c23f8/latestrelease/lib/TableLayout-20050920.jar -------------------------------------------------------------------------------- /latestrelease/lib/commons-compress-1.13.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/promworkbench/ProM-Framework/cb5c064b5e212e36363fb064cfa0f04cb85c23f8/latestrelease/lib/commons-compress-1.13.jar -------------------------------------------------------------------------------- /latestrelease/lib/commons-logging-1.1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/promworkbench/ProM-Framework/cb5c064b5e212e36363fb064cfa0f04cb85c23f8/latestrelease/lib/commons-logging-1.1.3.jar -------------------------------------------------------------------------------- /latestrelease/lib/images/logo_branding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/promworkbench/ProM-Framework/cb5c064b5e212e36363fb064cfa0f04cb85c23f8/latestrelease/lib/images/logo_branding.png -------------------------------------------------------------------------------- /latestrelease/lib/jargs-latest.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/promworkbench/ProM-Framework/cb5c064b5e212e36363fb064cfa0f04cb85c23f8/latestrelease/lib/jargs-latest.jar -------------------------------------------------------------------------------- /latestrelease/lib/jgraph-5.13.0.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/promworkbench/ProM-Framework/cb5c064b5e212e36363fb064cfa0f04cb85c23f8/latestrelease/lib/jgraph-5.13.0.4.jar -------------------------------------------------------------------------------- /latestrelease/lib/slickerbox-1.0rc1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/promworkbench/ProM-Framework/cb5c064b5e212e36363fb064cfa0f04cb85c23f8/latestrelease/lib/slickerbox-1.0rc1.jar -------------------------------------------------------------------------------- /latestrelease/packages.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /lib/images/logo_branding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/promworkbench/ProM-Framework/cb5c064b5e212e36363fb064cfa0f04cb85c23f8/lib/images/logo_branding.png -------------------------------------------------------------------------------- /src/org/processmining/framework/ProMID.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework; 2 | 3 | import java.util.UUID; 4 | 5 | public interface ProMID extends Comparable { 6 | 7 | /** 8 | * ProMID are used in Collections, so this method has to be implemented in 9 | * all its subclasses. 10 | * 11 | * @return 12 | */ 13 | public boolean equals(Object o); 14 | 15 | /** 16 | * ProMID are used in HashMaps, so this method has to be implemented in all 17 | * its subclasses. 18 | * 19 | * @return 20 | */ 21 | public int hashCode(); 22 | 23 | /** 24 | * Determines equality between this ProMID and any given object. Basically 25 | * checks for equality using the toString() methods of both objects. 26 | * 27 | * @param o 28 | * the object to compare the string representation with 29 | * @return true if the toString() of this provided object ID equals the 30 | * toString() of the given object parameter. 31 | */ 32 | public boolean equalsIgnoreType(Object o); 33 | 34 | /** 35 | * Returns a UUID that is used for this object. 36 | * 37 | * @return 38 | */ 39 | public UUID getUUID(); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/org/processmining/framework/abstractplugins/AbstractImportPlugin.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.abstractplugins; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.InputStream; 7 | import java.net.URI; 8 | import java.net.URL; 9 | 10 | import javax.swing.filechooser.FileFilter; 11 | 12 | import org.processmining.framework.plugin.PluginContext; 13 | import org.processmining.framework.plugin.annotations.PluginVariant; 14 | 15 | /** 16 | * Note that implementing classes of this baseclass should carry the 17 | * UIImportPlugin annotation 18 | * 19 | * Subclasses of AbstractImportPlugin should use the @Plugin Annotation as 20 | * follows: 21 | * 22 | * @Plugin( name = "{any name}", parameterLabels={"Filename"}, returnLabels = { 23 | * {The right return labels} }, returnTypes = { {The right return 24 | * classes} }) 25 | * 26 | * 27 | * @author bfvdonge 28 | * 29 | */ 30 | public abstract class AbstractImportPlugin implements ImportPlugin { 31 | 32 | private File file = null; 33 | 34 | /* 35 | * (non-Javadoc) 36 | * 37 | * @see org.processmining.plugins.abstractplugins.ImportPlugin#getFile() 38 | */ 39 | public File getFile() { 40 | return file; 41 | } 42 | 43 | /* 44 | * (non-Javadoc) 45 | * 46 | * @see 47 | * org.processmining.plugins.abstractplugins.ImportPlugin#importFile(org 48 | * .processmining.framework.plugin.PluginContext, java.lang.String) 49 | */ 50 | @PluginVariant(requiredParameterLabels = { 0 }) 51 | public Object importFile(PluginContext context, String filename) throws Exception { 52 | file = new File(filename); 53 | return importFromStream(context, new FileInputStream(file), filename, file.length()); 54 | } 55 | 56 | /* 57 | * (non-Javadoc) 58 | * 59 | * @see 60 | * org.processmining.plugins.abstractplugins.ImportPlugin#importFile(org 61 | * .processmining.framework.plugin.PluginContext, java.net.URI) 62 | */ 63 | @PluginVariant(requiredParameterLabels = { 0 }) 64 | public Object importFile(PluginContext context, URI uri) throws Exception { 65 | return importFromStream(context, uri.toURL().openStream(), uri.toString(), 0); 66 | } 67 | 68 | /* 69 | * (non-Javadoc) 70 | * 71 | * @see 72 | * org.processmining.plugins.abstractplugins.ImportPlugin#importFile(org 73 | * .processmining.framework.plugin.PluginContext, java.net.URL) 74 | */ 75 | @PluginVariant(requiredParameterLabels = { 0 }) 76 | public Object importFile(PluginContext context, URL url) throws Exception { 77 | file = new File(url.toURI()); 78 | return importFromStream(context, url.openStream(), url.toString(), 0); 79 | } 80 | 81 | /* 82 | * (non-Javadoc) 83 | * 84 | * @see 85 | * org.processmining.plugins.abstractplugins.ImportPlugin#importFile(org 86 | * .processmining.framework.plugin.PluginContext, java.io.File) 87 | */ 88 | @PluginVariant(requiredParameterLabels = { 0 }) 89 | public Object importFile(PluginContext context, File f) throws Exception { 90 | file = f; 91 | InputStream stream = getInputStream(f); 92 | return importFromStream(context, stream, file.getName(), file.length()); 93 | } 94 | 95 | /** 96 | * This method returns an inputStream for a file. Note that the default 97 | * implementation returns "new FileInputStream(file);" 98 | * 99 | * @param file 100 | * @return 101 | * @throws FileNotFoundException 102 | */ 103 | protected InputStream getInputStream(File file) throws Exception { 104 | return new FileInputStream(file); 105 | } 106 | 107 | /** 108 | * This method is called by all plugin variants to do the actual importing. 109 | * 110 | * @param context 111 | * @param input 112 | * @param filename 113 | * @param fileSizeInBytes 114 | * @return 115 | * @throws Exception 116 | */ 117 | protected abstract Object importFromStream(PluginContext context, InputStream input, String filename, 118 | long fileSizeInBytes) throws Exception; 119 | 120 | } 121 | 122 | class ZipFilter extends FileFilter { 123 | 124 | private final FileFilter parent; 125 | 126 | public ZipFilter(FileFilter parent) { 127 | this.parent = parent; 128 | } 129 | 130 | public boolean accept(File f) { 131 | return (f.getAbsolutePath().endsWith(".zip") || parent.accept(f)); 132 | } 133 | 134 | public String getDescription() { 135 | return parent.getDescription(); 136 | } 137 | 138 | } -------------------------------------------------------------------------------- /src/org/processmining/framework/abstractplugins/ImportPlugin.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.abstractplugins; 2 | 3 | import java.io.File; 4 | import java.net.URI; 5 | import java.net.URL; 6 | 7 | import org.processmining.framework.plugin.PluginContext; 8 | import org.processmining.framework.plugin.annotations.PluginVariant; 9 | 10 | /** 11 | * This interface should be implemented by plugins that serve as input plugins. 12 | * 13 | * Such a plugin should have the @Plugin annotation on the class level and does 14 | * not have to define any variants, as these are defined in the interface. 15 | * 16 | * @author bfvdonge 17 | * 18 | */ 19 | 20 | public interface ImportPlugin { 21 | 22 | /** 23 | * Returns the File object this plugin was instantiated with. 24 | * 25 | * @return 26 | */ 27 | public File getFile(); 28 | 29 | @PluginVariant(requiredParameterLabels = { 0 }) 30 | public Object importFile(PluginContext context, String filename) throws Exception; 31 | 32 | @PluginVariant(requiredParameterLabels = { 0 }) 33 | public Object importFile(PluginContext context, URI uri) throws Exception; 34 | 35 | @PluginVariant(requiredParameterLabels = { 0 }) 36 | public Object importFile(PluginContext context, URL url) throws Exception; 37 | 38 | @PluginVariant(requiredParameterLabels = { 0 }) 39 | public Object importFile(PluginContext context, File f) throws Exception; 40 | 41 | } -------------------------------------------------------------------------------- /src/org/processmining/framework/annotations/AuthoredType.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target( { ElementType.TYPE }) 10 | public @interface AuthoredType { 11 | 12 | public final static String TUE = "Eindhoven University of Technology"; 13 | 14 | /** 15 | * Specifies the user-readable type for this class 16 | * 17 | * @return 18 | */ 19 | String typeName(); 20 | 21 | /** 22 | * Specifies the affiliation of the author 23 | * 24 | * @return 25 | */ 26 | String affiliation(); 27 | 28 | /** 29 | * specifies the e-mail address of the author 30 | * 31 | * @return 32 | */ 33 | String email(); 34 | 35 | /** 36 | * Specifies the name of the author 37 | * 38 | * @return 39 | */ 40 | String author(); 41 | 42 | /** 43 | * Specifies the website of the author (note that this should be URL style, 44 | * i.e. with http://) 45 | * 46 | * @return 47 | */ 48 | String website() default "http://www.processmining.org"; 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/org/processmining/framework/annotations/Icon.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target( { ElementType.TYPE }) 10 | public @interface Icon { 11 | 12 | /** 13 | * Specifies the relative path to the icon to be loaded if this type has to 14 | * be represented by an Icon 15 | * 16 | * @return 17 | */ 18 | public String icon(); 19 | } 20 | -------------------------------------------------------------------------------- /src/org/processmining/framework/annotations/TestMethod.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * By adding this annotation to a method, the method is flagged as a test method 10 | * for ProM. A hudson server should, on each commit, find all methods annotated 11 | * with this annotation and exectute it. 12 | * 13 | * The method should not require parameters and should be declared static. The 14 | * return type of the method should be: String. 15 | * 16 | * The string returned by this method is compared to either the string defined 17 | * in the output field, or with the contents of the file indicated by 18 | * filename(). 19 | * 20 | * If both filename and output are specified, then only output is used and the 21 | * file is ignored. 22 | * 23 | * @author bfvdonge 24 | * 25 | */ 26 | @Retention(RetentionPolicy.RUNTIME) 27 | @Target({ ElementType.METHOD }) 28 | public @interface TestMethod { 29 | 30 | String filename() default ""; 31 | 32 | String output() default ""; 33 | 34 | boolean returnSystemOut() default false; 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/org/processmining/framework/boot/AddJarsForPackageRunnable.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.boot; 2 | 3 | import java.io.File; 4 | import java.net.MalformedURLException; 5 | import java.net.URL; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import org.processmining.framework.boot.Boot.Level; 10 | import org.processmining.framework.packages.PackageDescriptor; 11 | import org.processmining.framework.plugin.PluginManager; 12 | import org.processmining.framework.util.PathHacker; 13 | 14 | /** 15 | * Threaded implementation of the addJarsForPackage method 16 | * 17 | * @author berti 18 | * 19 | */ 20 | public class AddJarsForPackageRunnable extends Thread { 21 | PackageDescriptor pack; 22 | Level verbose; 23 | PluginManager plugins; 24 | 25 | public AddJarsForPackageRunnable(PackageDescriptor pack, Level verbose, PluginManager plugins) { 26 | this.pack = pack; 27 | this.verbose = verbose; 28 | this.plugins = plugins; 29 | } 30 | 31 | /** 32 | * Entry point for thread 33 | */ 34 | public void run() { 35 | if (verbose == Level.ALL) { 36 | System.out.println("Scanning package: " + pack); 37 | } 38 | File dir = pack.getLocalPackageDirectory(); 39 | if (!dir.exists() || !dir.isDirectory() || !dir.canRead()) { 40 | if (verbose == Level.ALL) { 41 | System.out.println(" Error: package directory does not exist: " + dir); 42 | } 43 | return; 44 | } 45 | // First, recusively iterate subfolders, where no scanning for plugins is necessary 46 | // this ensures all requires libraries are known when scanning for plugins 47 | for (File f : dir.listFiles()) { 48 | // Scan for jars. Only jars in the root of the package will be scanned for 49 | // plugins and other annotations. 50 | if (f.isDirectory()) { 51 | Boot.addJarsFromPackageDirectory(f, verbose, plugins); 52 | try { 53 | Boot.addURLToClasspath(f.toURI().toURL()); 54 | } catch (MalformedURLException e) { 55 | } 56 | } 57 | } 58 | 59 | // Now scan the jar files in the package root folder. 60 | for (File f : dir.listFiles()) { 61 | if (f.getAbsolutePath().endsWith(PluginManager.JAR_EXTENSION)) { 62 | URL url; 63 | try { 64 | url = f.toURI().toURL(); 65 | if (verbose == Level.ALL) { 66 | System.out.println(" scanning for plugins: " + url); 67 | } 68 | Boot.addURLToClasspath(url); 69 | if (f.getAbsolutePath().endsWith(PluginManager.JAR_EXTENSION)) { 70 | plugins.register(url, pack); 71 | } 72 | } catch (MalformedURLException e) { 73 | e.printStackTrace(); 74 | } 75 | } 76 | } 77 | 78 | List subthreads = new ArrayList(); 79 | PathHacker.addLibraryPathFromDirectory(pack.getLocalPackageDirectory()); 80 | try { 81 | PathHacker.addJar(pack.getLocalPackageDirectory().toURI().toURL()); 82 | for (File f : pack.getLocalPackageDirectory().listFiles()) { 83 | if (f.isDirectory()) { 84 | PathHackerRunnable runnable = new PathHackerRunnable(pack, verbose, plugins, f); 85 | subthreads.add(runnable); 86 | subthreads.get(subthreads.size()-1).start(); 87 | } 88 | } 89 | } catch (MalformedURLException e) { 90 | assert (false); 91 | } 92 | 93 | for (Thread t : subthreads) { 94 | try { 95 | t.join(); 96 | } catch (InterruptedException e) { 97 | // TODO Auto-generated catch block 98 | e.printStackTrace(); 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/org/processmining/framework/boot/PathHackerRunnable.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.boot; 2 | 3 | import java.io.File; 4 | import java.net.MalformedURLException; 5 | 6 | import org.processmining.framework.boot.Boot.Level; 7 | import org.processmining.framework.packages.PackageDescriptor; 8 | import org.processmining.framework.plugin.PluginManager; 9 | import org.processmining.framework.util.PathHacker; 10 | 11 | /** 12 | * Threaded executions of PathHacker addJar 13 | * 14 | * @author berti 15 | * 16 | */ 17 | public class PathHackerRunnable extends Thread { 18 | PackageDescriptor pack; 19 | Level verbose; 20 | PluginManager plugins; 21 | File f; 22 | 23 | public PathHackerRunnable(PackageDescriptor pack, Level verbose, PluginManager plugins, File f) { 24 | this.pack = pack; 25 | this.verbose = verbose; 26 | this.plugins = plugins; 27 | this.f = f; 28 | } 29 | 30 | /** 31 | * Entry point for thread 32 | */ 33 | public void run() { 34 | //System.out.println("pathHacker "+f.toURI()); 35 | try { 36 | PathHacker.addJar(f.toURI().toURL()); 37 | } catch (MalformedURLException e) { 38 | // TODO Auto-generated catch block 39 | e.printStackTrace(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/org/processmining/framework/connections/Connection.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.connections; 2 | 3 | import java.util.Collection; 4 | import java.util.Set; 5 | 6 | import org.processmining.framework.annotations.AuthoredType; 7 | import org.processmining.framework.annotations.Icon; 8 | import org.processmining.framework.util.collection.MultiSet; 9 | 10 | /** 11 | * A connection describes a relation between objects. The connection keeps a 12 | * number of weak references between the objects in the relation. Each object 13 | * should have a label describing the role of the object in the relation. These 14 | * roles are unique 15 | * 16 | * Note that for all implementations of Connection, it is essential to consider 17 | * memory consumption. Connections are kept in the framework for as long as the 18 | * isRemoved() method returns false, hence this method should return true at the 19 | * earliest occasion. 20 | * 21 | * All implementations of this class should carry the following annotations: 22 | * @KeepInProMCache 23 | * @ConnectionAnnotation 24 | * @ConnectionDoesntExistMessage(message = "Message for case that connection Doesn't Exist") 25 | * 26 | * @author bfvdonge 27 | * 28 | */ 29 | @AuthoredType(typeName = "Connection", affiliation = AuthoredType.TUE, author = "B.F. van Dongen", email = "b.f.v.dongen@tue.nl") 30 | @Icon(icon = "resourcetype_connection_30x35.png") 31 | public interface Connection { 32 | 33 | /** 34 | * Return the label of the connection 35 | * 36 | * @return 37 | */ 38 | public String getLabel(); 39 | 40 | /** 41 | * Return the ID of the connection. 42 | * 43 | * @return 44 | */ 45 | public ConnectionID getID(); 46 | 47 | /** 48 | * Return true if all objects given as parameter are contained in the 49 | * connection. Multiplicities are taken into account, however order is 50 | * abstracted from 51 | * 52 | * @param objects 53 | * the objects to check for 54 | * @return 55 | */ 56 | public boolean containsObjects(Object... objects); 57 | 58 | /** 59 | * Return true if all objects given as parameter are contained in the 60 | * connection. Multiplicities are taken into account, i.e. each object 61 | * should occur as often as it is returned by the iterator of the given 62 | * collection however order is abstracted from 63 | * 64 | * @param objects 65 | * the objects as a collection 66 | * @return 67 | */ 68 | public boolean containsObjects(Collection objects); 69 | 70 | /** 71 | * Return true if one of the objects connected by this connection no longer 72 | * exists, i.e. it is collected by the garbage collector. 73 | * 74 | * @return 75 | */ 76 | public boolean isRemoved(); 77 | 78 | /** 79 | * Return all objects contained in this connection, without their labels. 80 | * 81 | * By contract, this method should always return the same set of objects 82 | * after the connections was created, i.e. connections may only be changed 83 | * by changing the contents of the objects, but not by changing the 84 | * pointers. 85 | * 86 | * @return 87 | */ 88 | public MultiSet getObjects(); 89 | 90 | /** 91 | * Return the roles of all objects in this connection 92 | * 93 | * @return 94 | */ 95 | public Set getRoles(); 96 | 97 | /** 98 | * Return the object with the given role in this connection The type of the 99 | * returned object is T. However, no checks have to be performed to see if 100 | * the cast can be made. It is up to the calling method to ensure this cast 101 | * is safe. 102 | * 103 | * @param 104 | * The type of object that should be returned. 105 | * @param role 106 | * the role the returned object has to have 107 | * @return the object attached to this role (not null). 108 | */ 109 | public T getObjectWithRole(String role); 110 | 111 | /** 112 | * Removes the connection. After calling this method, isRemoved()returns 113 | * true; 114 | */ 115 | public void remove(); 116 | 117 | /** 118 | * sets the label of the connection to the new name 119 | * 120 | * @param name 121 | */ 122 | public void setLabel(String name); 123 | 124 | /** 125 | * This method should be called as soon as the connection is changed, for 126 | * example if the label changed, or if the contents of one of the connected 127 | * objects changes. 128 | * 129 | * By calling this method, the connection manager should be notified. 130 | */ 131 | public void updated(); 132 | 133 | /** 134 | * Sets the manager for the connection. This method is called by the 135 | * connection manager as soon as this connection is added to that manager. A 136 | * connection should keep a reference to the manager only in a transient 137 | * field. 138 | * 139 | * @param manager 140 | */ 141 | void setManager(ConnectionManager manager); 142 | 143 | } 144 | -------------------------------------------------------------------------------- /src/org/processmining/framework/connections/ConnectionAnnotation.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.connections; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Inherited; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * This annotation is used by the framework to scan for all implementations if 11 | * Connection. 12 | * 13 | * @author bfvdonge 14 | * 15 | */ 16 | @Retention(RetentionPolicy.RUNTIME) 17 | @Target({ ElementType.TYPE }) 18 | @Inherited 19 | public @interface ConnectionAnnotation { 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/org/processmining/framework/connections/ConnectionCannotBeObtained.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.connections; 2 | 3 | import org.processmining.framework.connections.annotations.ConnectionDoesntExistMessage; 4 | 5 | /** 6 | * Exception thrown by the connectionmanager if a requested connection does not 7 | * exist. 8 | * 9 | * @author bfvdonge 10 | * 11 | */ 12 | public class ConnectionCannotBeObtained extends Exception { 13 | 14 | private final Class connectionType; 15 | 16 | /** 17 | * Constructor with message and cause 18 | * 19 | * @param reason 20 | * The reason of throwing this exception 21 | * @param ex 22 | * the cause of this exception 23 | */ 24 | public ConnectionCannotBeObtained(String reason, ConnectionCannotBeObtained ex) { 25 | this(reason + " \n " + ex.getMessage(), ex.connectionType); 26 | } 27 | 28 | /** 29 | * Constructor with reason, connection type and objects. The message is set 30 | * to: "No known connection of type + connectionType + " between " + 31 | * Arrays.toString(objects) + " [" + reason + "]"; 32 | * 33 | * @param reason 34 | * The reason of throwing this exception 35 | * @param connectionType 36 | * The requested connection type 37 | * @param objects 38 | * the objects on which a connection was requested 39 | */ 40 | public ConnectionCannotBeObtained(String reason, Class connectionType, Object... objects) { 41 | super("No connection of type " + connectionType.getSimpleName() + 42 | // " can be obtained for objects: " + Arrays.toString(objects) + 43 | "\n The reason given is: " + reason + "\n " 44 | + getDoesntExistMessage(connectionType)) 45 | ; 46 | this.connectionType = connectionType; 47 | } 48 | 49 | /** 50 | * 51 | */ 52 | private static final long serialVersionUID = 224232280740635702L; 53 | 54 | private static String getDoesntExistMessage(Class connectionType) { 55 | if (connectionType == null) { 56 | return ""; 57 | } 58 | String s = ""; 59 | ConnectionDoesntExistMessage message = connectionType.getAnnotation(ConnectionDoesntExistMessage.class); 60 | if (message != null) { 61 | s = message.message(); 62 | } 63 | if ((connectionType != Connection.class) && (connectionType.getSuperclass() != null) 64 | && (Connection.class.isAssignableFrom(connectionType.getSuperclass()))) { 65 | s = getDoesntExistMessage(connectionType.getSuperclass()) + " \n " + s; 66 | } 67 | for (Class sup : connectionType.getInterfaces()) { 68 | if (Connection.class.isAssignableFrom(sup)) { 69 | s = getDoesntExistMessage(connectionType.getSuperclass()) + " \n " + s; 70 | } 71 | } 72 | return s; 73 | 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/org/processmining/framework/connections/ConnectionID.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.connections; 2 | 3 | import org.processmining.framework.ProMID; 4 | 5 | /** 6 | * ID of a connection. Need not to be persistent over serialization. 7 | * 8 | * @author bfvdonge 9 | * 10 | */ 11 | public interface ConnectionID extends ProMID { 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/org/processmining/framework/connections/ConnectionManager.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.connections; 2 | 3 | import java.util.Collection; 4 | 5 | import org.processmining.framework.plugin.PluginContext; 6 | import org.processmining.framework.plugin.events.ConnectionObjectListener; 7 | 8 | public interface ConnectionManager { 9 | 10 | /** 11 | * Returns a collection of connections between the objects specified, such 12 | * that the type of the connection is assignable from the given 13 | * connectionType (unless the parameter equals null). 14 | * 15 | * If no connections satisfying these criteria exist and the required type 16 | * is specified and no required name is specified, then the global context 17 | * searches for all available plugins with a ConnectionObjectFactory 18 | * annotation, which can be executed in a child of the given PluginContext 19 | * and accept the given objects as input 20 | * 21 | * If such plugins exist, the first of these plugins is selected and invoked 22 | * on the given objects. The result is obtained from the plugin and a new 23 | * connection is registered of the right type. This connection is then 24 | * returned. 25 | * 26 | * @param 27 | * the type of the requested connection. 28 | * @param connectionType 29 | * The type of the object requested. This type can be null, in 30 | * which case all types are considered. 31 | * @param context 32 | * The context which requests the connection. If a plugin is 33 | * invoked to create a connection, a child context of this 34 | * context is instantiated 35 | * @param objects 36 | * the objects which should be connected by the requested 37 | * connection. There might be more objects involved in the 38 | * connection 39 | * @return A collection of connections of the requested type T. If no 40 | * connection exists, an exception is thrown, hence the collection 41 | * is never empty. 42 | * @throws ConnectionCannotBeObtained 43 | * if the requested connection does not exist and cannot be 44 | * produced in the given context. 45 | */ 46 | Collection getConnections(Class connectionType, PluginContext context, 47 | Object... objects) throws ConnectionCannotBeObtained; 48 | 49 | /** 50 | * Returns a connection between the objects specified, such that the type of 51 | * the connection is assignable from the given connectionType (unless the 52 | * parameter equals null). 53 | * 54 | * If no connections satisfying these criteria exist and the required type 55 | * is specified and no required name is specified, then the global context 56 | * searches for all available plugins with a ConnectionObjectFactory 57 | * annotation, which can be executed in a child of the given PluginContext 58 | * and accept the given objects as input 59 | * 60 | * If such plugins exist, the first of these plugins is selected and invoked 61 | * on the given objects. The result is obtained from the plugin and a new 62 | * connection is registered of the right type. This connection is then 63 | * returned. 64 | * 65 | * @param 66 | * the type of the requested connection. 67 | * @param connectionType 68 | * The type of the object requested. This type can be null, in 69 | * which case all types are considered. 70 | * @param context 71 | * The context which requests the connection. If a plugin is 72 | * invoked to create a connection, a child context of this 73 | * context is instantiated 74 | * @param objects 75 | * the objects which should be connected by the requested 76 | * connection. There might be more objects involved in the 77 | * connection 78 | * @return A connection of the requested type T. If no connection exists, an 79 | * exception is thrown, hence null is never returned. 80 | * @throws ConnectionCannotBeObtained 81 | * if the requested connection does not exist and cannot be 82 | * produced in the given context. 83 | */ 84 | T getFirstConnection(Class connectionType, PluginContext context, Object... objects) 85 | throws ConnectionCannotBeObtained; 86 | 87 | /** 88 | * Returns the connection with the given ID. 89 | * 90 | * @param id 91 | * the connection ID 92 | * @return the connection with the given ID 93 | */ 94 | Connection getConnection(ConnectionID id) throws ConnectionCannotBeObtained; 95 | 96 | /** 97 | * Returns the list of registered connectionObject listeners 98 | * 99 | * @return the list of registered connectionObject listeners 100 | */ 101 | ConnectionObjectListener.ListenerList getConnectionListeners(); 102 | 103 | /** 104 | * Returns a collection of connection IDs registered to this global context. 105 | * 106 | * @return the ids of the registered connections 107 | */ 108 | Collection getConnectionIDs(); 109 | 110 | /** 111 | * Adds the given connection to the framework. 112 | * 113 | * @param connection 114 | * The connection to be registered 115 | * @return the given parameter connection 116 | */ 117 | T addConnection(T connection); 118 | 119 | /** 120 | * Returns whether connections are enabled. If not, then connecitons will not be added. 121 | * @return whether connections are enabled 122 | */ 123 | boolean isEnabled(); 124 | 125 | /** 126 | * Sets whether connections are enabled. 127 | * @param isEnabled whether connections should be enabled 128 | */ 129 | void setEnabled(boolean isEnabled); 130 | 131 | void clear(); 132 | } 133 | -------------------------------------------------------------------------------- /src/org/processmining/framework/connections/DynamicConnection.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.connections; 2 | 3 | /** 4 | * Tagger interface to indicate that a connection will change after 5 | * instantiation. Since the actual objects involved in the connection are not 6 | * allowed to change, these changes should be limited to the contents of the 7 | * connection itself. 8 | * 9 | * The main use for this interface is in serialization, where DynamicConnections 10 | * are only serialized when ProM is closed. 11 | * 12 | * @author bfvdonge 13 | * 14 | */ 15 | public interface DynamicConnection { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/org/processmining/framework/connections/annotations/ConnectionDoesntExistMessage.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.connections.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ ElementType.TYPE }) 10 | public @interface ConnectionDoesntExistMessage { 11 | 12 | public String message() default ""; 13 | } 14 | -------------------------------------------------------------------------------- /src/org/processmining/framework/connections/annotations/ConnectionObjectFactory.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.connections.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Annotation used on plugins to signal that they can construct a Connection on 10 | * objects. 11 | * 12 | * The type of connection produced is given by the return type of the plugin, of 13 | * which there should be only 1, which is assignable from Connection.class. 14 | * 15 | * To avoid lifelocks such a plugin should not request any connection on its 16 | * inputs. If no connection can be made, null should be returned. 17 | * 18 | * @author bfvdonge 19 | * 20 | */ 21 | @Retention(RetentionPolicy.RUNTIME) 22 | @Target( { ElementType.METHOD, ElementType.TYPE }) 23 | public @interface ConnectionObjectFactory { 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/org/processmining/framework/connections/impl/AbstractStrongReferencingConnection.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.connections.impl; 2 | 3 | import java.lang.ref.WeakReference; 4 | import java.util.Collection; 5 | import java.util.HashSet; 6 | import java.util.Map; 7 | 8 | public abstract class AbstractStrongReferencingConnection extends AbstractConnection { 9 | 10 | // Keep a strong reference to some objects, as these 11 | // would otherwise fault the connection. 12 | // When checking for removal, these objects are ignored, i.e. the connection 13 | // is considered to be removed if any of the weak references has been nullified. 14 | private final Collection objectReferences = new HashSet(); 15 | 16 | public AbstractStrongReferencingConnection(String label) { 17 | super(label); 18 | } 19 | 20 | protected WeakReference putStrong(String role, T o) { 21 | objectReferences.add(o); 22 | return super.put(role, o); 23 | } 24 | 25 | @Override 26 | public boolean isRemoved() { 27 | for (Map.Entry> t : getMapping().entrySet()) { 28 | Object o = t.getValue().get(); 29 | if (objectReferences.contains(o)) { 30 | // Skip the objects to which Hard links need to be kept. 31 | continue; 32 | } 33 | if (o == null) { 34 | return true; 35 | } 36 | } 37 | return false; 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /src/org/processmining/framework/connections/impl/ConnectionIDImpl.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.connections.impl; 2 | 3 | import java.util.UUID; 4 | 5 | import org.processmining.framework.ProMID; 6 | import org.processmining.framework.connections.ConnectionID; 7 | 8 | public class ConnectionIDImpl implements ConnectionID { 9 | 10 | private final UUID id = UUID.randomUUID(); 11 | 12 | public String toString() { 13 | return id.toString(); 14 | } 15 | 16 | public int hashCode() { 17 | return id.hashCode(); 18 | } 19 | 20 | public boolean equals(Object o) { 21 | if (!(o instanceof ConnectionIDImpl)) { 22 | return false; 23 | } else { 24 | return ((ConnectionIDImpl) o).id.equals(id); 25 | } 26 | } 27 | 28 | public boolean equalsIgnoreType(Object o) { 29 | return toString().equals(o.toString()); 30 | } 31 | 32 | public int compareTo(ProMID o) { 33 | return o.getUUID().compareTo(id); 34 | } 35 | 36 | public UUID getUUID() { 37 | return id; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/org/processmining/framework/connections/impl/ConnectionManagerImpl.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.connections.impl; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.HashMap; 6 | import java.util.Iterator; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Map.Entry; 10 | 11 | import org.processmining.framework.connections.Connection; 12 | import org.processmining.framework.connections.ConnectionCannotBeObtained; 13 | import org.processmining.framework.connections.ConnectionID; 14 | import org.processmining.framework.connections.ConnectionManager; 15 | import org.processmining.framework.connections.annotations.ConnectionObjectFactory; 16 | import org.processmining.framework.plugin.PluginContext; 17 | import org.processmining.framework.plugin.PluginExecutionResult; 18 | import org.processmining.framework.plugin.PluginManager; 19 | import org.processmining.framework.plugin.PluginParameterBinding; 20 | import org.processmining.framework.plugin.events.ConnectionObjectListener; 21 | import org.processmining.framework.plugin.events.Logger.MessageLevel; 22 | import org.processmining.framework.util.Pair; 23 | 24 | public class ConnectionManagerImpl implements ConnectionManager { 25 | 26 | private final Map connections = new HashMap(); 27 | private final ConnectionObjectListener.ListenerList connectionListeners = new ConnectionObjectListener.ListenerList(); 28 | private final PluginManager pluginManager; 29 | private boolean isEnabled = true; 30 | 31 | public ConnectionManagerImpl(PluginManager pluginManager) { 32 | this.pluginManager = pluginManager; 33 | 34 | } 35 | 36 | /** 37 | * Returns the list of registered connectionObject listeners 38 | * 39 | * @return the list of registered connectionObject listeners 40 | */ 41 | public ConnectionObjectListener.ListenerList getConnectionListeners() { 42 | return connectionListeners; 43 | } 44 | 45 | public boolean isEnabled() { 46 | return isEnabled; 47 | } 48 | 49 | public void setEnabled(boolean isEnabled) { 50 | this.isEnabled = isEnabled; 51 | } 52 | 53 | public void clear() { 54 | connections.clear(); 55 | } 56 | 57 | public T addConnection(T connection) { 58 | if (isEnabled) { 59 | synchronized (connections) { 60 | connections.put(connection.getID(), connection); 61 | connection.setManager(this); 62 | connectionListeners.fireConnectionCreated(connection.getID()); 63 | } 64 | } 65 | return connection; 66 | } 67 | 68 | public Connection getConnection(ConnectionID id) throws ConnectionCannotBeObtained { 69 | Connection c = connections.get(id); 70 | synchronized (connections) { 71 | if (c == null || c.isRemoved()) { 72 | connections.remove(c); 73 | connectionListeners.fireConnectionDeleted(id); 74 | if (c != null) 75 | throw new ConnectionCannotBeObtained("Objects were deleted", c.getClass()); 76 | else 77 | throw new ConnectionCannotBeObtained("Objects were deleted", Object.class); 78 | } 79 | return c; 80 | } 81 | } 82 | 83 | public T getFirstConnection(Class connectionType, PluginContext context, 84 | Object... objects) throws ConnectionCannotBeObtained { 85 | return getConnections(true, connectionType, context, objects).iterator().next(); 86 | } 87 | 88 | public Collection getConnections(Class connectionType, PluginContext context, 89 | Object... objects) throws ConnectionCannotBeObtained { 90 | return getConnections(false, connectionType, context, objects); 91 | } 92 | 93 | @SuppressWarnings("unchecked") 94 | private Collection getConnections(boolean stopAtFirst, Class connectionType, 95 | PluginContext context, Object... objects) throws ConnectionCannotBeObtained { 96 | List available = new ArrayList(1); 97 | //System.gc(); 98 | synchronized (connections) { 99 | Iterator> it = connections.entrySet().iterator(); 100 | while (it.hasNext()) { 101 | Entry entry = it.next(); 102 | Connection c = entry.getValue(); 103 | if (c.isRemoved()) { 104 | it.remove(); 105 | connectionListeners.fireConnectionDeleted(c.getID()); 106 | continue; 107 | } 108 | if (((connectionType == null) || connectionType.isAssignableFrom(c.getClass())) 109 | && c.containsObjects(objects)) { 110 | context.log("Connection found: " + c, MessageLevel.DEBUG); 111 | available.add((T) c); 112 | if (stopAtFirst) { 113 | return available; 114 | } 115 | } 116 | } 117 | } 118 | if (!available.isEmpty()) { 119 | return available; 120 | } 121 | if ((connectionType == null) || (objects.length <= 1)) { 122 | throw new ConnectionCannotBeObtained("No plugin available to create connection", connectionType, objects); 123 | 124 | } 125 | Class[] types = new Class[objects.length]; 126 | for (int i = 0; i < objects.length; i++) { 127 | types[i] = objects[i].getClass(); 128 | } 129 | 130 | Collection> plugins = pluginManager.find(ConnectionObjectFactory.class, 131 | connectionType, context.getClass(), true, false, false, types); 132 | if (plugins.isEmpty()) { 133 | throw new ConnectionCannotBeObtained("No plugin available to create connection", connectionType, objects); 134 | } 135 | PluginContext c2 = context.createChildContext("Creating connection of Type " + connectionType); 136 | Pair pair = plugins.iterator().next(); 137 | PluginParameterBinding binding = pair.getSecond(); 138 | try { 139 | 140 | PluginExecutionResult pluginResult = binding.invoke(c2, objects); 141 | pluginResult.synchronize(); 142 | T connectionObject = pluginResult.getResult(pair.getFirst()); 143 | 144 | if (connectionObject == null) { 145 | throw new ConnectionCannotBeObtained("Factory plugin returned null.", connectionType, objects); 146 | } 147 | available.add(addConnection(connectionObject)); 148 | context.log("Added connection: " + connectionObject, MessageLevel.DEBUG); 149 | return available; 150 | } catch (Exception e) { 151 | throw new ConnectionCannotBeObtained(e.getMessage(), connectionType, objects); 152 | } finally { 153 | c2.getParentContext().deleteChild(c2); 154 | } 155 | } 156 | 157 | public Collection getConnectionIDs() { 158 | return connections.keySet(); 159 | } 160 | 161 | } 162 | -------------------------------------------------------------------------------- /src/org/processmining/framework/packages/PackageSet.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.packages; 2 | 3 | import java.util.HashSet; 4 | 5 | import org.processmining.framework.packages.PackageDescriptor.OS; 6 | 7 | public class PackageSet extends HashSet { 8 | 9 | private static final long serialVersionUID = -5010658216636461231L; 10 | 11 | public boolean add(PackageDescriptor e) { 12 | if (e.getOS() == OS.WIN64) { 13 | // check for removal of Win32 version 14 | for (PackageDescriptor pack : this) { 15 | if (pack.getName().equals(e.getName()) && // 16 | pack.getVersion().equals(e.getVersion()) && // 17 | pack.getOS() == OS.WIN32) { 18 | remove(pack); 19 | break; 20 | } 21 | } 22 | } else { 23 | if (e.getOS() == OS.WIN32) { 24 | // Check if Win64 version already in the set 25 | for (PackageDescriptor pack : this) { 26 | if (pack.getName().equals(e.getName()) && // 27 | pack.getVersion().equals(e.getVersion()) && // 28 | pack.getOS() == OS.WIN64) { 29 | // win64 version already available. Don't add 32 bit version. 30 | return false; 31 | } 32 | } 33 | } 34 | } 35 | return super.add(e); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/org/processmining/framework/packages/PackageStateReport.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.packages; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Set; 7 | import java.util.SortedSet; 8 | 9 | public class PackageStateReport { 10 | 11 | private final Map> missing; 12 | private final Map> conflicts; 13 | private final Map> multipleVersions; 14 | 15 | public PackageStateReport(Map> multipleVersions, 16 | Map> missing, Map> conflicts) { 17 | this.multipleVersions = multipleVersions; 18 | this.conflicts = conflicts; 19 | this.missing = missing; 20 | } 21 | 22 | public Map> getMissingDependencies() { 23 | return missing; 24 | } 25 | 26 | public Map> getConflictingPackages() { 27 | return conflicts; 28 | } 29 | 30 | public Map> getPackagesWithMultipleVersions() { 31 | return multipleVersions; 32 | } 33 | 34 | public String toString() { 35 | List lines = new ArrayList(); 36 | 37 | for (Map.Entry> item : getPackagesWithMultipleVersions().entrySet()) { 38 | lines.add("Package " + item.getKey() + " has or will have multiple versions installed:"); 39 | for (PackageDescriptor p : item.getValue()) { 40 | lines.add(" " + p); 41 | } 42 | } 43 | for (Map.Entry> item : getMissingDependencies().entrySet()) { 44 | lines.add("Package " + item.getKey() + " depends on packages which are and will not be installed:"); 45 | for (String dep : item.getValue()) { 46 | lines.add(" " + dep); 47 | } 48 | } 49 | for (Map.Entry> item : getConflictingPackages().entrySet()) { 50 | lines.add("Package " + item.getKey() + " conflicts with packages which are or will be installed:"); 51 | for (String confl : item.getValue()) { 52 | lines.add(" " + confl); 53 | } 54 | } 55 | 56 | StringBuffer result = new StringBuffer(); 57 | for (String s : lines) { 58 | result.append(s); 59 | result.append(System.getProperty("line.separator")); 60 | } 61 | return result.toString(); 62 | } 63 | 64 | public boolean hasErrors() { 65 | return !getConflictingPackages().isEmpty() || !getMissingDependencies().isEmpty() 66 | || !getPackagesWithMultipleVersions().isEmpty(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/org/processmining/framework/packages/PackageVersion.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.packages; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class PackageVersion implements Comparable { 7 | 8 | private final List version; 9 | 10 | public PackageVersion(String version) { 11 | this.version = parse(version); 12 | } 13 | 14 | private List parse(String v) { 15 | List result = new ArrayList(); 16 | String[] components = v.split("[^0-9]"); 17 | 18 | for (String c : components) { 19 | if (c.length() > 0) { 20 | result.add(Integer.parseInt(c)); 21 | } 22 | } 23 | return result; 24 | } 25 | 26 | public boolean equals(Object o) { 27 | if (!(o instanceof PackageVersion)) { 28 | return false; 29 | } 30 | return version.equals(((PackageVersion) o).version); 31 | } 32 | 33 | public int hashCode() { 34 | return version.hashCode(); 35 | } 36 | 37 | public String toString() { 38 | String result = new String(); 39 | 40 | for (Integer i : version) { 41 | if (result.length() > 0) { 42 | result += '.'; 43 | } 44 | result += i; 45 | } 46 | return result; 47 | } 48 | 49 | public boolean lessOrEqual(PackageVersion v) { 50 | return compareTo(v) <= 0; 51 | } 52 | 53 | public boolean lessThan(PackageVersion v) { 54 | return compareTo(v) < 0; 55 | } 56 | 57 | public int compareTo(PackageVersion v) { 58 | for (int i = 0; i < version.size(); i++) { 59 | if (i < v.version.size()) { 60 | int self = version.get(i); 61 | int other = v.version.get(i); 62 | 63 | if (self < other) { 64 | return -1; 65 | } else if (self > other) { 66 | return 1; 67 | } 68 | } else { 69 | return 1; 70 | } 71 | } 72 | return version.size() == v.version.size() ? 0 : -1; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/org/processmining/framework/packages/Repository.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.packages; 2 | 3 | import java.net.URL; 4 | 5 | public class Repository { 6 | 7 | private final URL url; 8 | 9 | public Repository(URL url) { 10 | this.url = url; 11 | } 12 | 13 | public URL getURL() { 14 | return url; 15 | } 16 | 17 | public String toString() { 18 | return "Repository(" + getURL().toString() + ")"; 19 | } 20 | 21 | public boolean equals(Object other) { 22 | if (!(other instanceof Repository)) { 23 | return false; 24 | } 25 | return ((Repository) other).getURL().equals(url); 26 | } 27 | 28 | public int hashCode() { 29 | return url.hashCode(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/org/processmining/framework/packages/UnknownPackageException.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.packages; 2 | 3 | public class UnknownPackageException extends Exception { 4 | 5 | /** 6 | * 7 | */ 8 | private static final long serialVersionUID = 1037754203430229972L; 9 | private final String name; 10 | 11 | public UnknownPackageException(String name) { 12 | super("Unknow package: " + name); 13 | this.name = name; 14 | } 15 | 16 | public String getName() { 17 | return name; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/org/processmining/framework/packages/UnknownPackageTypeException.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.packages; 2 | 3 | public class UnknownPackageTypeException extends Exception { 4 | 5 | private static final long serialVersionUID = -7248277354439798414L; 6 | private final PackageDescriptor pack; 7 | 8 | public UnknownPackageTypeException(PackageDescriptor pack) { 9 | super("Unknow package file type: " + pack.getURL()); 10 | this.pack = pack; 11 | } 12 | 13 | public PackageDescriptor getPack() { 14 | return pack; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/org/processmining/framework/packages/events/PackageManagerListener.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.packages.events; 2 | 3 | import java.io.File; 4 | import java.net.URL; 5 | import java.util.EventListener; 6 | 7 | import org.processmining.framework.packages.PackageDescriptor; 8 | import org.processmining.framework.plugin.events.ProMEventListenerList; 9 | 10 | public interface PackageManagerListener extends EventListener { 11 | 12 | public class ListenerList extends ProMEventListenerList { 13 | public void fireSessionStart() { 14 | for (PackageManagerListener listener : getListeners()) { 15 | listener.sessionStart(); 16 | } 17 | } 18 | 19 | public void fireSessionComplete(boolean error) { 20 | for (PackageManagerListener listener : getListeners()) { 21 | listener.sessionComplete(error); 22 | } 23 | } 24 | 25 | public void fireStartDownload(String packageName, URL url, PackageDescriptor pack) { 26 | for (PackageManagerListener listener : getListeners()) { 27 | listener.startDownload(packageName, url, pack); 28 | } 29 | } 30 | 31 | public void fireStartInstall(String packageName, File folder, PackageDescriptor pack) { 32 | for (PackageManagerListener listener : getListeners()) { 33 | listener.startInstall(packageName, folder, pack); 34 | } 35 | } 36 | 37 | public void fireFinishedInstall(String packageName, File folder, PackageDescriptor pack) { 38 | for (PackageManagerListener listener : getListeners()) { 39 | listener.finishedInstall(packageName, folder, pack); 40 | } 41 | } 42 | 43 | public void fireException(String exception) { 44 | for (PackageManagerListener listener : getListeners()) { 45 | listener.exception(exception); 46 | } 47 | } 48 | 49 | public void fireException(Throwable t) { 50 | for (PackageManagerListener listener : getListeners()) { 51 | listener.exception(t); 52 | } 53 | } 54 | } 55 | 56 | public void sessionStart(); 57 | 58 | public void exception(Throwable t); 59 | 60 | public void exception(String exception); 61 | 62 | public void startDownload(String packageName, URL url, PackageDescriptor pack); 63 | 64 | public void startInstall(String packageName, File folder, PackageDescriptor pack); 65 | 66 | public void finishedInstall(String packageName, File folder, PackageDescriptor pack); 67 | 68 | public void sessionComplete(boolean error); 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/org/processmining/framework/packages/impl/CancelledException.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.packages.impl; 2 | 3 | import org.xml.sax.SAXException; 4 | 5 | public class CancelledException extends SAXException { 6 | 7 | /** 8 | * 9 | */ 10 | private static final long serialVersionUID = -1288614934031744810L; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/GlobalContext.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin; 2 | 3 | import org.processmining.framework.connections.ConnectionManager; 4 | import org.processmining.framework.providedobjects.ProvidedObjectManager; 5 | 6 | /** 7 | * Any implementation should maintain a referencte to a single plugin context. 8 | * This plugin context is then used create children, in which plugins are 9 | * executed. 10 | * 11 | * @author bfvdonge 12 | * 13 | */ 14 | public interface GlobalContext { 15 | 16 | /** 17 | * Returns the plugin manager. The plugin manager can be used to query for 18 | * plugins which are registered in ProM. 19 | * 20 | * @return the plugin manager 21 | */ 22 | PluginManager getPluginManager(); 23 | 24 | /** 25 | * Returns the providedObject manager. The providedObject manager can be 26 | * used to query for providedObjects which are registered in ProM. The 27 | * manager should be a ProvidedObjectListener on all PluginInstanceContexts 28 | * created by createRootInstanceContext. 29 | * 30 | * @return the providedObject manager 31 | */ 32 | ProvidedObjectManager getProvidedObjectManager(); 33 | 34 | /** 35 | * Returns the connection manager. The connection manager can be used to 36 | * query for connections which are registered in ProM. 37 | * 38 | * @return the connection manager 39 | */ 40 | 41 | ConnectionManager getConnectionManager(); 42 | 43 | /** 44 | * The GlobalContext implementation should create IDs for all PluginContexts 45 | * instantiated for it. 46 | * 47 | * @return 48 | */ 49 | PluginContextID createNewPluginContextID(); 50 | 51 | /** 52 | * This method invokes the specified plugin in a context which is a child of 53 | * the main plugin context maintained by this globalContext. No results are 54 | * provided to the method calling this method and the plugin is executed 55 | * some time in the future, as decided by the implementing class. 56 | * 57 | * @param plugin 58 | * The plugin that should be invoked by the framework 59 | * @param index 60 | * The index of the plugin method that should be invoked. 61 | * @param objects 62 | * The objects to serve as input as accepted by the method at 63 | * index of the plugin 64 | */ 65 | void invokePlugin(PluginDescriptor plugin, int index, Object... objects); 66 | 67 | /** 68 | * This method invokes the specified binding in a context which is a child 69 | * of the main plugin context maintained by this globalContext. No results 70 | * are provided to the method calling this method and the plugin is executed 71 | * some time in the future, as decided by the implementing class. 72 | * 73 | * @param binding 74 | * The binding that should be invoked by the framework 75 | * @param objects 76 | * The objects to serve as input as accepted by the given 77 | * binding. 78 | */ 79 | void invokeBinding(PluginParameterBinding binding, Object... objects); 80 | 81 | /** 82 | * Returns the specific type of the PluginContext. This type is used to 83 | * instantiate new contexts in which to invoke plugins. 84 | * 85 | * @return the type of PluginContext provided by this global context 86 | */ 87 | Class getPluginContextType(); 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/InSufficientResultException.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin; 2 | 3 | /** 4 | * Thrown when a plugin returns less results than declared. 5 | * 6 | * @author bfvdonge 7 | * 8 | */ 9 | public class InSufficientResultException extends RuntimeException { 10 | 11 | private static final long serialVersionUID = -1416206990218147728L; 12 | 13 | public InSufficientResultException(String plugin, int expected, int returned) { 14 | super("Plugin " + plugin + " produced " + returned + " results, while " + expected + " results were declared."); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/IncorrectReturnTypeException.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin; 2 | 3 | /** 4 | * Thrown when a plugin returns an object of the wrong type. 5 | * 6 | * @author bfvdonge 7 | * 8 | */ 9 | public class IncorrectReturnTypeException extends RuntimeException { 10 | 11 | private static final long serialVersionUID = 8553687837509819311L; 12 | 13 | public IncorrectReturnTypeException(String plugin, int index, Class expected, Class returned) { 14 | super("Plugin " + plugin + " produced the wrong type of result at index " + index + ": Expected: " + expected 15 | + ", but received: " + (returned == null ? "nothing" : returned) + "."); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/ObjectConstructor.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin; 2 | 3 | import java.util.Collection; 4 | 5 | import org.processmining.framework.connections.Connection; 6 | import org.processmining.framework.connections.ConnectionCannotBeObtained; 7 | 8 | public interface ObjectConstructor { 9 | 10 | /** 11 | * Finds as many objects of the given type as can be found through the 12 | * connections of the other given type. If no objects can be found, it 13 | * constructs as many objects of the given type as there are plugins 14 | * available to the framework to do so. These plugins should be able to 15 | * execute in a child of the given context and accept, in any order, exactly 16 | * the input provided. Any other objects returned by the plugin, not being 17 | * the requested type are added to the provided objects of the framework. 18 | * Also, listeners are notified where applicable. If no plugings exist, or 19 | * if these plugins fail, a ConnectionDoesntExistException is thrown. 20 | * 21 | * @param 22 | * The type of the return object required. 23 | * @param The type of the connections to use when 24 | * trying to find the objects. 25 | * @param type 26 | * the type of the return object required. 27 | * @param connectionType 28 | * the type of the connections to use when trying to find the 29 | * objects. 30 | * @param role 31 | * the assumed role of the object in the connection. Given a 32 | * connection, the object can be retrieved through the role. 33 | * @param input 34 | * the input on which the plugin should work 35 | * @return a collection of objects as found or returned by the plugins. 36 | */ 37 | public Collection tryToFindOrConstructAllObjects(Class type, 38 | Class connectionType, String role, Object... input) throws ConnectionCannotBeObtained; 39 | 40 | /** 41 | * Returns the first object of the given type as can be found through the 42 | * connections of the other given type. If no objects can be found, it 43 | * constructs as an object of the given type using a plugin available to the 44 | * framework to do so. This plugins should be able to execute in a child of 45 | * the given context and accept, in any order, exactly the input provided. 46 | * Any other objects returned by the plugin, not being the requested type 47 | * are added to the provided objects of the framework. Also, listeners are 48 | * notified where applicable. If no plugins exist, or if these plugins fail, 49 | * a ConnectionDoesntExistException is thrown. 50 | * 51 | * @param 52 | * The type of the return object required. 53 | * @param The type of the connections to use when 54 | * trying to find the objects. 55 | * @param type 56 | * the type of the return object required. 57 | * @param connectionType 58 | * the type of the connections to use when trying to find the 59 | * objects. 60 | * @param role 61 | * the assumed role of the object in the connection. Given a 62 | * connection, the object can be retrieved through the role. 63 | * @param input 64 | * the input on which the plugin should work 65 | * @return a collection of objects as returned by the plugins. 66 | */ 67 | public T tryToFindOrConstructFirstObject(Class type, Class connectionType, 68 | String role, Object... input) throws ConnectionCannotBeObtained; 69 | 70 | /** 71 | * Returns the first object of the given type as can be found through the 72 | * connections of the other given type. If no objects can be found, it 73 | * constructs as an object of the given type using a plugin available to the 74 | * framework to do so. This plugins should be able to execute in a child of 75 | * the given context and accept, in any order, exactly the input provided. 76 | * Furthermore, the returned object should have the right label assigned to 77 | * it in the plugin definition. Any other objects returned by the plugin, 78 | * not being the requested type are added to the provided objects of the 79 | * framework. Also, listeners are notified where applicable. If no plugins 80 | * exist, or if these plugins fail, a ConnectionDoesntExistException is 81 | * thrown. 82 | * 83 | * @param 84 | * The type of the return object required. 85 | * @param The type of the connections to use when 86 | * trying to find the objects. 87 | * @param type 88 | * the type of the return object required. 89 | * @param name 90 | * the name of the plugin to use. 91 | * @param connectionType 92 | * the type of the connections to use when trying to find the 93 | * objects. 94 | * @param role 95 | * the assumed role of the object in the connection. Given a 96 | * connection, the object can be retrieved through the role. 97 | * @param input 98 | * the input on which the plugin should work 99 | * @return a collection of objects as returned by the plugins. 100 | */ 101 | public T tryToFindOrConstructFirstNamedObject(Class type, String name, 102 | Class connectionType, String role, Object... input) throws ConnectionCannotBeObtained; 103 | 104 | } -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/PluginContextID.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin; 2 | 3 | /** 4 | * Represents an ID of a plugin context. 5 | * 6 | * @author bfvdonge 7 | * 8 | */ 9 | public interface PluginContextID extends Comparable { 10 | 11 | /** 12 | * PluginContextID are used in Collections, so this method has to be 13 | * implemented in all its subclasses. 14 | * 15 | * @return 16 | */ 17 | public boolean equals(Object o); 18 | 19 | /** 20 | * PluginContextID are used in HashMaps, so this method has to be 21 | * implemented in all its subclasses. 22 | * 23 | * @return 24 | */ 25 | public int hashCode(); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/PluginDescriptorID.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin; 2 | 3 | /** 4 | * This interface provides an ID for each plugin. These IDs are persistent 5 | * between executions of ProM, provided that no code changes are made to the 6 | * plugin in question. 7 | * 8 | * @author bfvdonge 9 | * 10 | */ 11 | public interface PluginDescriptorID extends Comparable { 12 | 13 | /** 14 | * ProvidedObjectIDs are used in Collections, so this method has to be 15 | * implemented in all its subclasses. 16 | * 17 | * @return 18 | */ 19 | public boolean equals(Object o); 20 | 21 | /** 22 | * ProvidedObjectIDs are used in HashMaps, so this method has to be 23 | * implemented in all its subclasses. 24 | * 25 | * @return 26 | */ 27 | public int hashCode(); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/PluginExecutionResult.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin; 2 | 3 | import java.util.concurrent.CancellationException; 4 | import java.util.concurrent.ExecutionException; 5 | 6 | import org.processmining.framework.providedobjects.ProvidedObjectID; 7 | 8 | /** 9 | * This class represents the result of a plugin execution. It can be used to 10 | * obtain all details after executing a plugin. 11 | * 12 | * Typically, plugins are executed a-synchronously, but by calling synchronize() 13 | * on this object, the current thread is suspended untill all results are in (or 14 | * exceptions are thrown) 15 | * 16 | * @author bfvdonge 17 | * 18 | */ 19 | public interface PluginExecutionResult { 20 | 21 | /** 22 | * Returns the size of this result, i.e. how many objects were returned by 23 | * the plugin 24 | * 25 | * @return 26 | */ 27 | public int getSize(); 28 | 29 | /** 30 | * Synchronizes on any futures that might still exist in the result. If no 31 | * futures exist, this method does terminate normally 32 | * 33 | * @throws CancellationException 34 | * @throws ExecutionException 35 | * @throws InterruptedException 36 | */ 37 | public void synchronize() throws CancellationException, ExecutionException, InterruptedException; 38 | 39 | /** 40 | * returns the results of this plugin in an array. If synchronize() was 41 | * called, this method returns the actual objects. Otherwise, it might 42 | * return ProMFutures on the actual objects (or any combination thereof). 43 | * 44 | * @return 45 | */ 46 | public Object[] getResults(); 47 | 48 | /** 49 | * returns the result at the given index, casted to the given returntype. If 50 | * synchronize() was called, this method returns the actual object. 51 | * Otherwise, it might return a ProMFuture on the actual object. 52 | * 53 | * Note that 0<= resultIndex < getSize() 54 | * 55 | * @param 56 | * @param resultIndex 57 | * @return 58 | */ 59 | public T getResult(int resultIndex) throws ClassCastException; 60 | 61 | /** 62 | * This method returns the names of the results 63 | * 64 | * @return 65 | */ 66 | public String[] getResultNames(); 67 | 68 | /** 69 | * this method returns the name of the result at the given index. 70 | * 71 | * Note that 0<= resultIndex < getSize() 72 | * 73 | * @param resultIndex 74 | * @return 75 | */ 76 | public String getResultName(int resultIndex); 77 | 78 | /** 79 | * Tells this result under which provided object ID the object at index i is 80 | * known to the framework 81 | * 82 | * @param i 83 | * index of the object 84 | * @param id 85 | * the id of the provided object refering to the objet at index i 86 | */ 87 | void setProvidedObjectID(int i, ProvidedObjectID id); 88 | 89 | /** 90 | * Returns the ProvidedObjectID under which the object at index i is known 91 | * to the framework's ProvidedObject manager 92 | * 93 | * @param i 94 | * index of the object 95 | */ 96 | ProvidedObjectID getProvidedObjectID(int i); 97 | 98 | /** 99 | * Returns the type of the object at index i, as declared by the plugin 100 | * 101 | * @param i 102 | * @return 103 | */ 104 | public Class getType(int i); 105 | 106 | /** 107 | * Returns the plugin used to generate this result 108 | * 109 | * @return 110 | */ 111 | public PluginDescriptor getPlugin(); 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/ProMCanceller.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin; 2 | 3 | /** 4 | * Interface that can be used by visualizations to receive a notification from 5 | * the framework when they are removed. {@link #isCancelled()} will return true 6 | * in this case. 7 | * 8 | * @author F. Mannhardt, S.J.J Leemans 9 | * 10 | */ 11 | public interface ProMCanceller { 12 | 13 | /** 14 | * {@link ProMCanceller} that never returns true for {@link #isCancelled()} 15 | */ 16 | public final static ProMCanceller NEVER_CANCEL = new ProMCanceller() { 17 | 18 | public boolean isCancelled() { 19 | return false; 20 | } 21 | }; 22 | 23 | boolean isCancelled(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/Progress.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin; 2 | 3 | /** 4 | * Interface for progress indicator 5 | * 6 | * @author bfvdonge 7 | * 8 | */ 9 | public interface Progress { 10 | 11 | void setMinimum(int value); 12 | 13 | void setMaximum(int value); 14 | 15 | void setValue(int value); 16 | 17 | void setCaption(String message); 18 | 19 | String getCaption(); 20 | 21 | int getValue(); 22 | 23 | void inc(); 24 | 25 | void setIndeterminate(boolean makeIndeterminate); 26 | 27 | boolean isIndeterminate(); 28 | 29 | int getMinimum(); 30 | 31 | int getMaximum(); 32 | 33 | boolean isCancelled(); 34 | 35 | void cancel(); 36 | } 37 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/RecursiveCallException.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin; 2 | 3 | public class RecursiveCallException extends Exception { 4 | 5 | private static final long serialVersionUID = -1731740485590676086L; 6 | 7 | public RecursiveCallException(PluginContext context, PluginDescriptor plugin, int methodIndex) { 8 | super("A recursive call to method " + methodIndex + " of plugin " + plugin.getName() 9 | + " was discrovered when creating context " + context.getID() + "."); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/annotations/Bootable.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface Bootable { 11 | } 12 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/annotations/CLI.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface CLI { 11 | String functionName(); 12 | } 13 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/annotations/KeepInProMCache.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Inherited; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * Annotation that is used as a base annotation for all classes that need to be 11 | * kept in cache by the ProM framework. When a class carries this annotation, 12 | * the ProM PluginManager will scan the class during first boot and store the 13 | * class in the cache for future reference. 14 | * 15 | * This allows ProM to build a mapping from annotations to annotated classes 16 | * during boot. 17 | * 18 | * @author bfvdonge 19 | * 20 | */ 21 | 22 | @Target(ElementType.TYPE) 23 | @Retention(RetentionPolicy.RUNTIME) 24 | @Inherited 25 | public @interface KeepInProMCache { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/annotations/Plugin.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ ElementType.METHOD, ElementType.TYPE }) 10 | public @interface Plugin { 11 | 12 | /** 13 | * Returns the name identifying this plugin in a human readable way. 14 | * 15 | * @return 16 | */ 17 | String name(); 18 | 19 | /** 20 | * Returns an Array of strings, such that each String is an initial label 21 | * for a returned object. Plugins can change this label during execution. 22 | * 23 | * The length of the array should be the same as the length of the 24 | * returnTypes array. 25 | * 26 | * @return 27 | */ 28 | String[] returnLabels(); 29 | 30 | /** 31 | * Returns an Array of Class objects, such that each class object represents 32 | * the type of the returned object at that index, i.e. the plugin should 33 | * return as many objects as the length of this array, and each object 34 | * should be of the type given in this array. 35 | * 36 | * @return 37 | */ 38 | Class[] returnTypes(); 39 | 40 | /** 41 | * Returns the labels of the parameters for this plugin. 42 | * 43 | * If the Plugin annotation is used on a method, then the number of elements 44 | * in this array should correspond to the number of parameters that the 45 | * method requires, not counting the first parameter of type PluginContext. 46 | * 47 | * If the plugin annotation is used on a class, then each variant should 48 | * indicate which subset of parameters it requires. Each parameter should 49 | * appear in at least one variant. 50 | * 51 | * Note that the types of the parameters are not specified in the 52 | * annotation. Instead they are derived from the method definitions that 53 | * contain the logic of this plugin. Parameters can be overloaded, i.e. the 54 | * same parameter can have multiple types. 55 | * 56 | * @return 57 | */ 58 | String[] parameterLabels(); 59 | 60 | /** 61 | * Returns the help / description for this plugin. 62 | * 63 | * @return Empty string as default 64 | */ 65 | String help() default ""; 66 | 67 | /** 68 | * Signals the framework to make this plugin user-accessible. If a plugin is 69 | * not user-accessible, it does not show up in any UI 70 | * 71 | * @return Defaults to true. 72 | */ 73 | boolean userAccessible() default true; 74 | 75 | /** 76 | * Returns the index + 1 in the result array of the most significant result 77 | * for this plugin, i.e. if the first element in the array is the most 78 | * significant, then the value of this parameter should be 1. 79 | * 80 | * If the plugin does not return anything interesting itself, but considers 81 | * one of it's inputs to be the most significant one, then a negative value 82 | * should be returned. I.e. if the first parameter is the most significant 83 | * result, a value of -1 has to be returned. Note that this parameter should 84 | * always be included in all variants 85 | * 86 | * @return the index in the result array of the most significant result. If 87 | * no results are returned by this plugin, anything can be returned. 88 | * Defaults to 1 89 | * 90 | */ 91 | int mostSignificantResult() default 1; 92 | 93 | /** 94 | * Whether this plugin handles cancel itself. If this is true, the plug-in 95 | * will not be killed but is allowed to terminate itself by monitoring 96 | * isCancelled. 97 | * 98 | * @return 99 | */ 100 | boolean handlesCancel() default false; 101 | 102 | /** 103 | * Categories define the 'type' of functionality the plugin provides. 104 | */ 105 | PluginCategory[] categories() default { PluginCategory.Analytics }; 106 | 107 | /** 108 | * Keywords / tags for the plugin (extra description) 109 | */ 110 | String[] keywords() default {}; 111 | 112 | /** 113 | * Indication of quality for plug-in. 114 | * @return 115 | */ 116 | PluginQuality quality() default PluginQuality.VeryPoor; 117 | /** 118 | * Indication of level for plug-in. 119 | * @return 120 | */ 121 | PluginLevel level() default PluginLevel.NightlyBuild; 122 | 123 | String icon() default ""; 124 | String url() default ""; 125 | } 126 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/annotations/PluginCategory.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.annotations; 2 | 3 | /** 4 | * Plugin Category 5 | * 6 | * @author mleemans 7 | * 8 | * Possible categories specifying the 'type' of functionality the plugin 9 | * provides. 10 | */ 11 | public enum PluginCategory { 12 | Discovery( // 13 | "Discovery", // 14 | "Discovery plugin constructs a model from a given event log", // 15 | "action_filter_discovery_20x20.png"), // 16 | ConformanceChecking( // 17 | "Conformance Checking", // 18 | "Conformance checking plugin check conformance between a given a model and a given event log", // 19 | "action_filter_conformance_20x20.png"), // 20 | Enhancement( // 21 | "Enhancement", // 22 | "Enhancement plugin enhances a given model using a given log", // 23 | "action_filter_enhancement_20x20.png"), // 24 | Filtering( // 25 | "Filtering", // 26 | "Filtering plugin filters or clusters a given log", // 27 | "action_filter_filtering_20x20.png"), // 28 | Analytics( // 29 | "Analytics", // 30 | "Analytic plugin provides additional analysis for a given log", // 31 | "action_filter_analytics_20x20.png"); 32 | 33 | private final String name; 34 | private final String description; 35 | private final String imageFilterFilename; 36 | 37 | private PluginCategory(String name, String description, String imageFilterFilename) { 38 | this.name = name; 39 | this.description = description; 40 | this.imageFilterFilename = imageFilterFilename; 41 | } 42 | 43 | public String getName() { 44 | return name; 45 | } 46 | 47 | public String getDescription() { 48 | return description; 49 | } 50 | 51 | public String getImageFilterFilename() { 52 | return imageFilterFilename; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/annotations/PluginLevel.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.annotations; 2 | 3 | public enum PluginLevel { 4 | Local( // 5 | "Local", // 6 | 1), // 7 | NightlyBuild( // 8 | "NightlyBuild", // 9 | 2), // 10 | Regular( // 11 | "Regular", // 12 | 3), // 13 | PeerReviewed( // 14 | "PeerReviewed", // 15 | 4), // 16 | BulletProof( // 17 | "BulletProof", // 18 | 5); 19 | 20 | private final String name; 21 | private final int value; 22 | 23 | private PluginLevel(String name, int value) { 24 | this.name = name; 25 | this.value = value; 26 | } 27 | 28 | public String getName() { 29 | return name; 30 | } 31 | 32 | public int getValue() { 33 | return value; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/annotations/PluginQuality.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.annotations; 2 | 3 | public enum PluginQuality { 4 | VeryPoor( // 5 | "VeryPoor", // 6 | 0), // 7 | Poor( // 8 | "Poor", // 9 | 1), // 10 | Fair( // 11 | "Fair", // 12 | 2), // 13 | Good( // 14 | "Good", // 15 | 3), // 16 | VeryGood( // 17 | "VeryGood", // 18 | 4); 19 | 20 | private final String name; 21 | private final int value; 22 | 23 | private PluginQuality(String name, int value) { 24 | this.name = name; 25 | this.value = value; 26 | } 27 | 28 | public String getName() { 29 | return name; 30 | } 31 | 32 | public int getValue() { 33 | return value; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/annotations/PluginVariant.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface PluginVariant { 11 | 12 | /** 13 | * Each plugin variant specifies the required parameter labels in this 14 | * Array. The array should be at most as long as the parameterLabels array 15 | * of the Plugin annotation. Furthermore, all elements of the array should 16 | * be indices in the parametersLabels array of the Plugin annotation and the 17 | * elements should be ordered. 18 | * 19 | * @return 20 | */ 21 | int[] requiredParameterLabels(); 22 | 23 | /** 24 | * This String represents the label of the plugin variant. This label is 25 | * used to identify different variants of the same plugin, specifically when 26 | * multiple variants accept the same parameters of the same types. 27 | */ 28 | String variantLabel() default ""; 29 | 30 | /** 31 | * Returns the help / description for this plugin variant. 32 | * 33 | * @return Empty string as default 34 | */ 35 | String help() default ""; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/events/ConnectionObjectListener.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.events; 2 | 3 | import java.util.EventListener; 4 | 5 | import org.processmining.framework.connections.ConnectionID; 6 | 7 | public interface ConnectionObjectListener extends EventListener { 8 | 9 | public class ListenerList extends ProMEventListenerList { 10 | public void fireConnectionCreated(ConnectionID connectionID) { 11 | for (ConnectionObjectListener listener : getListeners()) { 12 | listener.connectionCreated(connectionID); 13 | } 14 | } 15 | 16 | public void fireConnectionDeleted(ConnectionID id) { 17 | for (ConnectionObjectListener listener : getListeners()) { 18 | listener.connectionDeleted(id); 19 | } 20 | } 21 | 22 | public void fireConnectionUpdated(ConnectionID id) { 23 | for (ConnectionObjectListener listener : getListeners()) { 24 | listener.connectionUpdated(id); 25 | } 26 | } 27 | } 28 | 29 | /** 30 | * This method signals the creation of a connection with the given ID. For 31 | * access to the actual connection, the connectionManager should be used. 32 | * 33 | * @param connectionID 34 | */ 35 | public void connectionCreated(ConnectionID connectionID); 36 | 37 | /** 38 | * This method signals the deletion of a connection with the given ID. For 39 | * access to the actual connection, the connectionManager should be used. 40 | * 41 | * @param connectionID 42 | */ 43 | public void connectionDeleted(ConnectionID connectionID); 44 | 45 | /** 46 | * This method signals that the connection with the given ID was updated. 47 | * For access to the actual connection, the connectionManager should be 48 | * used. 49 | * 50 | * Be aware, that the actual pointers to the objects connected by the 51 | * Connection with the given ID are not changed. Furthermore, it is wise not 52 | * to update connections too often. 53 | * 54 | * @param connectionID 55 | */ 56 | public void connectionUpdated(ConnectionID connectionID); 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/events/FutureListener.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.events; 2 | 3 | import java.util.EventListener; 4 | 5 | import org.processmining.framework.plugin.ProMFuture; 6 | 7 | public interface FutureListener extends EventListener { 8 | 9 | public class ListenerList extends ProMEventListenerList { 10 | public void fireFutureReady(ProMFuture future) { 11 | for (FutureListener listener : getListeners()) { 12 | listener.futureReady(future); 13 | } 14 | } 15 | } 16 | 17 | public void futureReady(ProMFuture future); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/events/Logger.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.events; 2 | 3 | import java.util.EventListener; 4 | 5 | import org.processmining.framework.plugin.PluginContextID; 6 | 7 | public interface Logger extends EventListener { 8 | 9 | public enum MessageLevel { 10 | /** 11 | * Normal message level, for information during runtime 12 | */ 13 | NORMAL(" ", "Normal"), 14 | /** 15 | * Warning message level, for warning messages during runtime 16 | */ 17 | WARNING("W", "Warning"), 18 | /** 19 | * Error message level, for error information during ruintime. Use in 20 | * case error can be recovered from, i.e. not in case of exception 21 | * handling. 22 | */ 23 | ERROR("E", "Error"), 24 | /** 25 | * All TEST messages are omitted in the release version. 26 | */ 27 | TEST("T", "Test"), 28 | /** 29 | * All DEBUG messages are omitted in the release version. 30 | */ 31 | DEBUG("D", "Debug"); 32 | 33 | private final String shortName; 34 | private final String longName; 35 | 36 | MessageLevel(String shortName, String longName) { 37 | this.shortName = shortName; 38 | this.longName = longName; 39 | } 40 | 41 | public String getShortName() { 42 | return shortName; 43 | } 44 | 45 | public String getLongName() { 46 | return longName; 47 | } 48 | } 49 | 50 | public class ListenerList extends ProMEventListenerList { 51 | 52 | public void fireLog(String message, PluginContextID contextID, MessageLevel messageLevel) { 53 | for (Logger listener : getListeners()) { 54 | listener.log(message, contextID, messageLevel); 55 | } 56 | } 57 | 58 | public void fireLog(Throwable t, PluginContextID contextID) { 59 | for (Logger listener : getListeners()) { 60 | listener.log(t, contextID); 61 | } 62 | } 63 | } 64 | 65 | public void log(String message, PluginContextID contextID, MessageLevel messageLevel); 66 | 67 | public void log(Throwable t, PluginContextID contextID); 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/events/NameChangeListener.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.events; 2 | 3 | import java.util.EventListener; 4 | 5 | public interface NameChangeListener extends EventListener { 6 | 7 | public class ListenerList extends ProMEventListenerList { 8 | public void fireNameChanged(String newName) { 9 | for (NameChangeListener listener : getListeners()) { 10 | listener.nameChanged(newName); 11 | } 12 | } 13 | } 14 | 15 | public void nameChanged(String newName); 16 | } 17 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/events/PluginLifeCycleEventListener.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.events; 2 | 3 | import java.util.EventListener; 4 | 5 | import org.processmining.framework.plugin.PluginContext; 6 | 7 | public interface PluginLifeCycleEventListener extends EventListener { 8 | 9 | /** 10 | * This method is invoked on a parent context, if a child context of that 11 | * parent is created. 12 | * 13 | * @param context 14 | * the new Child context 15 | */ 16 | public void pluginCreated(PluginContext context); 17 | 18 | /** 19 | * This method is invoked on a context, if it is started 20 | * 21 | * @param context 22 | * the context 23 | */ 24 | public void pluginStarted(PluginContext context); 25 | 26 | /** 27 | * This method is invoked on a context, if it is suspended 28 | * 29 | * @param context 30 | * the context 31 | */ 32 | public void pluginSuspended(PluginContext context); 33 | 34 | /** 35 | * This method is invoked on a context, if it is resumed 36 | * 37 | * @param context 38 | * the context 39 | */ 40 | public void pluginResumed(PluginContext context); 41 | 42 | /** 43 | * This method is invoked on a context, if it is completed 44 | * 45 | * @param context 46 | * the context 47 | */ 48 | public void pluginCompleted(PluginContext context); 49 | 50 | /** 51 | * This method is invoked on a context, if it is cancelled 52 | * 53 | * @param context 54 | * the context 55 | */ 56 | public void pluginCancelled(PluginContext context); 57 | 58 | /** 59 | * This method is invoked on a context, if it throws an exception 60 | * 61 | * @param context 62 | * the context 63 | */ 64 | public void pluginTerminatedWithError(PluginContext context, Throwable t); 65 | 66 | /** 67 | * This method is invoked on a context, if it's future was set. 68 | * 69 | * @param context 70 | * the context 71 | */ 72 | public void pluginFutureCreated(PluginContext context); 73 | 74 | /** 75 | * This method is invoked on a context, if it's deleted from its parent 76 | * 77 | * @param context 78 | * the context 79 | */ 80 | public void pluginDeleted(PluginContext context); 81 | 82 | public class List extends ProMEventListenerList { 83 | public void firePluginCreated(PluginContext context) { 84 | for (PluginLifeCycleEventListener listener : getListeners()) { 85 | listener.pluginCreated(context); 86 | } 87 | } 88 | 89 | public void firePluginStarted(PluginContext context) { 90 | for (PluginLifeCycleEventListener listener : getListeners()) { 91 | listener.pluginStarted(context); 92 | } 93 | } 94 | 95 | public void firePluginSuspended(PluginContext context) { 96 | for (PluginLifeCycleEventListener listener : getListeners()) { 97 | listener.pluginSuspended(context); 98 | } 99 | } 100 | 101 | public void firePluginResumed(PluginContext context) { 102 | for (PluginLifeCycleEventListener listener : getListeners()) { 103 | listener.pluginResumed(context); 104 | } 105 | } 106 | 107 | public void firePluginCompleted(PluginContext context) { 108 | for (PluginLifeCycleEventListener listener : getListeners()) { 109 | listener.pluginCompleted(context); 110 | } 111 | } 112 | 113 | public void firePluginCancelled(PluginContext context) { 114 | for (PluginLifeCycleEventListener listener : getListeners()) { 115 | listener.pluginCancelled(context); 116 | } 117 | } 118 | 119 | public void firePluginTerminatedWithError(PluginContext context, Throwable t) { 120 | for (PluginLifeCycleEventListener listener : getListeners()) { 121 | listener.pluginTerminatedWithError(context, t); 122 | } 123 | } 124 | 125 | public void firePluginFutureCreated(PluginContext context) { 126 | for (PluginLifeCycleEventListener listener : getListeners()) { 127 | listener.pluginFutureCreated(context); 128 | } 129 | } 130 | 131 | public void firePluginDeleted(PluginContext context) { 132 | for (PluginLifeCycleEventListener listener : getListeners()) { 133 | listener.pluginDeleted(context); 134 | } 135 | } 136 | } 137 | } -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/events/ProMEventListenerList.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.events; 2 | 3 | import java.lang.ref.WeakReference; 4 | import java.util.ArrayList; 5 | import java.util.EventListener; 6 | import java.util.Iterator; 7 | import java.util.List; 8 | 9 | public class ProMEventListenerList { 10 | 11 | private final List> listeners = new ArrayList>(2); 12 | 13 | public void add(T listener) { 14 | synchronized (listeners) { 15 | listeners.add(new WeakReference(listener)); 16 | } 17 | } 18 | 19 | public int getListenerCount() { 20 | return listeners.size(); 21 | } 22 | 23 | protected List getListeners() { 24 | List result = new ArrayList(); 25 | Iterator> it = listeners.iterator(); 26 | while (it.hasNext()) { 27 | T object = it.next().get(); 28 | if (object != null) { 29 | result.add(object); 30 | } else { 31 | it.remove(); 32 | } 33 | } 34 | return result; 35 | } 36 | 37 | public void remove(T listener) { 38 | while (listeners.contains(listener)) { 39 | listeners.remove(listener); 40 | } 41 | } 42 | 43 | public String toString() { 44 | return listeners.toString(); 45 | } 46 | 47 | public void removeAll() { 48 | listeners.clear(); 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/events/ProgressEventListener.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.events; 2 | 3 | import java.util.EventListener; 4 | 5 | public interface ProgressEventListener extends EventListener { 6 | 7 | void changeProgressCaption(String newCaption); 8 | 9 | void changeProgress(int progress); 10 | 11 | void changeProgressBounds(int lowBo, int upBo); 12 | 13 | void changeProgressIndeterminate(boolean indeterminate); 14 | 15 | public class ListenerList extends ProMEventListenerList { 16 | public void fireProgressCaptionChanged(String newCaption) { 17 | for (ProgressEventListener listener : getListeners()) { 18 | listener.changeProgressCaption(newCaption); 19 | } 20 | } 21 | 22 | public void fireProgressChanged(int progress) { 23 | for (ProgressEventListener listener : getListeners()) { 24 | listener.changeProgress(progress); 25 | } 26 | } 27 | 28 | public void fireProgressBoundsChanged(int lowBo, int upBo) { 29 | for (ProgressEventListener listener : getListeners()) { 30 | listener.changeProgressBounds(lowBo, upBo); 31 | } 32 | } 33 | 34 | public void fireProgressIndeterminateChanged(boolean indeterminate) { 35 | for (ProgressEventListener listener : getListeners()) { 36 | listener.changeProgressIndeterminate(indeterminate); 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/events/ProvidedObjectLifeCycleListener.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.events; 2 | 3 | import java.util.EventListener; 4 | 5 | import org.processmining.framework.plugin.PluginContext; 6 | import org.processmining.framework.providedobjects.ProvidedObjectID; 7 | 8 | public interface ProvidedObjectLifeCycleListener extends EventListener { 9 | 10 | public void providedObjectCreated(ProvidedObjectID objectID, PluginContext context); 11 | 12 | public void providedObjectFutureReady(ProvidedObjectID objectID); 13 | 14 | public void providedObjectNameChanged(ProvidedObjectID objectID); 15 | 16 | public void providedObjectObjectChanged(ProvidedObjectID objectID); 17 | 18 | public void providedObjectDeleted(ProvidedObjectID objectID); 19 | 20 | public class ListenerList extends ProMEventListenerList { 21 | public void fireProvidedObjectCreated(ProvidedObjectID objectID, PluginContext context) { 22 | for (ProvidedObjectLifeCycleListener listener : getListeners()) { 23 | listener.providedObjectCreated(objectID, context); 24 | } 25 | } 26 | 27 | public void fireProvidedObjectNameChanged(ProvidedObjectID objectID) { 28 | for (ProvidedObjectLifeCycleListener listener : getListeners()) { 29 | listener.providedObjectNameChanged(objectID); 30 | } 31 | } 32 | 33 | public void fireProvidedObjectObjectChanged(ProvidedObjectID objectID) { 34 | for (ProvidedObjectLifeCycleListener listener : getListeners()) { 35 | listener.providedObjectObjectChanged(objectID); 36 | } 37 | } 38 | 39 | public void fireProvidedObjectDeleted(ProvidedObjectID objectID) { 40 | for (ProvidedObjectLifeCycleListener listener : getListeners()) { 41 | listener.providedObjectDeleted(objectID); 42 | } 43 | } 44 | 45 | public void fireProvidedObjectFutureReady(ProvidedObjectID objectID) { 46 | for (ProvidedObjectLifeCycleListener listener : getListeners()) { 47 | listener.providedObjectFutureReady(objectID); 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/impl/AbstractGlobalContext.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.impl; 2 | 3 | import org.processmining.framework.connections.ConnectionManager; 4 | import org.processmining.framework.connections.impl.ConnectionManagerImpl; 5 | import org.processmining.framework.plugin.GlobalContext; 6 | import org.processmining.framework.plugin.PluginContext; 7 | import org.processmining.framework.plugin.PluginContextID; 8 | import org.processmining.framework.plugin.PluginDescriptor; 9 | import org.processmining.framework.plugin.PluginManager; 10 | import org.processmining.framework.plugin.PluginParameterBinding; 11 | import org.processmining.framework.plugin.events.Logger; 12 | import org.processmining.framework.providedobjects.ProvidedObjectManager; 13 | import org.processmining.framework.providedobjects.impl.ProvidedObjectManagerImpl; 14 | 15 | /** 16 | * Since this context should maintain a link to a single plugin context, and 17 | * PluginContextImpl is abstract, this context is also abstract. 18 | * 19 | * @author bfvdonge 20 | * 21 | */ 22 | public abstract class AbstractGlobalContext implements GlobalContext { 23 | 24 | private final ProvidedObjectManager providedObjectManager = new ProvidedObjectManagerImpl(); 25 | private final ConnectionManager connectionManager = new ConnectionManagerImpl(PluginManagerImpl.getInstance()); 26 | protected final Logger.ListenerList loggingEventListeners = new Logger.ListenerList(); 27 | 28 | public PluginManager getPluginManager() { 29 | return PluginManagerImpl.getInstance(); 30 | } 31 | 32 | public ConnectionManager getConnectionManager() { 33 | return connectionManager; 34 | } 35 | 36 | public ProvidedObjectManager getProvidedObjectManager() { 37 | return providedObjectManager; 38 | } 39 | 40 | public PluginContextID createNewPluginContextID() { 41 | return new PluginContextIDImpl(); 42 | } 43 | 44 | public void invokeBinding(PluginParameterBinding binding, Object... objects) { 45 | 46 | PluginContext c2 = getMainPluginContext().createChildContext(binding.getPlugin().getName()); 47 | 48 | try { 49 | // Create a new providedObject, by passing the future to the 50 | // providedObjectManager; 51 | getMainPluginContext().getPluginLifeCycleEventListeners().firePluginCreated(c2); 52 | binding.invoke(c2, objects); 53 | getProvidedObjectManager().createProvidedObjects(c2); 54 | 55 | } catch (IllegalArgumentException e) { 56 | getMainPluginContext().log(e); 57 | return; 58 | } finally { 59 | c2.getParentContext().deleteChild(c2); 60 | } 61 | 62 | // Since the result is still being calculated, we can only 63 | // use the defaultResultName for the providedObject. 64 | 65 | } 66 | 67 | public void invokePlugin(PluginDescriptor plugin, int index, Object... objects) { 68 | PluginContext c2 = getMainPluginContext().createChildContext(plugin.getName()); 69 | 70 | try { 71 | // Create a new providedObject, by passing the future to the 72 | // providedObjectManager; 73 | getMainPluginContext().getPluginLifeCycleEventListeners().firePluginCreated(c2); 74 | plugin.invoke(index, c2, objects); 75 | getProvidedObjectManager().createProvidedObjects(c2); 76 | 77 | } catch (IllegalArgumentException e) { 78 | getMainPluginContext().log(e); 79 | return; 80 | } finally { 81 | c2.getParentContext().deleteChild(c2); 82 | } 83 | 84 | // Since the result is still being calculated, we can only 85 | // use the defaultResultName for the providedObject. 86 | 87 | } 88 | 89 | protected abstract PluginContext getMainPluginContext(); 90 | 91 | public abstract Class getPluginContextType(); 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/impl/DependsOnUnknownException.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.impl; 2 | 3 | /** 4 | * thrown by the constructor of a plugindescritor if it depends on a plugin not 5 | * yet in the system. 6 | * 7 | * @author bfvdonge 8 | * 9 | */ 10 | public class DependsOnUnknownException extends Exception { 11 | 12 | public DependsOnUnknownException(String message) { 13 | super(message); 14 | } 15 | 16 | private static final long serialVersionUID = 4219323628021104089L; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/impl/FieldNotSetException.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.impl; 2 | 3 | public class FieldNotSetException extends Exception { 4 | 5 | private static final long serialVersionUID = 6942427887070071817L; 6 | 7 | public FieldNotSetException(String fieldName, String message) { 8 | super("Field " + fieldName + " was not yet set. " + message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/impl/FieldSetException.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.impl; 2 | 3 | public class FieldSetException extends Exception { 4 | 5 | private static final long serialVersionUID = 1024657629198603241L; 6 | 7 | public FieldSetException(String fieldName, String message) { 8 | super("Field " + fieldName + " was already set. " + message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/impl/PluginContextIDImpl.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.impl; 2 | 3 | import java.util.UUID; 4 | 5 | import org.processmining.framework.plugin.PluginContextID; 6 | 7 | public class PluginContextIDImpl implements PluginContextID { 8 | 9 | private final UUID id = UUID.randomUUID(); 10 | 11 | public String toString() { 12 | return id.toString(); 13 | } 14 | 15 | public int hashCode() { 16 | return id.hashCode(); 17 | } 18 | 19 | public boolean equals(Object o) { 20 | if (!(o instanceof PluginContextIDImpl)) { 21 | return false; 22 | } else { 23 | return ((PluginContextIDImpl) o).id.equals(id); 24 | } 25 | } 26 | 27 | public int compareTo(PluginContextID o) { 28 | if (!(o instanceof PluginContextIDImpl)) { 29 | // Nasty implementation and not likely to be necessary, 30 | // as the ProvidedObjectManager should take care of not 31 | // using different object as ID. 32 | return PluginContextIDImpl.class.getName().compareTo(o.getClass().getName()); 33 | } else { 34 | return ((PluginContextIDImpl) o).id.compareTo(id); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/impl/PluginDescriptorIDImpl.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.impl; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import org.processmining.framework.plugin.PluginDescriptorID; 6 | 7 | public class PluginDescriptorIDImpl implements PluginDescriptorID { 8 | 9 | private final String id; 10 | 11 | public PluginDescriptorIDImpl(Method pluginMethod) { 12 | String temp = pluginMethod.toGenericString(); 13 | int index = temp.indexOf(" throws "); 14 | if (index >= 0) { 15 | temp = temp.substring(0, index); 16 | } 17 | id = temp; 18 | } 19 | 20 | public PluginDescriptorIDImpl(Class pluginClass) { 21 | id = pluginClass.getName(); 22 | } 23 | 24 | // public PluginDescriptorIDImpl(MacroPluginDescriptorImpl macroPluginDescriptorImpl) { 25 | // id = macroPluginDescriptorImpl.getFileName(); 26 | // } 27 | 28 | public String toString() { 29 | return id; 30 | } 31 | 32 | public int hashCode() { 33 | return id.hashCode(); 34 | } 35 | 36 | public boolean equals(Object o) { 37 | if (!(o instanceof PluginDescriptorIDImpl)) { 38 | return false; 39 | } else { 40 | return ((PluginDescriptorIDImpl) o).id.equals(id); 41 | } 42 | } 43 | 44 | public int compareTo(PluginDescriptorID o) { 45 | if (!(o instanceof PluginDescriptorIDImpl)) { 46 | // Nasty implementation and not likely to be necessary, 47 | // as the ProvidedObjectManager should take care of not 48 | // using different object as ID. 49 | return PluginDescriptorIDImpl.class.getName().compareTo(o.getClass().getName()); 50 | } else { 51 | return ((PluginDescriptorIDImpl) o).id.compareTo(id); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/impl/PluginExecutionResultImpl.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.impl; 2 | 3 | import java.util.Arrays; 4 | import java.util.concurrent.CancellationException; 5 | import java.util.concurrent.ExecutionException; 6 | 7 | import org.processmining.framework.plugin.IncorrectReturnTypeException; 8 | import org.processmining.framework.plugin.PluginDescriptor; 9 | import org.processmining.framework.plugin.PluginExecutionResult; 10 | import org.processmining.framework.plugin.ProMFuture; 11 | import org.processmining.framework.plugin.events.NameChangeListener; 12 | import org.processmining.framework.providedobjects.ProvidedObjectID; 13 | import org.processmining.framework.util.Cast; 14 | 15 | public class PluginExecutionResultImpl implements PluginExecutionResult { 16 | 17 | private Object[] objects; 18 | private Exception exception = null; 19 | private final Class[] returnTypes; 20 | private final String pluginName; 21 | private final String[] returnNames; 22 | private final ProvidedObjectID[] ids; 23 | private Object[] parameters; 24 | private final PluginDescriptor plugin; 25 | 26 | public PluginExecutionResultImpl(Class[] returnTypes, String[] returnNames, PluginDescriptor plugin) { 27 | this.returnNames = returnNames; 28 | this.plugin = plugin; 29 | pluginName = plugin.getName(); 30 | objects = new Object[returnTypes.length]; 31 | ids = new ProvidedObjectID[returnTypes.length]; 32 | this.returnTypes = returnTypes; 33 | Arrays.fill(objects, null); 34 | Arrays.fill(ids, null); 35 | } 36 | 37 | public int getSize() { 38 | return returnNames.length; 39 | } 40 | 41 | void setResult(Object[] objects) throws IncorrectReturnTypeException { 42 | this.objects = objects; 43 | for (int i = 0; i < returnTypes.length; i++) { 44 | if (!returnTypes[i].equals(void.class)) { 45 | if (objects[i] == null) { 46 | continue; 47 | } 48 | Class type = objects[i].getClass(); 49 | if (objects[i] instanceof ProMFuture) { 50 | type = Cast.>cast(objects[i]).getReturnType(); 51 | } 52 | if (!returnTypes[i].isAssignableFrom(type)) { 53 | throw new IncorrectReturnTypeException(pluginName, i, returnTypes[i], objects[i].getClass()); 54 | } 55 | if (objects[i] instanceof ProMFuture) { 56 | final int index = i; 57 | ((ProMFuture) objects[i]).getNameChangeListeners().add(new NameChangeListener() { 58 | 59 | public void nameChanged(String newName) { 60 | returnNames[index] = newName; 61 | } 62 | }); 63 | } 64 | } 65 | } 66 | } 67 | 68 | Object getObject(int resultIndex) { 69 | return objects[resultIndex]; 70 | } 71 | 72 | void setException(Exception t) { 73 | exception = t; 74 | } 75 | 76 | Exception getException() { 77 | return exception; 78 | } 79 | 80 | @SuppressWarnings("unchecked") 81 | public T getResult(int resultIndex) throws ClassCastException { 82 | return (T) getObject(resultIndex); 83 | } 84 | 85 | public String getResultName(int resultIndex) { 86 | synchronized (objects) { 87 | if (getObject(resultIndex) instanceof ProMFuture) { 88 | return Cast.>cast(getObject(resultIndex)).getLabel(); 89 | } else { 90 | return returnNames[resultIndex]; 91 | } 92 | } 93 | } 94 | 95 | public String[] getResultNames() { 96 | return returnNames; 97 | } 98 | 99 | public Object[] getResults() { 100 | return objects; 101 | } 102 | 103 | public void synchronize() throws CancellationException, ExecutionException, InterruptedException { 104 | for (int i = 0; i < objects.length; i++) { 105 | if (objects[i] instanceof ProMFuture) { 106 | Object o = Cast.>cast(objects[i]).get(); 107 | synchronized (objects) { 108 | objects[i] = o; 109 | } 110 | } 111 | } 112 | } 113 | 114 | int getExpectedSize() { 115 | return objects.length; 116 | } 117 | 118 | public void setProvidedObjectID(int i, ProvidedObjectID id) { 119 | ids[i] = id; 120 | } 121 | 122 | public ProvidedObjectID getProvidedObjectID(int i) { 123 | return ids[i]; 124 | } 125 | 126 | public void setInput(Object[] parameters) { 127 | this.parameters = parameters; 128 | } 129 | 130 | public Object[] getParameters() { 131 | return parameters; 132 | } 133 | 134 | @SuppressWarnings("unchecked") 135 | public Class getType(int i) { 136 | return (Class) returnTypes[i]; 137 | } 138 | 139 | public PluginDescriptor getPlugin() { 140 | return plugin; 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /src/org/processmining/framework/plugin/impl/ProgressBarImpl.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.plugin.impl; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.processmining.framework.plugin.PluginContext; 7 | import org.processmining.framework.plugin.PluginExecutionResult; 8 | import org.processmining.framework.plugin.ProMFuture; 9 | import org.processmining.framework.plugin.Progress; 10 | 11 | public class ProgressBarImpl implements Progress { 12 | 13 | private int value = 0; 14 | private int min = 0; 15 | private int max = 1; 16 | private boolean indeterminate = true; 17 | private String message = ""; 18 | 19 | private static final long serialVersionUID = -3950799546173352932L; 20 | private final PluginContext context; 21 | private boolean canceled = false; 22 | 23 | public ProgressBarImpl(PluginContext context) { 24 | this.context = context; 25 | } 26 | 27 | public void setCaption(String message) { 28 | this.message = message; 29 | context.getProgressEventListeners().fireProgressCaptionChanged(message); 30 | } 31 | 32 | public void inc() { 33 | context.getProgressEventListeners().fireProgressChanged(++value); 34 | // Thread.yield(); 35 | } 36 | 37 | public void setMinimum(int value) { 38 | min = value; 39 | context.getProgressEventListeners().fireProgressBoundsChanged(min, max); 40 | } 41 | 42 | public void setMaximum(int value) { 43 | max = value; 44 | context.getProgressEventListeners().fireProgressBoundsChanged(min, max); 45 | } 46 | 47 | public void setValue(int value) { 48 | this.value = value; 49 | context.getProgressEventListeners().fireProgressChanged(value); 50 | // Thread.yield(); 51 | } 52 | 53 | public int getValue() { 54 | return value; 55 | } 56 | 57 | public void setIndeterminate(boolean makeIndeterminate) { 58 | indeterminate = makeIndeterminate; 59 | context.getProgressEventListeners().fireProgressIndeterminateChanged(makeIndeterminate); 60 | } 61 | 62 | public String getCaption() { 63 | return message; 64 | } 65 | 66 | public boolean isIndeterminate() { 67 | return indeterminate; 68 | } 69 | 70 | public int getMaximum() { 71 | return max; 72 | } 73 | 74 | public int getMinimum() { 75 | return min; 76 | } 77 | 78 | public boolean isCancelled() { 79 | PluginExecutionResult results = context.getResult(); 80 | // [HV] To be safe, check the following: 81 | if (results == null) { 82 | return false; 83 | } 84 | for (int i = 0; !canceled && (i < results.getSize()); i++) { 85 | try { 86 | Object o = results.getResult(i); 87 | if (o instanceof ProMFuture) { 88 | return results.>getResult(i).isCancelled(); 89 | } 90 | } catch (Exception e) { 91 | // cancel on fail; 92 | return true; 93 | } 94 | } 95 | return canceled; 96 | } 97 | 98 | public void cancel() { 99 | canceled = true; 100 | // BVD: Cancel all children too! 101 | List children = new ArrayList<>(context.getChildContexts()); 102 | for (PluginContext child : children) { 103 | if (child != null && child.getProgress() != null) { 104 | child.getProgress().cancel(); 105 | } 106 | } 107 | // Now cancel ProMFutures 108 | PluginExecutionResult results = context.getResult(); 109 | for (int i = 0; i < results.getSize(); i++) { 110 | Object o = results.getResult(i); 111 | if (o instanceof ProMFuture) { 112 | results.>getResult(i).cancel(true); 113 | } 114 | } 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/org/processmining/framework/providedobjects/ContextAwareObject.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.providedobjects; 2 | 3 | import org.processmining.framework.connections.ConnectionManager; 4 | import org.processmining.framework.plugin.PluginManager; 5 | 6 | /** 7 | * If an object implements this interface, then this object should use transient 8 | * fields to store pointers to the three managers. 9 | * 10 | * Upon deserialization of the object by the ProM framework, the three methods 11 | * in this interface are called before the object is used and added to the 12 | * framework as a provided object. 13 | * 14 | * Using this interface, objects can instantiate themselves as listeners on the 15 | * relevant parts of the framework that would otherwise only be available upon 16 | * instantiation from a PluginContext. 17 | * 18 | * @author bfvdonge 19 | * 20 | */ 21 | public interface ContextAwareObject { 22 | 23 | public void setManagers(ConnectionManager connectionManager, PluginManager pluginManager, 24 | ProvidedObjectManager providedObjectManager); 25 | } 26 | -------------------------------------------------------------------------------- /src/org/processmining/framework/providedobjects/ProvidedObject.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.providedobjects; 2 | 3 | public interface ProvidedObject { 4 | 5 | /** 6 | * Returns the ID of this Provided Object 7 | * 8 | * @return 9 | */ 10 | ProvidedObjectID getID(); 11 | 12 | /** 13 | * Returns the label of this provided object 14 | * 15 | * @return 16 | */ 17 | String getLabel(); 18 | 19 | /** 20 | * Sets the label of this provided object to the new label. 21 | * 22 | * @param label 23 | * the new label of the object 24 | * @throws ProvidedObjectDeletedException 25 | * If the object was removed from memory because there were no 26 | * useful references to it anymore 27 | */ 28 | void setLabel(String label) throws ProvidedObjectDeletedException; 29 | 30 | /** 31 | * Returns the object stored in this provided object. If the object is not 32 | * an instance of ProMFuture, then the object itself is returned. Otherwise, 33 | * it depends on the parameter whether the ProMFuture is returned, or the 34 | * calling thread is blocked until the future finished (or is cancelled) 35 | * 36 | * @param waitIfFuture 37 | * if set to false, the returned object might be an instance of 38 | * ProMFuture. Otherwise not. 39 | * @return 40 | * @throws ProvidedObjectDeletedException 41 | * If the object was removed from memory because there were no 42 | * useful references to it anymore 43 | */ 44 | Object getObject(boolean waitIfFuture) throws ProvidedObjectDeletedException; 45 | 46 | /** 47 | * Same as calling getObject(true); 48 | * 49 | * @return 50 | * @throws ProvidedObjectDeletedException 51 | * If the object was removed from memory because there were no 52 | * useful references to it anymore 53 | */ 54 | Object getObject() throws ProvidedObjectDeletedException; 55 | 56 | /** 57 | * Changes the content of this provided object by replacing the original 58 | * object with the new object. This can only be done if the current object 59 | * has not been deleted yet. 60 | * 61 | * @param object 62 | * @throws ProvidedObjectDeletedException 63 | * If the object was removed from memory because there were no 64 | * useful references to it anymore 65 | */ 66 | void setObject(Object object) throws ProvidedObjectDeletedException; 67 | 68 | /** 69 | * Returns whether or not this object has been deleted. Note that if this 70 | * method returns false, no ProvidedObjectDeletedExceptions are thrown in 71 | * subsequent, synchronized calls to this provided object. 72 | * 73 | * @return 74 | */ 75 | boolean isDeleted(); 76 | 77 | /** 78 | * Signals the provided object to delete itself. After calling this method, 79 | * isDeleted() will return true and where applicable, 80 | * ProvidedObjectDeletedExceptions will be thrown. 81 | */ 82 | void deleteObject(); 83 | 84 | /** 85 | * Returns the type of the object contained in this Provided Object. If the 86 | * internal object is a ProMFuture, then the result type of the future is 87 | * returned, i.e. ProMFuture.class is never returned by this method. 88 | * 89 | * @return 90 | * @throws ProvidedObjectDeletedException 91 | * If the object was removed from memory because there were no 92 | * useful references to it anymore 93 | */ 94 | Class getType() throws ProvidedObjectDeletedException; 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/org/processmining/framework/providedobjects/ProvidedObjectDeletedException.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.providedobjects; 2 | 3 | public class ProvidedObjectDeletedException extends Exception { 4 | 5 | /** 6 | * 7 | */ 8 | private static final long serialVersionUID = -4591364700388792910L; 9 | 10 | public ProvidedObjectDeletedException(String name) { 11 | super(name); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/org/processmining/framework/providedobjects/ProvidedObjectID.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.providedobjects; 2 | 3 | import org.processmining.framework.ProMID; 4 | 5 | public interface ProvidedObjectID extends ProMID { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/org/processmining/framework/providedobjects/ProvidedObjectManager.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.providedobjects; 2 | 3 | import java.util.List; 4 | 5 | import org.processmining.framework.plugin.PluginContext; 6 | import org.processmining.framework.plugin.events.ProvidedObjectLifeCycleListener; 7 | 8 | public interface ProvidedObjectManager { 9 | 10 | ProvidedObjectLifeCycleListener.ListenerList getProvidedObjectLifeCylceListeners(); 11 | 12 | /** 13 | * This method creates a new providedObjectID. The context passed to this 14 | * method should refer to the PluginContext of which the ProMFuture object 15 | * is the result, i.e. this.getProvidedObjectObject(createProvidedObject( 16 | * String name, PluginContext context)) = context.getFutureResult(); The 17 | * object will be wrapped in a ProMFuture, and a new childContext is created 18 | * for this ProMFuture 19 | * 20 | * @param name 21 | * The label of the providedObject identified by the returned 22 | * ProvidedObjectID (can be retrieved with 23 | * getProvidedObjectLabel() 24 | * @param object 25 | * the object to be wrapped in a new ProMFuture. 26 | * @param type 27 | * the type of the object, 28 | * @return a globally new id, identifying the providedObject 29 | */ 30 | ProvidedObjectID createProvidedObject(String name, T object, Class type, PluginContext context); 31 | 32 | /** 33 | * This method creates a new providedObjectID. The context passed to this 34 | * method should refer to the PluginContext of which the ProMFuture object 35 | * is the result, i.e. this.getProvidedObjectObject(createProvidedObject( 36 | * String name, PluginContext context)) = context.getFutureResult(); The 37 | * object will be wrapped in a ProMFuture, and a new childContext is created 38 | * for this ProMFuture 39 | * 40 | * Note that no type is provided with this method. Instead, the framework 41 | * will use the type of the given object, or if an @SubstitutionType 42 | * annotation was used on the object's class definition, the substitution 43 | * type is used. 44 | * 45 | * @param name 46 | * The label of the providedObject identified by the returned 47 | * ProvidedObjectID (can be retrieved with 48 | * getProvidedObjectLabel() 49 | * @param object 50 | * the object to be wrapped in a new ProMFuture. 51 | * 52 | * @return a globally new id, identifying the providedObject 53 | */ 54 | ProvidedObjectID createProvidedObject(String name, T object, PluginContext context); 55 | 56 | /** 57 | * This method creates a list of new providedObjectIDs for each object in 58 | * the PluginExecutionResult of the context. 59 | * 60 | * @param context 61 | * The context of which this providedObject will be the result 62 | * @return a list of globally new ids, identifying the providedObjects 63 | */ 64 | List createProvidedObjects(PluginContext context); 65 | 66 | /** 67 | * returns the provided object identified by this ID. Do not use this method 68 | * if not necessary, as the providedObject might not exist in memory 69 | * locally. 70 | * 71 | * @param id 72 | * @param waitIfFuture 73 | * TODO 74 | * @return 75 | * @throws ProvidedObjectDeletedException 76 | */ 77 | Object getProvidedObjectObject(ProvidedObjectID id, boolean waitIfFuture) throws ProvidedObjectDeletedException; 78 | 79 | String getProvidedObjectLabel(ProvidedObjectID id) throws ProvidedObjectDeletedException; 80 | 81 | Class getProvidedObjectType(ProvidedObjectID id) throws ProvidedObjectDeletedException; 82 | 83 | void changeProvidedObjectObject(ProvidedObjectID id, Object newObject) throws ProvidedObjectDeletedException; 84 | 85 | void deleteProvidedObject(ProvidedObjectID id) throws ProvidedObjectDeletedException; 86 | 87 | /** 88 | * Returns all provided Object IDs known to the framework. The list is 89 | * ordered in order of Arrival, i.e. the first objectID added to the 90 | * framework is returned first. 91 | * 92 | * @return 93 | */ 94 | List getProvidedObjects(); 95 | 96 | void relabelProvidedObject(ProvidedObjectID id, String label) throws ProvidedObjectDeletedException; 97 | 98 | void setEnabled(boolean enabled); 99 | 100 | boolean isEnabled(); 101 | 102 | void clear(); 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/org/processmining/framework/providedobjects/SubstitutionType.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.providedobjects; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.TYPE) 10 | public @interface SubstitutionType { 11 | Class substitutedType(); 12 | } 13 | -------------------------------------------------------------------------------- /src/org/processmining/framework/providedobjects/impl/ProvidedObjectIDImpl.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.providedobjects.impl; 2 | 3 | import java.util.UUID; 4 | 5 | import org.processmining.framework.ProMID; 6 | import org.processmining.framework.providedobjects.ProvidedObjectID; 7 | 8 | public class ProvidedObjectIDImpl implements ProvidedObjectID { 9 | 10 | private final UUID id = UUID.randomUUID(); 11 | 12 | public String toString() { 13 | return id.toString(); 14 | } 15 | 16 | public int hashCode() { 17 | return id.hashCode(); 18 | } 19 | 20 | public boolean equals(Object o) { 21 | if (!(o instanceof ProvidedObjectIDImpl)) { 22 | return false; 23 | } else { 24 | return ((ProvidedObjectIDImpl) o).id.equals(id); 25 | } 26 | } 27 | 28 | public boolean equalsIgnoreType(Object o) { 29 | return toString().equals(o.toString()); 30 | } 31 | 32 | public int compareTo(ProMID o) { 33 | return o.getUUID().compareTo(id); 34 | } 35 | 36 | public UUID getUUID() { 37 | return id; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/org/processmining/framework/providedobjects/impl/ProvidedObjectManagerImpl.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.providedobjects.impl; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | 8 | import org.processmining.framework.plugin.PluginContext; 9 | import org.processmining.framework.plugin.PluginExecutionResult; 10 | import org.processmining.framework.plugin.ProMFuture; 11 | import org.processmining.framework.plugin.events.ProvidedObjectLifeCycleListener; 12 | import org.processmining.framework.providedobjects.ProvidedObject; 13 | import org.processmining.framework.providedobjects.ProvidedObjectDeletedException; 14 | import org.processmining.framework.providedobjects.ProvidedObjectID; 15 | import org.processmining.framework.providedobjects.ProvidedObjectManager; 16 | import org.processmining.framework.providedobjects.SubstitutionType; 17 | 18 | public class ProvidedObjectManagerImpl implements ProvidedObjectManager { 19 | 20 | private final ProvidedObjectLifeCycleListener.ListenerList providedObjectLifeCycleListeners = new ProvidedObjectLifeCycleListener.ListenerList(); 21 | private final HashMap localProvidedObjects; 22 | private final List ids; 23 | 24 | private boolean enabled = true; 25 | 26 | public ProvidedObjectManagerImpl() { 27 | localProvidedObjects = new HashMap(); 28 | ids = new ArrayList(); 29 | } 30 | 31 | public ProvidedObjectLifeCycleListener.ListenerList getProvidedObjectLifeCylceListeners() { 32 | return providedObjectLifeCycleListeners; 33 | } 34 | 35 | @SuppressWarnings("unchecked") 36 | public ProvidedObjectID createProvidedObject(String label, T object, PluginContext context) { 37 | Class realType; 38 | if (object instanceof ProMFuture) { 39 | realType = ((ProMFuture) object).getReturnType(); 40 | } else { 41 | realType = object.getClass(); 42 | } 43 | if (realType.isAnnotationPresent(SubstitutionType.class)) { 44 | Class declaredType = realType.getAnnotation(SubstitutionType.class).substitutedType(); 45 | if (declaredType.isAssignableFrom(realType)) { 46 | realType = declaredType; 47 | } 48 | } 49 | return createProvidedObject(label, object, (Class) realType, context); 50 | } 51 | 52 | public ProvidedObjectID createProvidedObject(String label, T object, Class type, 53 | PluginContext context) { 54 | 55 | // construct a new ProvidedObject 56 | ProvidedObjectImpl po = new ProvidedObjectImpl(label, new ProvidedObjectIDImpl(), object, type, this); 57 | 58 | if (enabled) { 59 | // add it to the list of maintained PO's 60 | localProvidedObjects.put(po.getID(), po); 61 | ids.add(po.getID()); 62 | providedObjectLifeCycleListeners.fireProvidedObjectCreated(po.getID(), context); 63 | if (!(object instanceof ProMFuture)) { 64 | providedObjectLifeCycleListeners.fireProvidedObjectFutureReady(po.getID()); 65 | } else { 66 | try { 67 | po.setLabel(((ProMFuture) object).toString()); 68 | } catch (ProvidedObjectDeletedException e) { 69 | assert (false); 70 | } 71 | } 72 | } 73 | return po.getID(); 74 | 75 | } 76 | 77 | public List createProvidedObjects(PluginContext context) { 78 | List newIds = new ArrayList(); 79 | PluginExecutionResult result = context.getResult(); 80 | for (int i = 0; i < result.getSize(); i++) { 81 | ProvidedObjectID id = createProvidedObject(result.getResultName(i), result.getResult(i), result.getType(i), 82 | context); 83 | newIds.add(id); 84 | // ids.add(id); 85 | result.setProvidedObjectID(i, id); 86 | } 87 | return newIds; 88 | } 89 | 90 | private ProvidedObjectImpl getProvidedObject(ProvidedObjectID id) throws ProvidedObjectDeletedException { 91 | ProvidedObjectImpl po = localProvidedObjects.get(id); 92 | if (po == null) { 93 | throw new ProvidedObjectDeletedException("ProvidedObject with ID " + id + " is not known to the manager."); 94 | } 95 | return po; 96 | } 97 | 98 | public Object getProvidedObjectObject(ProvidedObjectID id, boolean waitIfFuture) 99 | throws ProvidedObjectDeletedException { 100 | ProvidedObject po = getProvidedObject(id); 101 | return po.getObject(waitIfFuture); 102 | } 103 | 104 | public String getProvidedObjectLabel(ProvidedObjectID id) throws ProvidedObjectDeletedException { 105 | ProvidedObject po = getProvidedObject(id); 106 | return po.getLabel(); 107 | } 108 | 109 | public Class getProvidedObjectType(ProvidedObjectID id) throws ProvidedObjectDeletedException { 110 | ProvidedObject po = getProvidedObject(id); 111 | return po.getType(); 112 | } 113 | 114 | public void changeProvidedObjectObject(ProvidedObjectID id, Object newObject) throws ProvidedObjectDeletedException { 115 | ProvidedObject po = getProvidedObject(id); 116 | po.setObject(newObject); 117 | } 118 | 119 | public void deleteProvidedObject(ProvidedObjectID id) throws ProvidedObjectDeletedException { 120 | ProvidedObjectImpl po = getProvidedObject(id); 121 | localProvidedObjects.remove(id); 122 | ids.remove(id); 123 | po.deleteObject(); 124 | } 125 | 126 | public List getProvidedObjects() { 127 | return Collections.unmodifiableList(ids); 128 | } 129 | 130 | public void relabelProvidedObject(ProvidedObjectID id, String label) throws ProvidedObjectDeletedException { 131 | getProvidedObject(id).setLabel(label); 132 | } 133 | 134 | public void providedObjectNameChanged(ProvidedObjectID objectID) { 135 | // Ignore 136 | } 137 | 138 | public void providedObjectObjectChanged(ProvidedObjectID objectID) { 139 | // Ignore 140 | } 141 | 142 | public void setEnabled(boolean enabled) { 143 | this.enabled = enabled; 144 | } 145 | 146 | public boolean isEnabled() { 147 | return enabled; 148 | } 149 | 150 | public void clear() { 151 | localProvidedObjects.clear(); 152 | ids.clear(); 153 | providedObjectLifeCycleListeners.removeAll(); 154 | } 155 | 156 | 157 | } 158 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/ArrayUtils.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util; 2 | 3 | import java.lang.reflect.Array; 4 | 5 | public class ArrayUtils { 6 | 7 | /** 8 | * No need for instantiation. Only static methods 9 | * 10 | */ 11 | private ArrayUtils() { 12 | 13 | } 14 | 15 | /** 16 | * Makes a copy of an array. If newLength is greater than the length of 17 | * source, then the result is an array with the contents of source, appended 18 | * with null elements. If the new array is shorter, then only a part is 19 | * copied. 20 | * 21 | * @param 22 | * type of the array 23 | * @param source 24 | * source array 25 | * @param newlength 26 | * new length of the target array 27 | * @return 28 | */ 29 | @SuppressWarnings("unchecked") 30 | public static T[] copyOf(T[] source, int newlength) { 31 | Class type = source.getClass().getComponentType(); 32 | T[] target = (T[]) Array.newInstance(type, newlength); 33 | System.arraycopy(source, 0, target, 0, Math.min(newlength, source.length)); 34 | for (int i = source.length; i < target.length; i++) { 35 | target[i] = null; 36 | } 37 | return target; 38 | 39 | } 40 | 41 | /** 42 | * Concatenates arrays 43 | * 44 | * @param 45 | * type of the array 46 | * @param first 47 | * first array 48 | * @param rest 49 | * arrays to be added 50 | * @return 51 | */ 52 | public static T[] concatAll(T[] first, T[]... rest) { 53 | 54 | int totalLength = first.length; 55 | for (T[] array : rest) { 56 | totalLength += array.length; 57 | } 58 | T[] result = copyOf(first, totalLength); 59 | int offset = first.length; 60 | for (T[] array : rest) { 61 | System.arraycopy(array, 0, result, offset, array.length); 62 | offset += array.length; 63 | } 64 | return result; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/AutoHelpCommandLineParser.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util; 2 | 3 | import jargs.gnu.CmdLineParser; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.LinkedList; 8 | import java.util.List; 9 | 10 | public class AutoHelpCommandLineParser extends CmdLineParser { 11 | private final List> optionHelpStrings = new ArrayList>(); 12 | private final String programName; 13 | private final Command[] commands; 14 | 15 | public static abstract class Command { 16 | private final String name; 17 | private final String help; 18 | 19 | public Command(String name, String help) { 20 | this.name = name; 21 | this.help = help; 22 | } 23 | 24 | public abstract int run(List args) throws Exception; 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public String getHelp() { 31 | return help; 32 | } 33 | } 34 | 35 | public AutoHelpCommandLineParser(String programName) { 36 | this(programName, null); 37 | } 38 | 39 | public AutoHelpCommandLineParser(String programName, Command[] commands) { 40 | this.programName = programName; 41 | this.commands = commands; 42 | } 43 | 44 | public Option addHelp(Option option, String helpString) { 45 | optionHelpStrings.add(new Pair(option, helpString)); 46 | return option; 47 | } 48 | 49 | public void printUsage() { 50 | if (commands != null) { 51 | System.err.println("Usage: " + programName + " [options] COMMAND [command arguments]"); 52 | } else { 53 | System.err.println("Usage: " + programName + " [options]"); 54 | } 55 | 56 | int width = 0; 57 | for (Pair option : optionHelpStrings) { 58 | width = Math.max(width, getOptionString(option).length()); 59 | } 60 | width = Math.min(25, width); 61 | 62 | for (Pair option : optionHelpStrings) { 63 | System.err.println(String.format(" %-" + width + "s %s", getOptionString(option), option.getSecond())); 64 | } 65 | 66 | if (commands != null) { 67 | width = 0; 68 | 69 | for (Command c : commands) { 70 | width = Math.max(width, c.getName().length()); 71 | } 72 | width = Math.min(25, width); 73 | 74 | System.err.println("The following commands are available:"); 75 | for (Command c : commands) { 76 | System.err.println(String.format(" %-" + width + "s %s", c.getName(), c.getHelp())); 77 | } 78 | } 79 | } 80 | 81 | private String getOptionString(Pair option) { 82 | return "-" + option.getFirst().shortForm() + " / --" + option.getFirst().longForm(); 83 | } 84 | 85 | public int runCommand() throws Exception { 86 | LinkedList arguments = new LinkedList(Arrays.asList(getRemainingArgs())); 87 | String commandName = arguments.removeFirst(); 88 | 89 | for (Command c : commands) { 90 | if (c.getName().equals(commandName)) { 91 | return c.run(arguments); 92 | } 93 | } 94 | return -1; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/Cast.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util; 2 | 3 | public class Cast { 4 | 5 | private Cast() { 6 | 7 | } 8 | 9 | /** 10 | * Casts the given object to type T. This static method can be used to avoid 11 | * "unchecked cast" warnings. Note that a runtime exception is still thrown 12 | * if the cast is not valid. However, using this method eliminates the use 13 | * of the @@SupressWarnings annotation, which obfuscates any valid warnings. 14 | * Note that this method should be used in combination with assertions to 15 | * assert the right type! 16 | * 17 | * @param 18 | * The type to cast to. 19 | * @param x 20 | * the object to cast 21 | * @return (T) x; 22 | */ 23 | @SuppressWarnings("unchecked") 24 | public static T cast(Object x) { 25 | return (T) x; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/Cleanable.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util; 2 | 3 | public interface Cleanable { 4 | 5 | void cleanUp(); 6 | } 7 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/CommandLineArgumentList.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class CommandLineArgumentList extends ArrayList { 6 | 7 | private static final long serialVersionUID = -1574623826051169007L; 8 | 9 | public String[] toStringArray() { 10 | return toArray(new String[0]); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/HTMLToString.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util; 2 | 3 | import java.awt.Color; 4 | import java.awt.Component; 5 | 6 | import javax.swing.JLabel; 7 | import javax.swing.JList; 8 | import javax.swing.ListCellRenderer; 9 | 10 | public interface HTMLToString { 11 | 12 | public String toHTMLString(boolean includeHTMLTags); 13 | 14 | public static class HTMLCellRenderer extends JLabel implements ListCellRenderer { 15 | /** 16 | * 17 | */ 18 | private static final long serialVersionUID = -808355468668630456L; 19 | 20 | public HTMLCellRenderer() { 21 | setOpaque(true); 22 | } 23 | 24 | public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, 25 | boolean cellHasFocus) { 26 | 27 | if (value instanceof HTMLToString) { 28 | setText(Cast.cast(value).toHTMLString(true)); 29 | } else { 30 | setText(value.toString()); 31 | } 32 | 33 | setBackground(isSelected ? Color.RED : Color.WHITE); 34 | setForeground(isSelected ? Color.WHITE : Color.BLACK); 35 | return this; 36 | 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/IconLoader.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util; 2 | 3 | import java.io.File; 4 | import java.net.MalformedURLException; 5 | 6 | import javax.swing.ImageIcon; 7 | 8 | import org.processmining.framework.boot.Boot; 9 | 10 | public class IconLoader { 11 | 12 | public static ImageIcon getStandardIcon(String name) { 13 | String imgLocation = "toolbarButtonGraphics/" + name + ".gif"; 14 | java.net.URL imageURL = Thread.currentThread().getContextClassLoader().getResource(imgLocation); 15 | 16 | return new ImageIcon(imageURL); 17 | } 18 | 19 | public static ImageIcon getProMLibIcon(String name) { 20 | try { 21 | File file = new File(Boot.IMAGES_FOLDER + File.separator + name + ".gif"); 22 | java.net.URL imageURL = file.toURI().toURL(); 23 | return new ImageIcon(imageURL); 24 | } catch (MalformedURLException e) { 25 | // TODO Auto-generated catch block 26 | e.printStackTrace(); 27 | } 28 | return null; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/LevenshteinDistance.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author R.P. Jagadeesh Chandra 'JC' Bose 7 | * @date 08 July 2010 8 | * @since 01 June 2009 9 | * @version 1.0 10 | * @email j.c.b.rantham.prabhakara@tue.nl 11 | * @copyright R.P. Jagadeesh Chandra 'JC' Bose 12 | * Architecture of Information Systems Group (AIS) 13 | * Department of Mathematics and Computer Science 14 | * University of Technology, Eindhoven, The Netherlands 15 | */ 16 | 17 | public class LevenshteinDistance{ 18 | int encodingLength; 19 | float[][] distanceMatrix; 20 | 21 | public LevenshteinDistance(int encodingLength, List charStreamList){ 22 | this.encodingLength = encodingLength; 23 | int noTraces = charStreamList.size(); 24 | distanceMatrix = new float[noTraces][noTraces]; 25 | computeLevenshteinDistanceLinearSpace(charStreamList); 26 | } 27 | 28 | public LevenshteinDistance(){ 29 | this.encodingLength = 1; 30 | } 31 | 32 | protected void computeLevenshteinDistanceLinearSpace(List charStreams){ 33 | int noCharStreams = charStreams.size(); 34 | 35 | String seq1, seq2; 36 | int lengthSeq1, lengthSeq2, maxLength, dist; 37 | float distanceNorm1; 38 | 39 | for(int i = 0; i < noCharStreams; i++){ 40 | 41 | seq1 = charStreams.get(i); 42 | lengthSeq1 = seq1.length()/encodingLength; 43 | 44 | for(int j = 0; j < i; j++){ 45 | seq2 = charStreams.get(j); 46 | 47 | if(seq1.equals(seq2)){ 48 | distanceNorm1 = 0; 49 | }else{ 50 | 51 | lengthSeq2 = seq2.length()/encodingLength; 52 | 53 | maxLength = lengthSeq1; 54 | if(lengthSeq2 > maxLength) 55 | maxLength = lengthSeq2; 56 | 57 | dist = getLevenshteinDistanceLinearSpace(seq1, seq2); 58 | distanceNorm1 = dist/(float)(lengthSeq1+lengthSeq2); 59 | } 60 | 61 | distanceMatrix[i][j] = distanceNorm1; 62 | distanceMatrix[j][i] = distanceNorm1; 63 | 64 | } 65 | } 66 | } 67 | 68 | public int getLevenshteinDistanceLinearSpace(String seq1, String seq2){ 69 | 70 | String sI, tJ; 71 | int lengthSeq1, lengthSeq2, cost; 72 | 73 | 74 | lengthSeq1 = seq1.length()/encodingLength; 75 | lengthSeq2 = seq2.length()/encodingLength; 76 | 77 | int[] S = new int[lengthSeq2+1]; 78 | 79 | S[0] = 0; 80 | S[1] = S[0] + 1; //Insert first symbol 81 | for(int j = 2; j <= lengthSeq2; j++){ 82 | S[j] = S[j-1]+1; 83 | } 84 | 85 | int s,c; 86 | for(int i = 1; i <= lengthSeq1; i++){ 87 | s = S[0]; 88 | S[0] = c = S[0]+ 1; //Insertion of first symbol 89 | sI = seq1.substring((i-1)*encodingLength, i*encodingLength); 90 | for(int j = 1; j <= lengthSeq2; j++){ 91 | tJ = seq2.substring((j-1)*encodingLength, j*encodingLength); 92 | 93 | cost = 0; 94 | if(!sI.equals(tJ)) 95 | cost = 1; 96 | c = Minimum(S[j]+1, s+cost, c+1); 97 | s = S[j]; 98 | S[j] = c; 99 | } 100 | } 101 | 102 | return S[lengthSeq2]; 103 | 104 | } 105 | 106 | private int Minimum(int a, int b, int c) { 107 | int mi; 108 | 109 | mi = a; 110 | if (b < mi) { 111 | mi = b; 112 | } 113 | if (c < mi) { 114 | mi = c; 115 | } 116 | return mi; 117 | 118 | } 119 | 120 | public float[][] getDistanceMatrix(){ 121 | return distanceMatrix; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/Pair.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util; 2 | 3 | public class Pair { 4 | 5 | protected final S second; 6 | protected final F first; 7 | 8 | public Pair(F first, S second) { 9 | this.first = first; 10 | this.second = second; 11 | } 12 | 13 | public F getFirst() { 14 | return first; 15 | } 16 | 17 | public S getSecond() { 18 | return second; 19 | } 20 | 21 | private static boolean equals(Object x, Object y) { 22 | return ((x == null) && (y == null)) || ((x != null) && x.equals(y)); 23 | } 24 | 25 | @SuppressWarnings("unchecked") 26 | @Override 27 | public boolean equals(Object other) { 28 | return (other instanceof Pair) && equals(first, ((Pair) other).first) 29 | && equals(second, ((Pair) other).second); 30 | } 31 | 32 | @Override 33 | public int hashCode() { 34 | if (first == null) { 35 | return second == null ? 0 : second.hashCode() + 1; 36 | } else { 37 | return second == null ? first.hashCode() + 2 : first.hashCode() * 17 + second.hashCode(); 38 | } 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "(" + first + "," + second + ")"; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/PathHacker.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util; 2 | 3 | import java.io.File; 4 | import java.lang.reflect.Field; 5 | import java.lang.reflect.Method; 6 | import java.net.URL; 7 | import java.net.URLClassLoader; 8 | import java.util.Properties; 9 | 10 | /** 11 | * Dynamically adds jars or dll files at runtime to the environment for direct 12 | * use 13 | * 14 | * @author T. van der Wiel 15 | * 16 | */ 17 | public class PathHacker { 18 | @SuppressWarnings("unchecked") 19 | private static final Class[] parameters = new Class[] { URL.class }; 20 | 21 | /** 22 | * ensures the given path is in java.library.path 23 | * 24 | * @param path 25 | * @throws Exception 26 | */ 27 | public static void addLibPath(String path) throws Exception { 28 | File file = new File(path); 29 | // Append the specified path to the existing java.library.path (if there is one already) 30 | String newLibraryPath = System.getProperty("java.library.path"); 31 | if ((newLibraryPath == null) || (newLibraryPath.length() < 1)) { 32 | newLibraryPath = file.getCanonicalPath(); 33 | } else if (newLibraryPath.contains(file.getCanonicalPath())) { 34 | return; 35 | } else { 36 | newLibraryPath += File.pathSeparator + file.getCanonicalPath(); 37 | } 38 | 39 | // Reflect into java.lang.System to get the static Properties reference 40 | Field f = System.class.getDeclaredField("props"); 41 | f.setAccessible(true); 42 | Properties props = (Properties) f.get(null); 43 | // replace the java.library.path with our new one 44 | props.put("java.library.path", newLibraryPath); 45 | 46 | // The classLoader may have already been initialized, so it needs to be fixed up. 47 | // Reflect into java.lang.ClassLoader to get the static String[] of user paths to native libraries 48 | Field usr_pathsField = ClassLoader.class.getDeclaredField("usr_paths"); 49 | usr_pathsField.setAccessible(true); 50 | String[] usr_paths = (String[]) usr_pathsField.get(null); 51 | String[] newUsr_paths = new String[usr_paths == null ? 1 : usr_paths.length + 1]; 52 | if (usr_paths != null) { 53 | System.arraycopy(usr_paths, 0, newUsr_paths, 0, usr_paths.length); 54 | } 55 | // Add the specified path to the end of a new String[] of user paths to native libraries 56 | newUsr_paths[newUsr_paths.length - 1] = file.getAbsolutePath(); 57 | usr_pathsField.set(null, newUsr_paths); 58 | } 59 | 60 | public static void addLibraryPathFromDirectory(File dir) { 61 | if (!dir.exists() || !dir.isDirectory() || !dir.canRead()) { 62 | return; 63 | } 64 | 65 | for (File f : dir.listFiles()) { 66 | if (f.isDirectory()) { 67 | try { 68 | addLibPath(f.getAbsolutePath()); 69 | } catch (Exception e) { 70 | // Failed, no big deal 71 | } 72 | addLibraryPathFromDirectory(f); 73 | } else { 74 | //skip 75 | } 76 | } 77 | } 78 | 79 | // /** 80 | // * tries to load the given file to the runtime environment 81 | // * @param file 82 | // * @throws IOException if an UnsatisfiedLinkError occurs 83 | // * @throws SecurityException if a security manager exists and its checkLink method doesn't allow loading of the specified dynamic library 84 | // * @throws UnsatisfiedLinkError if the file does not exist. 85 | // * @throws NullPointerException if filename is null 86 | // */ 87 | // public static void addLib(String file) throws Exception { 88 | // try { 89 | // Runtime.getRuntime().load(file); 90 | // } catch(UnsatisfiedLinkError e) { 91 | // throw new IOException("UnsatisfiedLinkError"); 92 | // } 93 | // } 94 | 95 | public static void addJar(String s) { 96 | File f = new File(s); 97 | addJar(f); 98 | } 99 | 100 | public static void addJar(File f) { 101 | try { 102 | // File.toURL() was deprecated, so use File.toURI().toURL() 103 | addJar(f.toURI().toURL()); 104 | } catch (Exception e) { 105 | e.printStackTrace(); 106 | } 107 | } 108 | 109 | /** 110 | * Adds the given URL to the classpath for direct use 111 | * 112 | * @param URL 113 | * of the Java Archive 114 | */ 115 | public static void addJar(URL u) { 116 | URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 117 | for (URL u2 : sysloader.getURLs()) { 118 | if (u.equals(u2)) { 119 | return; 120 | } 121 | } 122 | try { 123 | /* Class was uncheched, so used URLClassLoader.class instead */ 124 | Method method = URLClassLoader.class.getDeclaredMethod("addURL", parameters); 125 | method.setAccessible(true); 126 | method.invoke(sysloader, new Object[] { u }); 127 | } catch (Exception e) { 128 | e.printStackTrace(); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/ProMClassLoader.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util; 2 | 3 | import java.io.File; 4 | import java.net.MalformedURLException; 5 | import java.net.URL; 6 | import java.net.URLClassLoader; 7 | 8 | public class ProMClassLoader extends URLClassLoader { 9 | 10 | public ProMClassLoader(ClassLoader loader) { 11 | super(getClassPathURLs(), loader); 12 | // super(new URL[] { }, loader); 13 | } 14 | 15 | /* 16 | * Returns the URLs of all (absolute) paths as found in the current class path. 17 | */ 18 | private static URL[] getClassPathURLs() { 19 | // Get the current class path. 20 | String classpath = System.getProperty("java.class.path"); 21 | // Get the current path separator. 22 | String separator = System.getProperty("path.separator"); 23 | // Separate the paths in the class path. 24 | String[] paths = classpath.split(separator); 25 | // Convert every entry into a URL. Assume absolute paths in class path. 26 | URL[] urls = new URL[paths.length]; 27 | for (int i = 0; i < paths.length; i++) { 28 | try { 29 | // Convert this path into a proper URL. 30 | urls[i] = new File(paths[i]).toURI().toURL(); 31 | System.out.println("[ProMClassLoader] found in classpath: " + urls[i]); 32 | } catch (MalformedURLException e) { 33 | System.err.println("[ProMClassLoader] " + e.getMessage()); 34 | } 35 | } 36 | return urls; 37 | } 38 | 39 | // protected Class findClass(String name) throws ClassNotFoundException { 40 | // System.err.println("[ProMClassLoader] Find class " + name); 41 | // return super.findClass(name); 42 | // } 43 | 44 | // @Override public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { 45 | // System.out.println("[ProMClassLoader] Load class " + name); 46 | // return super.loadClass(name, resolve); 47 | // } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/StringUtils.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util; 2 | 3 | public class StringUtils { 4 | 5 | private StringUtils() { 6 | 7 | } 8 | 9 | public static String getJavaIdentifier(String name) { 10 | StringBuffer result = new StringBuffer(); 11 | boolean underscoreAdded = false; 12 | 13 | name = name.toLowerCase().trim(); 14 | for (int i = 0; i < name.length(); i++) { 15 | char c = name.charAt(i); 16 | if ((('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')) 17 | || ((result.length() > 0) && ('0' <= c) && (c <= '9'))) { 18 | result.append(c); 19 | underscoreAdded = false; 20 | } else if (!underscoreAdded) { 21 | result.append("_"); 22 | underscoreAdded = true; 23 | } 24 | } 25 | return result.toString(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/collection/AlphanumComparator.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.collection; 2 | 3 | /* 4 | * The Alphanum Algorithm is an improved sorting algorithm for strings 5 | * containing numbers. Instead of sorting numbers in ASCII order like a standard 6 | * sort, this algorithm sorts numbers in numeric order. 7 | * 8 | * The Alphanum Algorithm is discussed at http://www.DaveKoelle.com 9 | * 10 | * 11 | * This library is free software; you can redistribute it and/or modify it under 12 | * the terms of the GNU Lesser General Public License as published by the Free 13 | * Software Foundation; either version 2.1 of the License, or any later version. 14 | * 15 | * This library is distributed in the hope that it will be useful, but WITHOUT 16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 18 | * details. 19 | * 20 | * You should have received a copy of the GNU Lesser General Public License 21 | * along with this library; if not, write to the Free Software Foundation, Inc., 22 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 23 | */ 24 | 25 | import java.util.Comparator; 26 | 27 | /** 28 | * This is an updated version with enhancements made by Daniel Migowski, Andre 29 | * Bogus, and David Koelle 30 | * 31 | * To convert to use Templates (Java 1.5+): - Change "implements Comparator" to 32 | * "implements Comparator" - Change "compare(Object o1, Object o2)" to 33 | * "compare(String s1, String s2)" - Remove the type checking and casting in 34 | * compare(). 35 | * 36 | * To use this class: Use the static "sort" method from the 37 | * java.util.Collections class: Collections.sort(your list, new 38 | * AlphanumComparator()); 39 | */ 40 | public class AlphanumComparator implements Comparator { 41 | private final boolean isDigit(char ch) { 42 | return ch >= 48 && ch <= 57; 43 | } 44 | 45 | /** 46 | * Length of string is passed in for improved efficiency (only need to 47 | * calculate it once) 48 | **/ 49 | private final String getChunk(String s, int slength, int marker) { 50 | StringBuilder chunk = new StringBuilder(); 51 | char c = s.charAt(marker); 52 | chunk.append(c); 53 | marker++; 54 | if (isDigit(c)) { 55 | while (marker < slength) { 56 | c = s.charAt(marker); 57 | if (!isDigit(c)) 58 | break; 59 | chunk.append(c); 60 | marker++; 61 | } 62 | } else { 63 | while (marker < slength) { 64 | c = s.charAt(marker); 65 | if (isDigit(c)) 66 | break; 67 | chunk.append(c); 68 | marker++; 69 | } 70 | } 71 | return chunk.toString(); 72 | } 73 | 74 | public int compare(String s1, String s2) { 75 | int thisMarker = 0; 76 | int thatMarker = 0; 77 | int s1Length = s1.length(); 78 | int s2Length = s2.length(); 79 | 80 | while (thisMarker < s1Length && thatMarker < s2Length) { 81 | String thisChunk = getChunk(s1, s1Length, thisMarker); 82 | thisMarker += thisChunk.length(); 83 | 84 | String thatChunk = getChunk(s2, s2Length, thatMarker); 85 | thatMarker += thatChunk.length(); 86 | 87 | // If both chunks contain numeric characters, sort them numerically 88 | int result = 0; 89 | if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) { 90 | // Simple chunk comparison by length. 91 | int thisChunkLength = thisChunk.length(); 92 | result = thisChunkLength - thatChunk.length(); 93 | // If equal, the first different number counts 94 | if (result == 0) { 95 | for (int i = 0; i < thisChunkLength; i++) { 96 | result = thisChunk.charAt(i) - thatChunk.charAt(i); 97 | if (result != 0) { 98 | return result; 99 | } 100 | } 101 | } 102 | } else { 103 | result = thisChunk.compareTo(thatChunk); 104 | } 105 | 106 | if (result != 0) 107 | return result; 108 | } 109 | 110 | return s1Length - s2Length; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/collection/ComparablePair.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.collection; 2 | 3 | import org.processmining.framework.util.Pair; 4 | 5 | public class ComparablePair, S extends Comparable> extends Pair 6 | implements Comparable> { 7 | 8 | public ComparablePair(F first, S second) { 9 | super(first, second); 10 | } 11 | 12 | public > int compareTo(T x, T y) { 13 | if (x == null) { 14 | return y == null ? 0 : -1; 15 | } else { 16 | return x.compareTo(y); 17 | } 18 | } 19 | 20 | public int compareTo(ComparablePair other) { 21 | if (other == null) { 22 | return 1; 23 | } 24 | int result = compareTo(first, other.first); 25 | return result == 0 ? compareTo(second, other.second) : result; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/collection/HashMultiSet.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.collection; 2 | 3 | import java.util.Collection; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | public class HashMultiSet extends AbstractMultiSet> { 8 | 9 | /** 10 | * Constructs a new multiset, such that all elements of the given collection 11 | * are added as many times as they are returned by the iterator of that 12 | * collection. 13 | * 14 | * @param collection 15 | * Representing the objects that should be put in a multiset 16 | */ 17 | public HashMultiSet(Collection collection) { 18 | this(); 19 | addAll(collection); 20 | } 21 | 22 | /** 23 | * Constructs a new multiset, such that all elements of the given collection 24 | * are added as many times as they are in the given array. 25 | * 26 | * @param collection 27 | * Representing the objects that should be put in a multiset 28 | */ 29 | public HashMultiSet(T[] collection) { 30 | this(); 31 | for (T par : collection) { 32 | add(par); 33 | } 34 | } 35 | 36 | /** 37 | * Constructs a new, empty multiset, such that all elements of the given 38 | * collection are added as many times as they are returned by the iterator 39 | * of that collection. 40 | */ 41 | public HashMultiSet() { 42 | size = 0; 43 | map = new HashMap(); 44 | } 45 | 46 | MultiSet newMultiSet(Collection collection) { 47 | return new HashMultiSet(collection); 48 | } 49 | 50 | MultiSet newMultiSet() { 51 | return new HashMultiSet(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/collection/LinkedHashMultiSet.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.collection; 2 | 3 | import java.util.Collection; 4 | import java.util.LinkedHashMap; 5 | 6 | public class LinkedHashMultiSet extends HashMultiSet { 7 | 8 | /** 9 | * Constructs a new multiset, such that all elements of the given collection 10 | * are added as many times as they are returned by the iterator of that 11 | * collection. 12 | * 13 | * @param collection 14 | * Representing the objects that should be put in a multiset 15 | */ 16 | public LinkedHashMultiSet(Collection collection) { 17 | this(); 18 | addAll(collection); 19 | } 20 | 21 | /** 22 | * Constructs a new multiset, such that all elements of the given collection 23 | * are added as many times as they are in the given array. 24 | * 25 | * @param collection 26 | * Representing the objects that should be put in a multiset 27 | */ 28 | public LinkedHashMultiSet(T... collection) { 29 | this(); 30 | for (T par : collection) { 31 | add(par); 32 | } 33 | } 34 | 35 | /** 36 | * Constructs a new, empty multiset, such that all elements of the given 37 | * collection are added as many times as they are returned by the iterator 38 | * of that collection. 39 | */ 40 | public LinkedHashMultiSet() { 41 | size = 0; 42 | map = new LinkedHashMap(); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/collection/MultiSet.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.collection; 2 | 3 | import java.util.Collection; 4 | import java.util.List; 5 | import java.util.Set; 6 | 7 | import org.processmining.framework.util.HTMLToString; 8 | 9 | /** 10 | * This class implements a mutliset. The implementation is synchronized. 11 | * 12 | * @author bfvdonge 13 | * 14 | * @param 15 | * the type of the objects in this multiset. 16 | */ 17 | public interface MultiSet extends Collection, HTMLToString { 18 | 19 | /** 20 | * Adds the given object to the multiset, as many times as indicated by the 21 | * given weight parameter. 22 | * 23 | * @param par 24 | * the object to add 25 | * @param weight 26 | * the number of times to add it 27 | * @return the new number of occurrences of the object (>0) 28 | */ 29 | public Integer add(T par, Integer weight); 30 | 31 | /** 32 | * Converts this multiset to a list, such that each element occurs as often 33 | * as returned by the iterator of the multiset (its number of occurrences). 34 | * 35 | * @return a list of objects as returned by the iterator 36 | */ 37 | public List toList(); 38 | 39 | /** 40 | * returns true if this multiset is less or equal to the given multiset, 41 | * i.e. all objects in this multiset should be contained in the given set 42 | * and the number of occurrences in the given set is at least the number of 43 | * occurrences in this multiset. 44 | * 45 | * @param multiSet 46 | * the multiset to test 47 | * @return true if the given multiset is less or equal. 48 | */ 49 | public boolean isLessOrEqual(MultiSet multiSet); 50 | 51 | /** 52 | * returns the number of occurrences of the given object in this multiset. 53 | * 54 | * @param source 55 | * the object to get the occurrences for 56 | * @return the number of occurrences, 0 if the object does not occur. 57 | */ 58 | public Integer occurrences(Object source); 59 | 60 | /** 61 | * returns an unmodifiable set of unique objects in the multiset. 62 | * 63 | * @return an unmodifiable set of unique objects in the multiset. 64 | */ 65 | public Set baseSet(); 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/collection/SortedMultiSet.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.collection; 2 | 3 | import java.util.Comparator; 4 | import java.util.SortedSet; 5 | 6 | public interface SortedMultiSet extends MultiSet { 7 | 8 | Comparator comparator(); 9 | 10 | /** 11 | * returns an unmodifiable set of unique objects in the multiset. 12 | * 13 | * @return an unmodifiable set of unique objects in the multiset. 14 | */ 15 | SortedSet baseSet(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/collection/TreeMultiSet.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.collection; 2 | 3 | import java.util.Collection; 4 | import java.util.Collections; 5 | import java.util.Comparator; 6 | import java.util.SortedSet; 7 | import java.util.TreeMap; 8 | import java.util.TreeSet; 9 | 10 | public class TreeMultiSet extends AbstractMultiSet> implements SortedMultiSet { 11 | 12 | private Comparator comparator; 13 | 14 | /** 15 | * Constructs a new multiset, such that all elements of the given collection 16 | * are added as many times as they are returned by the iterator of that 17 | * collection. 18 | * 19 | * All elements inserted into the multiset must implement the Comparable 20 | * interface. Furthermore, all such elements must be mutually comparable: 21 | * e1.compareTo(e2) must not throw a ClassCastException for any elements e1 22 | * and e2 in the set. 23 | * 24 | * @param collection 25 | * Representing the objects that should be put in a multiset 26 | */ 27 | public TreeMultiSet(Collection collection) { 28 | this((Comparator) null); 29 | addAll(collection); 30 | } 31 | 32 | /** 33 | * Constructs a new multiset, such that all elements of the given collection 34 | * are added as many times as they are in the given array. 35 | * 36 | * All elements inserted into the multiset must implement the Comparable 37 | * interface. Furthermore, all such elements must be mutually comparable: 38 | * e1.compareTo(e2) must not throw a ClassCastException for any elements e1 39 | * and e2 in the set. 40 | * 41 | * @param collection 42 | * Representing the objects that should be put in a multiset 43 | */ 44 | public TreeMultiSet(T... collection) { 45 | this((Comparator) null); 46 | for (T par : collection) { 47 | add(par); 48 | } 49 | } 50 | 51 | /** 52 | * Constructs a new, empty multiset, such that all elements of the given 53 | * collection are added as many times as they are returned by the iterator 54 | * of that collection. 55 | * 56 | * All elements inserted into the multiset must implement the Comparable 57 | * interface. Furthermore, all such elements must be mutually comparable: 58 | * e1.compareTo(e2) must not throw a ClassCastException for any elements e1 59 | * and e2 in the set. 60 | * 61 | */ 62 | public TreeMultiSet() { 63 | this((Comparator) null); 64 | } 65 | 66 | /** 67 | * Constructs a new multiset, such that all elements of the given collection 68 | * are added as many times as they are returned by the iterator of that 69 | * collection. 70 | * 71 | * @param comp 72 | * A comparator providing sorting on the elements of the multiset 73 | * @param collection 74 | * Representing the objects that should be put in a multiset 75 | */ 76 | public TreeMultiSet(Collection collection, Comparator comp) { 77 | this(comp); 78 | addAll(collection); 79 | } 80 | 81 | /** 82 | * Constructs a new multiset, such that all elements of the given collection 83 | * are added as many times as they are in the given array. 84 | * 85 | * @param comp 86 | * A comparator providing sorting on the elements of the multiset 87 | * @param collection 88 | * Representing the objects that should be put in a multiset 89 | */ 90 | public TreeMultiSet(Comparator comp, T... collection) { 91 | this(comp); 92 | for (T par : collection) { 93 | add(par); 94 | } 95 | } 96 | 97 | /** 98 | * Constructs a new, empty multiset, such that all elements of the given 99 | * collection are added as many times as they are returned by the iterator 100 | * of that collection. 101 | * 102 | * @param comp 103 | * A comparator providing sorting on the elements of the multiset 104 | */ 105 | public TreeMultiSet(Comparator comp) { 106 | size = 0; 107 | TreeMap newMap = new TreeMap(comp); 108 | comparator = newMap.comparator(); 109 | map = newMap; 110 | } 111 | 112 | MultiSet newMultiSet(Collection collection) { 113 | return new TreeMultiSet(collection); 114 | } 115 | 116 | MultiSet newMultiSet() { 117 | return new TreeMultiSet(); 118 | } 119 | 120 | public Comparator comparator() { 121 | return comparator; 122 | } 123 | 124 | /** 125 | * returns an unmodifiable set of unique objects in the multiset. 126 | * 127 | * @return an unmodifiable set of unique objects in the multiset. 128 | */ 129 | public SortedSet baseSet() { 130 | // JAVA 5 CODE: 131 | SortedSet set = new TreeSet(comparator); 132 | set.addAll(map.keySet()); 133 | // JAVA 6 CODE: 134 | // SortedSet set = map.navigableKeySet()); 135 | return Collections.unmodifiableSortedSet(set); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/collection/WeakKeyValueMap.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.collection; 2 | 3 | import java.lang.ref.WeakReference; 4 | import java.util.AbstractMap; 5 | import java.util.Collection; 6 | import java.util.HashSet; 7 | import java.util.Map; 8 | import java.util.Set; 9 | import java.util.WeakHashMap; 10 | 11 | public class WeakKeyValueMap extends AbstractMap { 12 | 13 | private final Map> map; 14 | 15 | public WeakKeyValueMap(int initialCapacity, float loadFactor) { 16 | map = new WeakHashMap>(initialCapacity, loadFactor); 17 | } 18 | 19 | public WeakKeyValueMap(int initialCapacity) { 20 | map = new WeakHashMap>(initialCapacity); 21 | } 22 | 23 | public WeakKeyValueMap() { 24 | map = new WeakHashMap>(); 25 | 26 | } 27 | 28 | public WeakKeyValueMap(Map m) { 29 | this(); 30 | putAll(m); 31 | } 32 | 33 | public void clear() { 34 | map.clear(); 35 | } 36 | 37 | public boolean containsKey(Object key) { 38 | return map.containsKey(key); 39 | } 40 | 41 | public boolean containsValue(Object value) { 42 | for (WeakReference w : map.values()) { 43 | if (value.equals(w.get())) { 44 | return true; 45 | } 46 | } 47 | return false; 48 | } 49 | 50 | public Set> entrySet() { 51 | Set> set = new HashSet>(); 52 | for (java.util.Map.Entry> entry : map.entrySet()) { 53 | set.add(new SimpleEntry(entry.getKey(), entry.getValue().get())); 54 | } 55 | return set; 56 | } 57 | 58 | public V get(Object key) { 59 | WeakReference val = map.get(key); 60 | return val == null ? null : val.get(); 61 | } 62 | 63 | public boolean isEmpty() { 64 | return map.isEmpty(); 65 | } 66 | 67 | public Set keySet() { 68 | return map.keySet(); 69 | } 70 | 71 | public V put(K key, V value) { 72 | V val = get(key); 73 | map.put(key, new WeakReference(value)); 74 | return val; 75 | } 76 | 77 | public void putAll(Map m) { 78 | for (Map.Entry entry : m.entrySet()) { 79 | put(entry.getKey(), entry.getValue()); 80 | } 81 | } 82 | 83 | public V remove(Object key) { 84 | return map.remove(key).get(); 85 | } 86 | 87 | public int size() { 88 | return map.size(); 89 | } 90 | 91 | public Collection values() { 92 | Set set = new HashSet(); 93 | for (WeakReference val : map.values()) { 94 | set.add(val.get()); 95 | } 96 | return set; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/progress/XProgressBarListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenXES 3 | * 4 | * The reference implementation of the XES meta-model for event 5 | * log data management. 6 | * 7 | * Copyright (c) 2008 Christian W. Guenther (christian@deckfour.org) 8 | * 9 | * 10 | * LICENSE: 11 | * 12 | * This code is free software; you can redistribute it and/or 13 | * modify it under the terms of the GNU Lesser General Public License 14 | * as published by the Free Software Foundation; either version 3 15 | * of the License, or (at your option) any later version. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU Lesser General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU Lesser General Public License 23 | * along with this program; if not, write to the Free Software 24 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 25 | * 26 | * EXEMPTION: 27 | * 28 | * The use of this software can also be conditionally licensed for 29 | * other programs, which do not satisfy the specified conditions. This 30 | * requires an exemption from the general license, which may be 31 | * granted on a per-case basis. 32 | * 33 | * If you want to license the use of this software with a program 34 | * incompatible with the LGPL, please contact the author for an 35 | * exemption at the following email address: 36 | * christian@deckfour.org 37 | * 38 | */ 39 | package org.processmining.framework.util.progress; 40 | 41 | import javax.swing.JProgressBar; 42 | 43 | /** 44 | * This class implements a progress listener for controlling 45 | * an attached Swing progress bar. The progress bar will then reflect 46 | * the progress as received by this listener. 47 | * 48 | * @author Christian W. Guenther (christian@deckfour.org) 49 | * 50 | */ 51 | public class XProgressBarListener implements XProgressListener { 52 | 53 | /** 54 | * Controlled progress bar. 55 | */ 56 | protected JProgressBar progressBar; 57 | /** 58 | * Start value to use in progress bar. 59 | * When the progress listener begins, this will be 60 | * the displayed value on the progress bar. 61 | */ 62 | protected int startValue; 63 | /** 64 | * Stop value to use in progress bar. 65 | * When the progress listener is completed, this will 66 | * be the displayed value on the progress bar. 67 | */ 68 | protected int stopValue; 69 | 70 | /** 71 | * Creates a new progress bar listener with the specified progress 72 | * bar for display. The progress bar will accurately and completely 73 | * reflect the progress, as received by this listener. 74 | * 75 | * @param progressBar Progress bar to display progress. 76 | */ 77 | public XProgressBarListener(JProgressBar progressBar) { 78 | this(progressBar, progressBar.getMinimum(), progressBar.getMaximum()); 79 | } 80 | 81 | /** 82 | * Creates a new progress bar listener with the specified progress 83 | * bar for display. Allows the specification of start and stop values 84 | * for the progress bar, so that this listener may control only part 85 | * of a more higher-level progress (e.g., the loading of one from 86 | * a number of files). 87 | * 88 | * @param progressBar Progress bar to display progress. 89 | * @param startValue When the progress listener begins, this will be 90 | * the displayed value on the progress bar. 91 | * @param stopValue When the progress listener is completed, this will 92 | * be the displayed value on the progress bar. 93 | */ 94 | public XProgressBarListener(JProgressBar progressBar, int startValue, int stopValue) { 95 | this.progressBar = progressBar; 96 | this.startValue = startValue; 97 | this.stopValue = stopValue; 98 | } 99 | 100 | /* (non-Javadoc) 101 | * @see org.deckfour.xes.util.MonitoredInputStream.ProgressListener#updateProgress(int, int) 102 | */ 103 | public void updateProgress(int progress, int maxProgress) { 104 | int increment = (int)((double)(stopValue - startValue) * ((double)maxProgress / (double)progress)); 105 | progressBar.setValue(startValue + increment); 106 | } 107 | 108 | /** 109 | * Checks whether the monitored process has been canceled. 110 | */ 111 | public boolean isAborted() { 112 | return false; 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/progress/XProgressListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * OpenXES 3 | * 4 | * The reference implementation of the XES meta-model for event 5 | * log data management. 6 | * 7 | * Copyright (c) 2008 Christian W. Guenther (christian@deckfour.org) 8 | * 9 | * 10 | * LICENSE: 11 | * 12 | * This code is free software; you can redistribute it and/or 13 | * modify it under the terms of the GNU Lesser General Public License 14 | * as published by the Free Software Foundation; either version 3 15 | * of the License, or (at your option) any later version. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU Lesser General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU Lesser General Public License 23 | * along with this program; if not, write to the Free Software 24 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 25 | * 26 | * EXEMPTION: 27 | * 28 | * The use of this software can also be conditionally licensed for 29 | * other programs, which do not satisfy the specified conditions. This 30 | * requires an exemption from the general license, which may be 31 | * granted on a per-case basis. 32 | * 33 | * If you want to license the use of this software with a program 34 | * incompatible with the LGPL, please contact the author for an 35 | * exemption at the following email address: 36 | * christian@deckfour.org 37 | * 38 | */ 39 | package org.processmining.framework.util.progress; 40 | 41 | /** 42 | * Interface for listening for progress on 43 | * an unspecified process. 44 | * 45 | * A progress listener can abort the monitored 46 | * process. Abortion is specified by using the 47 | * isAborted() method, which should 48 | * be queried periodically by the using party. 49 | * 50 | * @author Christian W. Guenther (christian@deckfour.org) 51 | * 52 | */ 53 | public interface XProgressListener { 54 | 55 | /** 56 | * Notifies the listener about progress being made. 57 | * 58 | * @param progress Current progress step achieved. 59 | * @param maxProgress Maximal progress steps available. 60 | */ 61 | public void updateProgress(int progress, int maxProgress); 62 | 63 | /** 64 | * Checks whether the monitored process has been canceled. 65 | */ 66 | public boolean isAborted(); 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/search/BreadthFirstExpandCollection.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.search; 2 | 3 | import java.util.Collection; 4 | 5 | public class BreadthFirstExpandCollection extends DepthFirstExpandCollection { 6 | 7 | public void add(Collection newElements) { 8 | stack.addAll(0, newElements); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/search/DepthFirstExpandCollection.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.search; 2 | 3 | import java.util.Collection; 4 | import java.util.Stack; 5 | 6 | public class DepthFirstExpandCollection implements ExpandCollection { 7 | 8 | protected Stack stack = new Stack(); 9 | 10 | public void add(Collection newElements) { 11 | stack.addAll(newElements); 12 | } 13 | 14 | public N pop() { 15 | return stack.pop(); 16 | } 17 | 18 | public boolean isEmpty() { 19 | return stack.isEmpty(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/search/ExpandCollection.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.search; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * 7 | * @author bfvdonge 8 | * 9 | * @param 10 | */ 11 | public interface ExpandCollection { 12 | 13 | /** 14 | * Gets and removes the first element to be expanded by the node expander. 15 | * 16 | * Implementing classes may assume that isEmpty() returns false before any 17 | * call to pop, i.e. the first line of the implementation can be: 18 | * assert (!isEmpty()) 19 | * 20 | * @return the first element to be investigated by the searcher. 21 | */ 22 | public N pop(); 23 | 24 | /** 25 | * Adds the given elements to the collection. Note that implementing classes 26 | * may safely assume that the calling thread owns the monitor, i.e. there is 27 | * no need to synchronize on the collection retained by this 28 | * expandcollection and removals are allowed. Furthermore, the implementing 29 | * class may decide not to include any of the given newElements if it 30 | * decides that they are not to be investigated further. 31 | * 32 | * @param newElements 33 | * the nodes to expand further 34 | */ 35 | public void add(Collection newElements); 36 | 37 | /** 38 | * Checks whether or not the collection retained by this ExpandCollection is 39 | * empty. If this method returns false, a call to pop() can be made. 40 | * 41 | * @return 42 | */ 43 | public boolean isEmpty(); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/search/NodeExpander.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.search; 2 | 3 | import java.util.Collection; 4 | 5 | import org.processmining.framework.plugin.Progress; 6 | 7 | /** 8 | * This class is used by the MultiThreadedSearcher to handle callbacks. Each 9 | * time the searcher considers a node, it asks the registered expander to expand 10 | * the node. If a node cannot be expanded, then a call to processLeaf is made. 11 | * The expander should not process any leafs from within the expandNode method. 12 | * 13 | * @author bfvdonge 14 | * 15 | * @param 16 | */ 17 | public interface NodeExpander { 18 | 19 | /** 20 | * This method is called by the searcher when a node in the search tree has 21 | * to be considered for expansion. The node to expand is given as a 22 | * parameter and the method should return a collection of nodes representing 23 | * the children of this node. If the node turns out to be a leaf, an empty 24 | * collection has to be returned. 25 | * 26 | * @param toExpand 27 | * The node to expand. 28 | * @param progress 29 | * The progress indicator provided to the searcher in which this 30 | * expander is registered. The expander may increment the 31 | * progress, but it should check for cancellation, especially 32 | * when doing long computations. 33 | * @param unmodifiableResultCollection 34 | * the leafs of the search space that have been added to the 35 | * resultCollection by the processLeaf method. Note that any 36 | * access to this collection should be synchronized and this 37 | * collection should not be modified in this method. However the 38 | * provided collection is modifiable, as for synchronization 39 | * purposes, the actual resultCollection is provided. 40 | * @return A collection of child nodes, or an empty collection if this node 41 | * turns out to be a leaf. 42 | */ 43 | public Collection expandNode(N toExpand, Progress progress, Collection unmodifiableResultCollection); 44 | 45 | /** 46 | * This method is called by the searcher to which this expander is 47 | * registered each time a leaf was encountered. The provided 48 | * resultCollection was specified in the startSearch method of the searcher 49 | * and can be used to store this result. A typical implementation is: 50 | * 51 | * 52 | * synchronized(resultCollection) { 53 | * resultCollection.add(leaf); 54 | * } 55 | * 56 | * 57 | * However, more advanced implementations are possible. 58 | * 59 | * Finally, note that calls to this method are not thread-safe, i.e. the 60 | * implementing class should take care of synchronization on the 61 | * resultCollection if necessary (as in the example above). 62 | * 63 | * @param leaf 64 | * The node that was found to be a leaf by the expandNode method 65 | * (i.e. the expandNode method returned and empty collection) 66 | * @param progress 67 | * The progress indicator provided to the searcher in which this 68 | * expander is registered. The expander may increment the 69 | * progress, but it should check for cancellation, especially 70 | * when doing long computations. 71 | * @param resultCollection 72 | * The collection to which to add the leaf node. More advanced 73 | * computations are allowed here, i.e. the resultCollection can 74 | * be changed. Note however that this requires syncrhonization on 75 | * the collection, as calls to this method are not thread-safe. 76 | */ 77 | public void processLeaf(N leaf, Progress progress, Collection resultCollection); 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/socket/Service.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.socket; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.io.PrintWriter; 7 | import java.net.ServerSocket; 8 | import java.net.Socket; 9 | import java.net.SocketTimeoutException; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.concurrent.Executor; 13 | 14 | import org.processmining.framework.plugin.events.Logger.MessageLevel; 15 | 16 | /** 17 | * This is a wrapper for a server socket. It has an arbitrary number of 18 | * registered ServiceHandler-s. Whenever a client connects to the service, all 19 | * registered handlers are notified. Each handler can further communucate with 20 | * the client. 21 | * 22 | * @author christian 23 | * 24 | */ 25 | 26 | public class Service { 27 | 28 | protected ServerSocket serverSocket; // server socket 29 | private final int port; // port for the server socket 30 | protected List handlers = new ArrayList(); // registered handlers 31 | 32 | /** 33 | * The only constructor, which simply sets a port to be used by the server 34 | * socket. Note that the constructor does not open the server socket. 35 | * 36 | * @param port 37 | * for the server socket. 38 | */ 39 | public Service(int port) { 40 | super(); 41 | this.port = port; 42 | serverSocket = null; 43 | } 44 | 45 | /** 46 | * Registers a new handler. From this moment, the handler will be notified 47 | * about new client connections. 48 | * 49 | * @param handler 50 | * to be registered. 51 | */ 52 | public void addServiceHandler(ServiceHandler handler) { 53 | handlers.add(handler); 54 | } 55 | 56 | /** 57 | * Unregister the handler. From this moment, the handler will not longer be 58 | * notified about new client connections. 59 | * 60 | * @param handler 61 | * to be unregistered. 62 | */ 63 | public void removeServiceHandler(ServiceHandler handler) { 64 | handlers.remove(handler); 65 | } 66 | 67 | /** 68 | * Opens the server socked on the given port. Periodically notifies the 69 | * environment that the service is alive. Notifies all registered handlers 70 | * about every new client connection. It keeps on listening on the socket 71 | * until the environment is canceled, upon which the socket is closed. 72 | * 73 | * @param environment 74 | * is the environment of this service. 75 | * @param executor 76 | * enables notification of handlers in a new thread. 77 | * @throws IOException 78 | */ 79 | public void start(ServiceEnvironment environment, Executor executor) throws IOException { 80 | serverSocket = new ServerSocket(getPort()); 81 | 82 | while (!environment.isCancelled()) { 83 | try { 84 | environment.stillAlive(); 85 | // wait for and handle incoming connections 86 | serverSocket.setSoTimeout(500); 87 | Socket clientSocket = serverSocket.accept(); 88 | handleConnection(clientSocket, environment, executor); 89 | } catch (SocketTimeoutException e) { 90 | // environment.log("No Connection Accepted", MessageLevel.DEBUG); 91 | continue; 92 | } catch (IOException e) { 93 | // abort and give up 94 | environment.log("Operational Support Server Failed: " + e.getMessage(), MessageLevel.ERROR); 95 | serverSocket.close(); 96 | throw e; 97 | } 98 | } 99 | serverSocket.close(); 100 | 101 | environment.log("Operational Support Server Finished", MessageLevel.DEBUG); 102 | } 103 | 104 | /** 105 | * Notifies all registered handlers about every new client connection. 106 | * 107 | * @param socket 108 | * is the client socket. 109 | * @param environment 110 | * is the environment of this service. 111 | * @param executor 112 | * enables notification of handlers in a new thread. 113 | */ 114 | protected void handleConnection(Socket socket, ServiceEnvironment environment, Executor executor) { 115 | ConnectionHandlerRunnable handler = new ConnectionHandlerRunnable(socket, environment); 116 | executor.execute(handler); 117 | } 118 | 119 | /** 120 | * Get the server port. 121 | * 122 | * @return the port. 123 | */ 124 | public int getPort() { 125 | return port; 126 | } 127 | 128 | /** 129 | * A simple class that enables notification of ServiceHandler-s in a new 130 | * thread. 131 | * 132 | * @author christian 133 | * 134 | */ 135 | protected class ConnectionHandlerRunnable implements Runnable { 136 | 137 | protected Socket clientSocket; 138 | private final ServiceEnvironment environment; 139 | 140 | public ConnectionHandlerRunnable(Socket aSocket, ServiceEnvironment environment) { 141 | clientSocket = aSocket; 142 | this.environment = environment; 143 | } 144 | 145 | /** 146 | * Notifies all registered handlers about a new client connection in a 147 | * new thread. 148 | */ 149 | public void run() { 150 | try { 151 | BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 152 | PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); 153 | for (ServiceHandler handler : handlers) { 154 | handler.handleRequest(environment, in, out); 155 | } 156 | } catch (IOException e) { 157 | // abort and give up 158 | 159 | environment.log("Fatal error handling connection,", MessageLevel.ERROR); 160 | environment.log("failed with IO Exception:", MessageLevel.ERROR); 161 | environment.log(e); 162 | } finally { 163 | // clean up connection 164 | try { 165 | if (clientSocket != null) { 166 | clientSocket.close(); 167 | } 168 | } catch (IOException ie) { /* this one's forsaken.. */ 169 | } 170 | } 171 | } 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/socket/ServiceEnvironment.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.socket; 2 | 3 | import org.processmining.framework.plugin.events.Logger.MessageLevel; 4 | 5 | /** 6 | * This interface represents a service environment. It allows communication 7 | * between a service and its environment. 8 | * 9 | * @author Maja Pesic 10 | */ 11 | 12 | public interface ServiceEnvironment { 13 | 14 | /** 15 | * Provides the information about the state of the environment. A service 16 | * uses this method to decide when to close its socket. 17 | * 18 | * @return true - if the socket should be closed false - if the service 19 | * should continue listening on the socket. 20 | */ 21 | public boolean isCancelled(); 22 | 23 | /** 24 | * A service uses this method to log messages in the environment. 25 | * 26 | * @param message 27 | * is the message that should be logged 28 | * @param level 29 | * is the type of message 30 | */ 31 | public void log(String message, MessageLevel level); 32 | 33 | /** 34 | * A service uses this method to log messages in the environment. 35 | * 36 | * @param message 37 | * is the message that should be logged 38 | */ 39 | public void log(String message); 40 | 41 | /** 42 | * A service uses this method to log occurrence of an exception in the 43 | * environment. 44 | * 45 | * @param t 46 | * is the exception that occurred and should be logged 47 | */ 48 | public void log(Throwable t); 49 | 50 | /** 51 | * While listening on its socket, a service will regularly invoke this 52 | * method. This method periodically signals to the environment that the 53 | * service is still listening to its socket. 54 | */ 55 | public void stillAlive(); 56 | 57 | /** 58 | * A service uses this method to signal that it has been canceled (i.e., the 59 | * socket is closed). 60 | */ 61 | public void cancel(); 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/socket/ServiceHandler.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.socket; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.PrintWriter; 6 | 7 | /** 8 | * This interface enables a service to respond to newly connected clients. If a 9 | * class wants to be informed about and/or respond to new requests of a service, 10 | * then this class should implement this interface and it should be added as a 11 | * handler to the service. 12 | * 13 | * @author christian 14 | */ 15 | 16 | public interface ServiceHandler { 17 | /** 18 | * Invoked whenever a client connects to the service. 19 | * 20 | * @param environment 21 | * is the registered environment of the service. A handler can 22 | * use this parameter to, for example, log messages. 23 | * @param in 24 | * is the buffer from which the client's request can be read. 25 | * @param out 26 | * is the buffer where a possible response to the client can be 27 | * written. 28 | * @throws IOException 29 | */ 30 | public void handleRequest(ServiceEnvironment environment, BufferedReader in, PrintWriter out) throws IOException; 31 | } 32 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/ui/ExpandButton.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.ui; 2 | 3 | /* 4 | * Copyright (c) 2007 Christian W. Guenther (christian@deckfour.org) 5 | * 6 | * LICENSE: 7 | * 8 | * This code is free software; you can redistribute it and/or modify it under 9 | * the terms of the GNU General Public License as published by the Free Software 10 | * Foundation; either version 2 of the License, or (at your option) any later 11 | * version. 12 | * 13 | * This program is distributed in the hope that it will be useful, but WITHOUT 14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License along with 19 | * this program; if not, write to the Free Software Foundation, Inc., 51 20 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 21 | * 22 | * EXEMPTION: 23 | * 24 | * License to link and use is also granted to open source programs which are not 25 | * licensed under the terms of the GPL, given that they satisfy one or more of 26 | * the following conditions: 1) Explicit license is granted to the ProM and 27 | * ProMimport programs for usage, linking, and derivative work. 2) Carte blance 28 | * license is granted to all programs developed at Eindhoven Technical 29 | * University, The Netherlands, or under the umbrella of STW Technology 30 | * Foundation, The Netherlands. For further exemptions not covered by the above 31 | * conditions, please contact the author of this code. 32 | */ 33 | 34 | import java.awt.AlphaComposite; 35 | import java.awt.Color; 36 | import java.awt.Dimension; 37 | import java.awt.Graphics; 38 | import java.awt.Graphics2D; 39 | import java.awt.RenderingHints; 40 | import java.awt.event.MouseEvent; 41 | import java.awt.event.MouseListener; 42 | 43 | import javax.swing.BorderFactory; 44 | import javax.swing.JButton; 45 | 46 | /** 47 | * @author Christian W. Guenther (christian@deckfour.org) 48 | * 49 | */ 50 | public class ExpandButton extends JButton { 51 | 52 | private static final long serialVersionUID = -8427659617273150458L; 53 | 54 | protected Color colorTriangle = new Color(220, 220, 220, 220); 55 | 56 | protected boolean isExpanded = false; 57 | protected boolean mouseOver = false; 58 | 59 | public ExpandButton() { 60 | setOpaque(false); 61 | setBorder(BorderFactory.createEmptyBorder()); 62 | Dimension size = new Dimension(21, 21); 63 | setMinimumSize(size); 64 | setMaximumSize(size); 65 | setPreferredSize(size); 66 | addMouseListener(new MouseListener() { 67 | public void mouseClicked(MouseEvent arg0) { /* ignore */ 68 | } 69 | 70 | public void mouseEntered(MouseEvent arg0) { 71 | mouseOver = true; 72 | repaint(); 73 | } 74 | 75 | public void mouseExited(MouseEvent arg0) { 76 | mouseOver = false; 77 | repaint(); 78 | } 79 | 80 | public void mousePressed(MouseEvent arg0) { /* ignore */ 81 | } 82 | 83 | public void mouseReleased(MouseEvent arg0) { /* ignore */ 84 | } 85 | }); 86 | } 87 | 88 | public boolean isExpanded() { 89 | return isExpanded; 90 | } 91 | 92 | public void setExpanded(boolean expanded) { 93 | isExpanded = expanded; 94 | repaint(); 95 | } 96 | 97 | protected void paintComponent(Graphics g) { 98 | Graphics2D g2d = (Graphics2D) g.create(); 99 | g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 100 | int y[] = new int[] { 5, 15, 5 }; 101 | int x[] = new int[] { 5, 10, 15 }; 102 | g2d.setColor(colorTriangle); 103 | if (mouseOver == false) { 104 | g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f)); 105 | } 106 | if (isExpanded == true) { 107 | g2d.fillPolygon(x, y, 3); 108 | } else { 109 | g2d.fillPolygon(y, x, 3); 110 | } 111 | g2d.dispose(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/org/processmining/framework/util/ui/TypeToggleButton.java: -------------------------------------------------------------------------------- 1 | package org.processmining.framework.util.ui; 2 | 3 | /* 4 | * Copyright (c) 2007 Christian W. Guenther (christian@deckfour.org) 5 | * 6 | * LICENSE: 7 | * 8 | * This code is free software; you can redistribute it and/or modify it under 9 | * the terms of the GNU General Public License as published by the Free Software 10 | * Foundation; either version 2 of the License, or (at your option) any later 11 | * version. 12 | * 13 | * This program is distributed in the hope that it will be useful, but WITHOUT 14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License along with 19 | * this program; if not, write to the Free Software Foundation, Inc., 51 20 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 21 | * 22 | * EXEMPTION: 23 | * 24 | * License to link and use is also granted to open source programs which are not 25 | * licensed under the terms of the GPL, given that they satisfy one or more of 26 | * the following conditions: 1) Explicit license is granted to the ProM and 27 | * ProMimport programs for usage, linking, and derivative work. 2) Carte blance 28 | * license is granted to all programs developed at Eindhoven Technical 29 | * University, The Netherlands, or under the umbrella of STW Technology 30 | * Foundation, The Netherlands. For further exemptions not covered by the above 31 | * conditions, please contact the author of this code. 32 | */ 33 | 34 | import java.awt.AlphaComposite; 35 | import java.awt.Color; 36 | import java.awt.Dimension; 37 | import java.awt.FontMetrics; 38 | import java.awt.Graphics; 39 | import java.awt.Graphics2D; 40 | import java.awt.RenderingHints; 41 | import java.awt.event.ActionEvent; 42 | import java.awt.event.ActionListener; 43 | import java.awt.event.MouseEvent; 44 | import java.awt.event.MouseListener; 45 | import java.awt.geom.Rectangle2D; 46 | 47 | import javax.swing.BorderFactory; 48 | import javax.swing.JButton; 49 | 50 | /** 51 | * @author Christian W. Guenther (christian@deckfour.org) 52 | * 53 | */ 54 | public class TypeToggleButton extends JButton { 55 | 56 | /** 57 | * 58 | */ 59 | private static final long serialVersionUID = 8489141352439288484L; 60 | protected Color colorPassive = new Color(90, 90, 90, 200); 61 | protected Color colorTextPassive = new Color(180, 180, 180, 200); 62 | protected Color colorTextActive = new Color(10, 10, 10, 200); 63 | protected FontMetrics metrics; 64 | protected int size = 20; 65 | 66 | protected boolean mouseOver = false; 67 | protected boolean buttonIsEnabled = true; 68 | 69 | protected String type; 70 | protected String letter; 71 | protected Color active; 72 | 73 | public TypeToggleButton(String type, String letter, Color active) { 74 | setOpaque(false); 75 | setBorder(BorderFactory.createEmptyBorder()); 76 | setToolTipText("Click to disable " + type); 77 | this.type = type; 78 | this.letter = letter; 79 | this.active = active; 80 | setFont(getFont().deriveFont(12f)); 81 | metrics = getFontMetrics(getFont()); 82 | addActionListener(new ActionListener() { 83 | public void actionPerformed(ActionEvent arg0) { 84 | setButtonEnabled(!buttonIsEnabled); 85 | } 86 | }); 87 | addMouseListener(new MouseListener() { 88 | public void mouseClicked(MouseEvent arg0) { /* ignore */ 89 | } 90 | 91 | public void mouseEntered(MouseEvent arg0) { 92 | mouseOver = true; 93 | repaint(); 94 | } 95 | 96 | public void mouseExited(MouseEvent arg0) { 97 | mouseOver = false; 98 | repaint(); 99 | } 100 | 101 | public void mousePressed(MouseEvent arg0) { /* ignore */ 102 | } 103 | 104 | public void mouseReleased(MouseEvent arg0) { /* ignore */ 105 | } 106 | }); 107 | Dimension dim = new Dimension(size + 4, size + 4); 108 | setMinimumSize(dim); 109 | setMaximumSize(dim); 110 | setPreferredSize(dim); 111 | } 112 | 113 | public boolean isEnabled() { 114 | return buttonIsEnabled; 115 | } 116 | 117 | public void setButtonEnabled(boolean enabled) { 118 | buttonIsEnabled = enabled; 119 | if (buttonIsEnabled == true) { 120 | setToolTipText("Click to disable " + type); 121 | } else { 122 | setToolTipText("Click to enable " + type); 123 | } 124 | repaint(); 125 | } 126 | 127 | protected void paintComponent(Graphics g) { 128 | int width = getWidth(); 129 | int height = getHeight(); 130 | Graphics2D g2d = (Graphics2D) g.create(); 131 | g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 132 | if (mouseOver == false) { 133 | g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f)); 134 | } 135 | if (buttonIsEnabled == true) { 136 | g2d.setColor(active); 137 | } else { 138 | g2d.setColor(colorPassive); 139 | } 140 | g2d.fillRoundRect(((width - size) / 2), ((height - size) / 2), size - 1, size - 1, 8, 8); 141 | if (buttonIsEnabled == true) { 142 | g2d.setColor(colorTextActive); 143 | } else { 144 | g2d.setColor(colorTextPassive); 145 | } 146 | Rectangle2D stringBounds = metrics.getStringBounds(letter, g2d); 147 | int fontX = (width - (int) stringBounds.getWidth()) / 2; 148 | int fontY = ((height - (int) stringBounds.getHeight()) / 2) + metrics.getAscent(); 149 | g2d.drawString(letter, fontX, fontY); 150 | g2d.dispose(); 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /tests/test.properties: -------------------------------------------------------------------------------- 1 | package.name=ProM-Framework 2 | 3 | # name of build project 4 | test.projectname=${package.name}.test 5 | 6 | # location of plugin code, binaries, and test files (can be modified) 7 | home=${test.basedir}/.. 8 | #bin=${home}/bindist # set in build.xml 9 | #src=${home}/src # set in build.xml 10 | 11 | # location of tests and test files 12 | dir.test-src=${test.basedir}/src-test/ 13 | dir.test-bin=${test.basedir}/bin-test/ 14 | dir.testfiles=${test.basedir}/testfiles/ 15 | 16 | # default JUnit tests 17 | test.default=org/processmining/tests/**/*.java 18 | 19 | # location of test results (can be modified) 20 | dir.coveragereport.html=${test.basedir}/cover-html 21 | dir.coveragereport.xml=${test.basedir}/cover-xml --------------------------------------------------------------------------------