[Git][java-team/libpf4j-java][upstream] New upstream version 3.7.0+dfsg

Pierre Gruet (@pgt) gitlab at salsa.debian.org
Wed Jul 6 12:30:34 BST 2022



Pierre Gruet pushed to branch upstream at Debian Java Maintainers / libpf4j-java


Commits:
c958f621 by Pierre Gruet at 2022-07-04T22:02:32+02:00
New upstream version 3.7.0+dfsg
- - - - -


30 changed files:

- + .github/FUNDING.yml
- + .github/workflows/build.yml
- CHANGELOG.md
- README.md
- demo/api/pom.xml
- demo/app/pom.xml
- demo/plugins/plugin1/pom.xml
- demo/plugins/plugin2/pom.xml
- demo/plugins/pom.xml
- demo/pom.xml
- maven-archetypes/quickstart/pom.xml
- maven-archetypes/quickstart/src/main/resources/archetype-resources/pom.xml
- pf4j/pom.xml
- + pf4j/src/main/java-templates/org/pf4j/Pf4jInfo.java
- pf4j/src/main/java/module-info.java
- pf4j/src/main/java/org/pf4j/AbstractExtensionFinder.java
- pf4j/src/main/java/org/pf4j/AbstractPluginManager.java
- pf4j/src/main/java/org/pf4j/DefaultVersionManager.java
- pf4j/src/main/java/org/pf4j/ManifestPluginDescriptorFinder.java
- pf4j/src/main/java/org/pf4j/PluginClassLoader.java
- pf4j/src/main/java/org/pf4j/PropertiesPluginDescriptorFinder.java
- + pf4j/src/main/java/org/pf4j/SecurePluginManagerWrapper.java
- pf4j/src/main/java/org/pf4j/SingletonExtensionFactory.java
- pf4j/src/main/java/org/pf4j/util/FileUtils.java
- pf4j/src/test/java/org/pf4j/AbstractExtensionFinderTest.java
- pf4j/src/test/java/org/pf4j/AbstractPluginManagerTest.java
- pf4j/src/test/java/org/pf4j/DefaultVersionManagerTest.java
- + pf4j/src/test/java/org/pf4j/SecurePluginManagerWrapperTest.java
- pf4j/src/test/java/org/pf4j/SingletonExtensionFactoryTest.java
- pom.xml


Changes:

=====================================
.github/FUNDING.yml
=====================================
@@ -0,0 +1 @@
+github: decebals


=====================================
.github/workflows/build.yml
=====================================
@@ -0,0 +1,36 @@
+name: Build
+on:
+    push:
+        branches:
+            - '*'
+    pull_request:
+        types: [opened, synchronize, reopened]
+jobs:
+    build:
+        name: Build
+        runs-on: ubuntu-latest
+        steps:
+            - uses: actions/checkout at v2
+              with:
+                  fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
+            - name: Set up JDK 11
+              uses: actions/setup-java at v1
+              with:
+                  java-version: 11
+            - name: Cache SonarCloud packages
+              uses: actions/cache at v1
+              with:
+                  path: ~/.sonar/cache
+                  key: ${{ runner.os }}-sonar
+                  restore-keys: ${{ runner.os }}-sonar
+            - name: Cache Maven packages
+              uses: actions/cache at v1
+              with:
+                  path: ~/.m2
+                  key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+                  restore-keys: ${{ runner.os }}-m2
+            - name: Build and analyze
+              env:
+                  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}  # Needed to get PR information, if any
+                  SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+              run: cd pf4j && mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar


=====================================
CHANGELOG.md
=====================================
@@ -4,6 +4,27 @@ This project adheres to [Semantic Versioning](http://semver.org/).
 
 ### [Unreleased][unreleased]
 
+#### Fixed
+- [#435]: Fix the path separator used in the SingletonExtensionFactoryTest.java
+- [#451]: Fix Dependency version check fails even if required is '*'
+- [#490]: Fix memory leak in SingletonExtensionFactory
+
+#### Changed
+- Update mockito version from 2.24.0 to 3.8.0
+- [#426]: Update module-info.java
+- [#455]: Do not rely on version from Manifest
+- Update Log4j version to 2.17.1
+
+#### Added
+- [#430]: Add a unit test in AbstractExtensionFinderTest to reproduce #428
+- [#450]: Add wrapper to plugin manager (SecurePluginManagerWrapper)
+- Add code analyses via Sonar
+- Add support for reading plugin descriptor from zip
+
+#### Removed
+
+### [3.6.0] - 2021-01-16
+
 #### Fixed
 - [#394]: `DependencyResolver` lost dependent info after plugin stop
 
@@ -413,7 +434,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
 
 #### Removed
 
-[unreleased]: https://github.com/decebals/pf4j/compare/release-3.5.0...HEAD
+[unreleased]: https://github.com/decebals/pf4j/compare/release-3.6.0...HEAD
+[3.6.0]: https://github.com/decebals/pf4j/compare/release-3.5.0...release-3.6.0
 [3.5.0]: https://github.com/decebals/pf4j/compare/release-3.4.1...release-3.5.0
 [3.4.1]: https://github.com/decebals/pf4j/compare/release-3.4.0...release-3.4.1
 [3.4.1]: https://github.com/decebals/pf4j/compare/release-3.3.0...release-3.4.0
@@ -439,6 +461,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
 [0.11.0]: https://github.com/decebals/pf4j/compare/release-0.10.0...release-0.11.0
 [0.10.0]: https://github.com/decebals/pf4j/compare/release-0.9.0...release-0.10.0
 
+[#490]: https://github.com/pf4j/pf4j/pull/490
+[#455]: https://github.com/pf4j/pf4j/pull/455
+[#451]: https://github.com/pf4j/pf4j/pull/451
+[#450]: https://github.com/pf4j/pf4j/pull/450
+[#435]: https://github.com/pf4j/pf4j/pull/435
+[#430]: https://github.com/pf4j/pf4j/pull/430
+[#426]: https://github.com/pf4j/pf4j/pull/426
 [#415]: https://github.com/pf4j/pf4j/pull/415
 [#404]: https://github.com/pf4j/pf4j/pull/404
 [#402]: https://github.com/pf4j/pf4j/pull/402


=====================================
README.md
=====================================
@@ -156,7 +156,7 @@ PF4J is very customizable and comes with a lot of goodies. Please read the docum
 
 Documentation
 ---------------
-Documentation is available on [pf4j.org](http://www.pf4j.org)
+Documentation is available on [pf4j.org](http://pf4j.org)
 
 Demo
 ---------------


=====================================
demo/api/pom.xml
=====================================
@@ -4,12 +4,12 @@
     <parent>
         <groupId>org.pf4j.demo</groupId>
         <artifactId>pf4j-demo-parent</artifactId>
-        <version>3.6.0</version>
+        <version>3.7.0</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>pf4j-demo-api</artifactId>
-    <version>3.6.0</version>
+    <version>3.7.0</version>
     <packaging>jar</packaging>
     <name>Demo Api</name>
 


=====================================
demo/app/pom.xml
=====================================
@@ -4,12 +4,12 @@
     <parent>
         <groupId>org.pf4j.demo</groupId>
         <artifactId>pf4j-demo-parent</artifactId>
-        <version>3.6.0</version>
+        <version>3.7.0</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>pf4j-demo-app</artifactId>
-    <version>3.6.0</version>
+    <version>3.7.0</version>
     <packaging>jar</packaging>
     <name>Demo App</name>
 


=====================================
demo/plugins/plugin1/pom.xml
=====================================
@@ -4,12 +4,12 @@
     <parent>
         <groupId>org.pf4j.demo</groupId>
         <artifactId>pf4j-demo-plugins</artifactId>
-        <version>3.6.0</version>
+        <version>3.7.0</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>pf4j-demo-plugin1</artifactId>
-    <version>3.6.0</version>
+    <version>3.7.0</version>
     <packaging>jar</packaging>
     <name>Demo Plugin #1</name>
 


=====================================
demo/plugins/plugin2/pom.xml
=====================================
@@ -4,12 +4,12 @@
     <parent>
         <groupId>org.pf4j.demo</groupId>
         <artifactId>pf4j-demo-plugins</artifactId>
-        <version>3.6.0</version>
+        <version>3.7.0</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>pf4j-demo-plugin2</artifactId>
-    <version>3.6.0</version>
+    <version>3.7.0</version>
     <packaging>jar</packaging>
     <name>Demo Plugin #2</name>
 


=====================================
demo/plugins/pom.xml
=====================================
@@ -4,12 +4,12 @@
     <parent>
         <groupId>org.pf4j.demo</groupId>
         <artifactId>pf4j-demo-parent</artifactId>
-        <version>3.6.0</version>
+        <version>3.7.0</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>pf4j-demo-plugins</artifactId>
-    <version>3.6.0</version>
+    <version>3.7.0</version>
     <packaging>pom</packaging>
     <name>Demo Plugins Parent</name>
 


=====================================
demo/pom.xml
=====================================
@@ -4,13 +4,13 @@
     <parent>
         <groupId>org.pf4j</groupId>
         <artifactId>pf4j-parent</artifactId>
-        <version>3.6.0</version>
+        <version>3.7.0</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.pf4j.demo</groupId>
     <artifactId>pf4j-demo-parent</artifactId>
-    <version>3.6.0</version>
+    <version>3.7.0</version>
     <packaging>pom</packaging>
     <name>Demo Parent</name>
 


=====================================
maven-archetypes/quickstart/pom.xml
=====================================
@@ -4,7 +4,7 @@
     <parent>
         <groupId>org.pf4j</groupId>
         <artifactId>pf4j-parent</artifactId>
-        <version>3.6.0</version>
+        <version>3.7.0</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 


=====================================
maven-archetypes/quickstart/src/main/resources/archetype-resources/pom.xml
=====================================
@@ -27,7 +27,7 @@
 
         <pf4j.version>{{project.version}}</pf4j.version>
         <slf4j.version>1.7.25</slf4j.version>
-        <log4j.version>2.13.1</log4j.version>
+        <log4j.version>2.17.1</log4j.version>
     </properties>
 
     <build>


=====================================
pf4j/pom.xml
=====================================
@@ -4,18 +4,34 @@
     <parent>
         <groupId>org.pf4j</groupId>
         <artifactId>pf4j-parent</artifactId>
-        <version>3.6.0</version>
+        <version>3.7.0</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>pf4j</artifactId>
-    <version>3.6.0</version>
+    <version>3.7.0</version>
     <packaging>jar</packaging>
     <name>PF4J</name>
     <description>Plugin Framework for Java</description>
 
+    <properties>
+        <sonar.projectKey>pf4j_pf4j</sonar.projectKey>
+    </properties>
+
     <build>
         <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>templating-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>filter-src</id>
+                        <goals>
+                            <goal>filter-sources</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>


=====================================
pf4j/src/main/java-templates/org/pf4j/Pf4jInfo.java
=====================================
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2012-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.pf4j;
+
+/**
+ * This class provides access to the current Pf4j version which might otherwise not be possible:
+ * e.g. in Uber-Jars where the Manifest was merged and the Pf4j info was overridden
+ * @author Wolfram Haussig
+ */
+public class Pf4jInfo {
+    /**
+     * the current Pf4j version
+     */
+    public static final String VERSION = "${project.version}";
+}


=====================================
pf4j/src/main/java/module-info.java
=====================================
@@ -26,14 +26,14 @@ module org.pf4j {
     // provides javax.annotation
     requires java.compiler;
 
-    // provided by the ASM library
-    requires org.objectweb.asm;
+    // provided by the ASM library, use "requires static" since it's optional
+    requires static org.objectweb.asm;
 
     // The SLF4J library currently does not provide a module.
     // Version 1.8 provides a module called "org.slf4j". But this version is
     // currently in beta stage. Therefore I'm not sure, if we already like to
     // use it.
-    requires slf4j.api;
+    requires org.slf4j;
 
     // The java-semver library currently does not provide a module.
     // Maybe we should send them a pull request, that at least they provide an


=====================================
pf4j/src/main/java/org/pf4j/AbstractExtensionFinder.java
=====================================
@@ -83,7 +83,7 @@ public abstract class AbstractExtensionFinder implements ExtensionFinder, Plugin
 
         // classpath's extensions <=> pluginId = null
         Set<String> classNames = findClassNames(pluginId);
-        if (classNames == null || classNames.isEmpty()) {
+        if (classNames.isEmpty()) {
             return result;
         }
 
@@ -218,7 +218,12 @@ public abstract class AbstractExtensionFinder implements ExtensionFinder, Plugin
 
     @Override
     public Set<String> findClassNames(String pluginId) {
-        return getEntries().get(pluginId);
+        Set<String> classNames = getEntries().get(pluginId);
+        if (classNames == null) {
+            return Collections.emptySet();
+        }
+
+        return classNames;
     }
 
     @Override


=====================================
pf4j/src/main/java/org/pf4j/AbstractPluginManager.java
=====================================
@@ -660,17 +660,7 @@ public abstract class AbstractPluginManager implements PluginManager {
     }
 
     public String getVersion() {
-        String version = null;
-
-        Package pf4jPackage = PluginManager.class.getPackage();
-        if (pf4jPackage != null) {
-            version = pf4jPackage.getImplementationVersion();
-            if (version == null) {
-                version = pf4jPackage.getSpecificationVersion();
-            }
-        }
-
-        return (version != null) ? version : "0.0.0";
+        return Pf4jInfo.VERSION;
     }
 
     protected abstract PluginRepository createPluginRepository();
@@ -860,10 +850,7 @@ public abstract class AbstractPluginManager implements PluginManager {
         ClassLoader pluginClassLoader = getPluginLoader().loadPlugin(pluginPath, pluginDescriptor);
         log.debug("Loaded plugin '{}' with class loader '{}'", pluginPath, pluginClassLoader);
 
-        // create the plugin wrapper
-        log.debug("Creating wrapper for plugin '{}'", pluginPath);
-        PluginWrapper pluginWrapper = new PluginWrapper(this, pluginDescriptor, pluginPath, pluginClassLoader);
-        pluginWrapper.setPluginFactory(getPluginFactory());
+        PluginWrapper pluginWrapper = createPluginWrapper(pluginDescriptor, pluginPath, pluginClassLoader);
 
         // test for disabled plugin
         if (isPluginDisabled(pluginDescriptor.getPluginId())) {
@@ -890,6 +877,19 @@ public abstract class AbstractPluginManager implements PluginManager {
 
         return pluginWrapper;
     }
+    
+    /**
+     * creates the plugin wrapper. override this if you want to prevent plugins having full access to the plugin manager
+     * 
+     * @return
+     */
+    protected PluginWrapper createPluginWrapper(PluginDescriptor pluginDescriptor, Path pluginPath, ClassLoader pluginClassLoader) {
+        // create the plugin wrapper
+        log.debug("Creating wrapper for plugin '{}'", pluginPath);
+        PluginWrapper pluginWrapper = new PluginWrapper(this, pluginDescriptor, pluginPath, pluginClassLoader);
+        pluginWrapper.setPluginFactory(getPluginFactory());
+        return pluginWrapper;
+    }
 
     /**
      * Tests for already loaded plugins on given path.


=====================================
pf4j/src/main/java/org/pf4j/DefaultVersionManager.java
=====================================
@@ -39,7 +39,7 @@ public class DefaultVersionManager implements VersionManager {
      */
     @Override
     public boolean checkVersionConstraint(String version, String constraint) {
-        return StringUtils.isNullOrEmpty(constraint) || Version.valueOf(version).satisfies(constraint);
+        return StringUtils.isNullOrEmpty(constraint) || "*".equals(constraint) || Version.valueOf(version).satisfies(constraint);
     }
 
     @Override


=====================================
pf4j/src/main/java/org/pf4j/ManifestPluginDescriptorFinder.java
=====================================
@@ -27,6 +27,8 @@ import java.nio.file.Path;
 import java.util.jar.Attributes;
 import java.util.jar.JarFile;
 import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
 
 /**
  * Read the plugin descriptor from the manifest file.
@@ -48,7 +50,7 @@ public class ManifestPluginDescriptorFinder implements PluginDescriptorFinder {
 
     @Override
     public boolean isApplicable(Path pluginPath) {
-        return Files.exists(pluginPath) && (Files.isDirectory(pluginPath) || FileUtils.isJarFile(pluginPath));
+        return Files.exists(pluginPath) && (Files.isDirectory(pluginPath) || FileUtils.isZipOrJarFile(pluginPath));
     }
 
     @Override
@@ -60,40 +62,14 @@ public class ManifestPluginDescriptorFinder implements PluginDescriptorFinder {
 
     protected Manifest readManifest(Path pluginPath) {
         if (FileUtils.isJarFile(pluginPath)) {
-            try (JarFile jar = new JarFile(pluginPath.toFile())) {
-                Manifest manifest = jar.getManifest();
-                if (manifest != null) {
-                    return manifest;
-                }
-            } catch (IOException e) {
-                throw new PluginRuntimeException(e);
-            }
-        }
-
-        Path manifestPath = getManifestPath(pluginPath);
-        if (manifestPath == null) {
-            throw new PluginRuntimeException("Cannot find the manifest path");
-        }
-
-        log.debug("Lookup plugin descriptor in '{}'", manifestPath);
-        if (Files.notExists(manifestPath)) {
-            throw new PluginRuntimeException("Cannot find '{}' path", manifestPath);
+            return readManifestFromJar(pluginPath);
         }
 
-        try (InputStream input = Files.newInputStream(manifestPath)) {
-            return new Manifest(input);
-        } catch (IOException e) {
-            throw new PluginRuntimeException(e);
-        }
-    }
-
-    protected Path getManifestPath(Path pluginPath) {
-        if (Files.isDirectory(pluginPath)) {
-            // legacy (the path is something like "classes/META-INF/MANIFEST.MF")
-            return FileUtils.findFile(pluginPath,"MANIFEST.MF");
+        if (FileUtils.isZipFile(pluginPath)) {
+            return readManifestFromZip(pluginPath);
         }
 
-        return null;
+        return readManifestFromDirectory(pluginPath);
     }
 
     protected PluginDescriptor createPluginDescriptor(Manifest manifest) {
@@ -140,4 +116,42 @@ public class ManifestPluginDescriptorFinder implements PluginDescriptorFinder {
         return new DefaultPluginDescriptor();
     }
 
+    protected Manifest readManifestFromJar(Path jarPath) {
+        try (JarFile jar = new JarFile(jarPath.toFile())) {
+            return jar.getManifest();
+        } catch (IOException e) {
+            throw new PluginRuntimeException(e, "Cannot read manifest from {}", jarPath);
+        }
+    }
+
+    protected Manifest readManifestFromZip(Path zipPath) {
+        try (ZipFile zip = new ZipFile(zipPath.toFile())) {
+            ZipEntry manifestEntry = zip.getEntry("classes/META-INF/MANIFEST.MF");
+            try (InputStream manifestInput = zip.getInputStream(manifestEntry)) {
+                return new Manifest(manifestInput);
+            }
+        } catch (IOException e) {
+            throw new PluginRuntimeException(e, "Cannot read manifest from {}", zipPath);
+        }
+    }
+
+    protected Manifest readManifestFromDirectory(Path pluginPath) {
+        // legacy (the path is something like "classes/META-INF/MANIFEST.MF")
+        Path manifestPath = FileUtils.findFile(pluginPath,"MANIFEST.MF");
+        if (manifestPath == null) {
+            throw new PluginRuntimeException("Cannot find the manifest path");
+        }
+
+        log.debug("Lookup plugin descriptor in '{}'", manifestPath);
+        if (Files.notExists(manifestPath)) {
+            throw new PluginRuntimeException("Cannot find '{}' path", manifestPath);
+        }
+
+        try (InputStream input = Files.newInputStream(manifestPath)) {
+            return new Manifest(input);
+        } catch (IOException e) {
+            throw new PluginRuntimeException(e, "Cannot read manifest from {}", pluginPath);
+        }
+    }
+
 }


=====================================
pf4j/src/main/java/org/pf4j/PluginClassLoader.java
=====================================
@@ -103,7 +103,7 @@ public class PluginClassLoader extends URLClassLoader {
             }
 
             // if the class is part of the plugin engine use parent class loader
-            if (className.startsWith(PLUGIN_PACKAGE_PREFIX) && !className.startsWith("org.pf4j.demo")) {
+            if (className.startsWith(PLUGIN_PACKAGE_PREFIX) && !className.startsWith("org.pf4j.demo") && !className.startsWith("org.pf4j.test")) {
 //                log.trace("Delegate the loading of PF4J class '{}' to parent", className);
                 return getParent().loadClass(className);
             }


=====================================
pf4j/src/main/java/org/pf4j/PropertiesPluginDescriptorFinder.java
=====================================
@@ -59,7 +59,7 @@ public class PropertiesPluginDescriptorFinder implements PluginDescriptorFinder
 
     @Override
     public boolean isApplicable(Path pluginPath) {
-        return Files.exists(pluginPath) && (Files.isDirectory(pluginPath) || FileUtils.isJarFile(pluginPath));
+        return Files.exists(pluginPath) && (Files.isDirectory(pluginPath) || FileUtils.isZipOrJarFile(pluginPath));
     }
 
     @Override
@@ -97,13 +97,13 @@ public class PropertiesPluginDescriptorFinder implements PluginDescriptorFinder
     protected Path getPropertiesPath(Path pluginPath, String propertiesFileName) {
         if (Files.isDirectory(pluginPath)) {
             return pluginPath.resolve(Paths.get(propertiesFileName));
-        } else {
-            // it's a jar file
-            try {
-                return FileUtils.getPath(pluginPath, propertiesFileName);
-            } catch (IOException e) {
-                throw new PluginRuntimeException(e);
-            }
+        }
+
+        // it's a zip or jar file
+        try {
+            return FileUtils.getPath(pluginPath, propertiesFileName);
+        } catch (IOException e) {
+            throw new PluginRuntimeException(e);
         }
     }
 


=====================================
pf4j/src/main/java/org/pf4j/SecurePluginManagerWrapper.java
=====================================
@@ -0,0 +1,305 @@
+package org.pf4j;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Use this class to wrap the original plugin manager to prevent full access from within plugins.
+ * Override AbstractPluginManager.createPluginWrapper to use this class
+ * @author Wolfram Haussig
+ *
+ */
+public class SecurePluginManagerWrapper implements PluginManager {
+
+    private static final String PLUGIN_PREFIX = "Plugin ";
+    /**
+     * the current plugin
+     */
+    private String currentPluginId;
+    /**
+     * the original plugin manager
+     */
+    private PluginManager original;
+
+    /**
+     * The registered {@link PluginStateListener}s.
+     */
+    protected List<PluginStateListener> pluginStateListeners = new ArrayList<>();
+    /**
+     * wrapper for pluginStateListeners
+     */
+    private PluginStateListenerWrapper listenerWrapper = new PluginStateListenerWrapper();
+
+    /**
+     * constructor
+     * @param original the original plugin manager
+     * @param currentPlugin the current pluginId
+     */
+    public SecurePluginManagerWrapper(PluginManager original, String currentPluginId) {
+        this.original = original;
+        this.currentPluginId = currentPluginId;
+    }
+
+    @Override
+    public boolean isDevelopment() {
+        return original.isDevelopment();
+    }
+
+    @Override
+    public boolean isNotDevelopment() {
+        return original.isNotDevelopment();
+    }
+
+    @Override
+    public List<PluginWrapper> getPlugins() {
+        return Arrays.asList(getPlugin(currentPluginId));
+    }
+
+    @Override
+    public List<PluginWrapper> getPlugins(PluginState pluginState) {
+        return getPlugins().stream().filter(p -> p.getPluginState() == pluginState).collect(Collectors.toList());
+    }
+
+    @Override
+    public List<PluginWrapper> getResolvedPlugins() {
+        return getPlugins().stream().filter(p -> p.getPluginState().ordinal() >= PluginState.RESOLVED.ordinal()).collect(Collectors.toList());
+    }
+
+    @Override
+    public List<PluginWrapper> getUnresolvedPlugins() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public List<PluginWrapper> getStartedPlugins() {
+        return getPlugins(PluginState.STARTED);
+    }
+
+    @Override
+    public PluginWrapper getPlugin(String pluginId) {
+        if (currentPluginId.equals(pluginId)) {
+            return original.getPlugin(pluginId);
+        } else {
+            throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getPlugin for foreign pluginId!");
+        }
+    }
+
+    @Override
+    public void loadPlugins() {
+        throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute loadPlugins!");
+    }
+
+    @Override
+    public String loadPlugin(Path pluginPath) {
+        throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute loadPlugin!");
+    }
+
+    @Override
+    public void startPlugins() {
+        throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute startPlugins!");
+    }
+
+    @Override
+    public PluginState startPlugin(String pluginId) {
+        throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute startPlugin!");
+    }
+
+    @Override
+    public void stopPlugins() {
+        throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute stopPlugins!");
+    }
+
+    @Override
+    public PluginState stopPlugin(String pluginId) {
+        if (currentPluginId.equals(pluginId)) {
+            return original.stopPlugin(pluginId);
+        } else {
+            throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute stopPlugin for foreign pluginId!");
+        }
+    }
+
+    @Override
+    public void unloadPlugins() {
+        throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute unloadPlugins!");
+    }
+
+    @Override
+    public boolean unloadPlugin(String pluginId) {
+        if (currentPluginId.equals(pluginId)) {
+            return original.unloadPlugin(pluginId);
+        } else {
+            throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute unloadPlugin for foreign pluginId!");
+        }
+    }
+
+    @Override
+    public boolean disablePlugin(String pluginId) {
+        if (currentPluginId.equals(pluginId)) {
+            return original.disablePlugin(pluginId);
+        } else {
+            throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute disablePlugin for foreign pluginId!");
+        }
+    }
+
+    @Override
+    public boolean enablePlugin(String pluginId) {
+        throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute enablePlugin!");
+    }
+
+    @Override
+    public boolean deletePlugin(String pluginId) {
+        if (currentPluginId.equals(pluginId)) {
+            return original.deletePlugin(pluginId);
+        } else {
+            throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute deletePlugin for foreign pluginId!");
+        }
+    }
+
+    @Override
+    public ClassLoader getPluginClassLoader(String pluginId) {
+        if (currentPluginId.equals(pluginId)) {
+            return original.getPluginClassLoader(pluginId);
+        } else {
+            throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getPluginClassLoader for foreign pluginId!");
+        }
+    }
+
+    @Override
+    public List<Class<?>> getExtensionClasses(String pluginId) {
+        if (currentPluginId.equals(pluginId)) {
+            return original.getExtensionClasses(pluginId);
+        } else {
+            throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getExtensionClasses for foreign pluginId!");
+        }
+    }
+
+    @Override
+    public <T> List<Class<? extends T>> getExtensionClasses(Class<T> type) {
+        return getExtensionClasses(type, currentPluginId);
+    }
+
+    @Override
+    public <T> List<Class<? extends T>> getExtensionClasses(Class<T> type, String pluginId) {
+        if (currentPluginId.equals(pluginId)) {
+            return original.getExtensionClasses(type, pluginId);
+        } else {
+            throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getExtensionClasses for foreign pluginId!");
+        }
+    }
+
+    @Override
+    public <T> List<T> getExtensions(Class<T> type) {
+        return getExtensions(type, currentPluginId);
+    }
+
+    @Override
+    public <T> List<T> getExtensions(Class<T> type, String pluginId) {
+        if (currentPluginId.equals(pluginId)) {
+            return original.getExtensions(type, pluginId);
+        } else {
+            throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getExtensions for foreign pluginId!");
+        }
+    }
+
+    @Override
+    public List<?> getExtensions(String pluginId) {
+        if (currentPluginId.equals(pluginId)) {
+            return original.getExtensions(pluginId);
+        } else {
+            throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getExtensions for foreign pluginId!");
+        }
+    }
+
+    @Override
+    public Set<String> getExtensionClassNames(String pluginId) {
+        if (currentPluginId.equals(pluginId)) {
+            return original.getExtensionClassNames(pluginId);
+        } else {
+            throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getExtensionClassNames for foreign pluginId!");
+        }
+    }
+
+    @Override
+    public ExtensionFactory getExtensionFactory() {
+        return original.getExtensionFactory();
+    }
+
+    @Override
+    public RuntimeMode getRuntimeMode() {
+        return original.getRuntimeMode();
+    }
+
+    @Override
+    public PluginWrapper whichPlugin(Class<?> clazz) {
+        ClassLoader classLoader = clazz.getClassLoader();
+        PluginWrapper plugin = getPlugin(currentPluginId);
+        if (plugin.getPluginClassLoader() == classLoader) {
+            return plugin;
+        }
+        return null;
+    }
+
+    @Override
+    public void addPluginStateListener(PluginStateListener listener) {
+        if (pluginStateListeners.isEmpty()) {
+            this.original.addPluginStateListener(listenerWrapper);
+        }
+        pluginStateListeners.add(listener);
+    }
+
+    @Override
+    public void removePluginStateListener(PluginStateListener listener) {
+        pluginStateListeners.remove(listener);
+        if (pluginStateListeners.isEmpty()) {
+            this.original.removePluginStateListener(listenerWrapper);
+        }
+    }
+
+    @Override
+    public void setSystemVersion(String version) {
+        throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute setSystemVersion!");
+    }
+
+    @Override
+    public String getSystemVersion() {
+        return original.getSystemVersion();
+    }
+
+    @Override
+    public Path getPluginsRoot() {
+        throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getPluginsRoot!");
+    }
+
+    @Override
+    public List<Path> getPluginsRoots() {
+        throw new IllegalAccessError(PLUGIN_PREFIX + currentPluginId + " tried to execute getPluginsRoots!");
+    }
+
+    @Override
+    public VersionManager getVersionManager() {
+        return original.getVersionManager();
+    }
+
+    /**
+     * Wrapper for PluginStateListener events. will only propagate events if they match the current pluginId
+     * @author Wolfram Haussig
+     *
+     */
+    private class PluginStateListenerWrapper implements PluginStateListener {
+
+        @Override
+        public void pluginStateChanged(PluginStateEvent event) {
+            if (event.getPlugin().getPluginId().equals(currentPluginId)) {
+                for (PluginStateListener listener : pluginStateListeners) {
+                    listener.pluginStateChanged(event);
+                }
+            }
+        }
+
+    }
+}


=====================================
pf4j/src/main/java/org/pf4j/SingletonExtensionFactory.java
=====================================
@@ -19,7 +19,6 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.WeakHashMap;
 
 /**
  * An {@link ExtensionFactory} that always returns a specific instance.
@@ -32,12 +31,18 @@ public class SingletonExtensionFactory extends DefaultExtensionFactory {
 
     private final List<String> extensionClassNames;
 
-    private Map<ClassLoader, Map<String, Object>> cache;
+    private final Map<ClassLoader, Map<String, Object>> cache;
 
-    public SingletonExtensionFactory(String... extensionClassNames) {
+    public SingletonExtensionFactory(PluginManager pluginManager, String... extensionClassNames) {
         this.extensionClassNames = Arrays.asList(extensionClassNames);
 
-        cache = new WeakHashMap<>(); // simple cache implementation
+        cache = new HashMap<>();
+
+        pluginManager.addPluginStateListener(event -> {
+            if (event.getPluginState() != PluginState.STARTED) {
+                cache.remove(event.getPlugin().getPluginClassLoader());
+            }
+        });
     }
 
     @Override


=====================================
pf4j/src/main/java/org/pf4j/util/FileUtils.java
=====================================
@@ -217,9 +217,19 @@ public final class FileUtils {
         return Files.isRegularFile(path) && path.toString().toLowerCase().endsWith(".jar");
     }
 
+    /**
+     * Return true only if path is a jar or zip file.
+     *
+     * @param path to a file/dir
+     * @return true if file ending in {@code .zip} or {@code .jar}
+     */
+    public static boolean isZipOrJarFile(Path path) {
+        return isZipFile(path) || isJarFile(path);
+    }
+
     public static Path getPath(Path path, String first, String... more) throws IOException {
         URI uri = path.toUri();
-        if (isJarFile(path)) {
+        if (isZipOrJarFile(path)) {
             String pathString = path.toAbsolutePath().toString();
             // transformation for Windows OS
             pathString = StringUtils.addStart(pathString.replace("\\", "/"), "/");


=====================================
pf4j/src/test/java/org/pf4j/AbstractExtensionFinderTest.java
=====================================
@@ -19,6 +19,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.io.ByteStreams;
 import com.google.testing.compile.Compilation;
 import java.util.Comparator;
+import java.util.UUID;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -204,6 +205,45 @@ public class AbstractExtensionFinderTest {
         assertEquals(1, result.size());
     }
 
+    /**
+     * Test of {@link org.pf4j.AbstractExtensionFinder#find(java.lang.String)}.
+     */
+    @Test
+    public void testFindExtensionWrappersFromPluginId() {
+        ExtensionFinder instance = new AbstractExtensionFinder(pluginManager) {
+
+            @Override
+            public Map<String, Set<String>> readPluginsStorages() {
+                Map<String, Set<String>> entries = new LinkedHashMap<>();
+
+                Set<String> bucket = new HashSet<>();
+                bucket.add("org.pf4j.test.TestExtension");
+                bucket.add("org.pf4j.test.FailTestExtension");
+                entries.put("plugin1", bucket);
+                bucket = new HashSet<>();
+                bucket.add("org.pf4j.test.TestExtension");
+                entries.put("plugin2", bucket);
+
+                return entries;
+            }
+
+            @Override
+            public Map<String, Set<String>> readClasspathStorages() {
+                return Collections.emptyMap();
+            }
+
+        };
+
+        List<ExtensionWrapper> plugin1Result = instance.find("plugin1");
+        assertEquals(2, plugin1Result.size());
+
+        List<ExtensionWrapper> plugin2Result = instance.find("plugin2");
+        assertEquals(0, plugin2Result.size());
+
+        List<ExtensionWrapper> plugin3Result = instance.find(UUID.randomUUID().toString());
+        assertEquals(0, plugin3Result.size());
+    }
+
     @Test
     public void findExtensionAnnotation() throws Exception {
         Compilation compilation = javac().compile(ExtensionAnnotationProcessorTest.Greeting,


=====================================
pf4j/src/test/java/org/pf4j/AbstractPluginManagerTest.java
=====================================
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.mockito.Mockito.CALLS_REAL_METHODS;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -45,5 +46,11 @@ public class AbstractPluginManagerTest {
         List<TestExtensionPoint> extensions = pluginManager.getExtensions(TestExtensionPoint.class);
         assertEquals(1, extensions.size());
     }
+    
+    @Test
+    public void getVersion() {
+        AbstractPluginManager pluginManager = mock(AbstractPluginManager.class, CALLS_REAL_METHODS);
+        assertNotEquals("0.0.0", pluginManager.getVersion());
+    }
 
 }


=====================================
pf4j/src/test/java/org/pf4j/DefaultVersionManagerTest.java
=====================================
@@ -39,6 +39,7 @@ public class DefaultVersionManagerTest {
     public void checkVersionConstraint() {
         assertFalse(versionManager.checkVersionConstraint("1.4.3", ">2.0.0")); // simple
         assertTrue(versionManager.checkVersionConstraint("1.4.3", ">=1.4.0 & <1.6.0")); // range
+        assertTrue(versionManager.checkVersionConstraint("undefined", "*"));
     }
 
     @Test


=====================================
pf4j/src/test/java/org/pf4j/SecurePluginManagerWrapperTest.java
=====================================
@@ -0,0 +1,272 @@
+package org.pf4j;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+import org.pf4j.test.PluginJar;
+import org.pf4j.test.TestExtension;
+import org.pf4j.test.TestExtensionPoint;
+import org.pf4j.test.TestPlugin;
+
+public class SecurePluginManagerWrapperTest {
+
+    private static final String OTHER_PLUGIN_ID = "test-plugin-2";
+    private static final String THIS_PLUGIN_ID = "test-plugin-1";
+    private PluginJar thisPlugin;
+    private PluginJar otherPlugin;
+    private PluginManager pluginManager;
+    private PluginManager wrappedPluginManager;
+    private int pluginManagerEvents = 0;
+    private int wrappedPluginManagerEvents = 0;
+
+    @TempDir
+    Path pluginsPath;
+
+    @BeforeEach
+    public void setUp() throws IOException {
+        pluginManagerEvents = 0;
+        wrappedPluginManagerEvents = 0;
+        thisPlugin = new PluginJar.Builder(pluginsPath.resolve("test-plugin1.jar"), THIS_PLUGIN_ID).pluginClass(TestPlugin.class.getName()).pluginVersion("1.2.3").extension(TestExtension.class.getName()).build();
+        otherPlugin = new PluginJar.Builder(pluginsPath.resolve("test-plugin2.jar"), OTHER_PLUGIN_ID).pluginClass(TestPlugin.class.getName()).pluginVersion("1.2.3").extension(TestExtension.class.getName()).build();
+
+        pluginManager = new JarPluginManager(pluginsPath);
+        wrappedPluginManager = new SecurePluginManagerWrapper(pluginManager, THIS_PLUGIN_ID);
+    }
+
+    @AfterEach
+    public void tearDown() {
+        pluginManager.unloadPlugins();
+
+        thisPlugin = null;
+        otherPlugin = null;
+        pluginManager = null;
+    }
+
+    @Test
+    public void pluginStateListeners() {
+        pluginManager.addPluginStateListener(new PluginStateListener() {
+            @Override
+            public void pluginStateChanged(PluginStateEvent event) {
+                pluginManagerEvents++;
+            }
+        });
+        wrappedPluginManager.addPluginStateListener(new PluginStateListener() {
+            @Override
+            public void pluginStateChanged(PluginStateEvent event) {
+                wrappedPluginManagerEvents++;
+            }
+        });
+        pluginManager.loadPlugins();
+        pluginManager.startPlugins();
+        assertEquals(4, pluginManagerEvents);
+        assertEquals(2, wrappedPluginManagerEvents);
+    }
+
+    @Test
+    public void deletePlugin() {
+        pluginManager.loadPlugins();
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.deletePlugin(OTHER_PLUGIN_ID));
+        assertTrue(wrappedPluginManager.deletePlugin(THIS_PLUGIN_ID));
+    }
+
+    @Test
+    public void disablePlugin() {
+        pluginManager.loadPlugins();
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.disablePlugin(OTHER_PLUGIN_ID));
+        assertTrue(wrappedPluginManager.disablePlugin(THIS_PLUGIN_ID));
+    }
+
+    @Test
+    public void enablePlugin() {
+        pluginManager.loadPlugins();
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.enablePlugin(OTHER_PLUGIN_ID));
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.enablePlugin(THIS_PLUGIN_ID));
+    }
+
+    @Test
+    public void getExtensionClasses() {
+        pluginManager.loadPlugins();
+        pluginManager.startPlugins();
+        assertEquals(1, wrappedPluginManager.getExtensionClasses(TestExtensionPoint.class).size());
+
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getExtensionClasses(TestExtensionPoint.class, OTHER_PLUGIN_ID));
+        assertEquals(1, wrappedPluginManager.getExtensionClasses(TestExtensionPoint.class, THIS_PLUGIN_ID).size());
+
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getExtensionClasses(OTHER_PLUGIN_ID));
+        assertEquals(1, wrappedPluginManager.getExtensionClasses(THIS_PLUGIN_ID).size());
+    }
+
+    @Test
+    public void getExtensionClassNames() {
+        pluginManager.loadPlugins();
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getExtensionClassNames(OTHER_PLUGIN_ID));
+        assertEquals(1, wrappedPluginManager.getExtensionClassNames(THIS_PLUGIN_ID).size());
+    }
+
+    @Test
+    public void getExtensionFactory() {
+        pluginManager.loadPlugins();
+        assertEquals(pluginManager.getExtensionFactory(), wrappedPluginManager.getExtensionFactory());
+    }
+
+    @Test
+    public void getExtensions() {
+        pluginManager.loadPlugins();
+        pluginManager.startPlugins();
+        assertEquals(1, wrappedPluginManager.getExtensions(TestExtensionPoint.class).size());
+
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getExtensions(TestExtensionPoint.class, OTHER_PLUGIN_ID));
+        assertEquals(1, wrappedPluginManager.getExtensions(TestExtensionPoint.class, THIS_PLUGIN_ID).size());
+
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getExtensions(OTHER_PLUGIN_ID));
+        assertEquals(1, wrappedPluginManager.getExtensions(THIS_PLUGIN_ID).size());
+    }
+
+    @Test
+    public void getPlugin() {
+        pluginManager.loadPlugins();
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getPlugin(OTHER_PLUGIN_ID));
+        assertEquals(THIS_PLUGIN_ID, wrappedPluginManager.getPlugin(THIS_PLUGIN_ID).getPluginId());
+    }
+
+    @Test
+    public void getPluginClassLoader() {
+        pluginManager.loadPlugins();
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getPluginClassLoader(OTHER_PLUGIN_ID));
+        assertNotNull(wrappedPluginManager.getPluginClassLoader(THIS_PLUGIN_ID));
+    }
+
+    @Test
+    public void getPlugins() {
+        pluginManager.loadPlugins();
+        assertEquals(2, pluginManager.getPlugins().size());
+        assertEquals(1, wrappedPluginManager.getPlugins().size());
+    }
+
+    @Test
+    public void getPluginsRoot() {
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getPluginsRoot());
+    }
+
+    @Test
+    public void getPluginsRoots() {
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.getPluginsRoots());
+    }
+
+    @Test
+    public void getResolvedPlugins() {
+        pluginManager.loadPlugins();
+        assertEquals(2, pluginManager.getResolvedPlugins().size());
+        assertEquals(1, wrappedPluginManager.getResolvedPlugins().size());
+    }
+
+    @Test
+    public void getRuntimeMode() {
+        assertEquals(pluginManager.getRuntimeMode(), wrappedPluginManager.getRuntimeMode());
+    }
+
+    @Test
+    public void getStartedPlugins() {
+        pluginManager.loadPlugins();
+        pluginManager.startPlugins();
+        assertEquals(2, pluginManager.getStartedPlugins().size());
+        assertEquals(1, wrappedPluginManager.getStartedPlugins().size());
+    }
+
+    @Test
+    public void getSystemVersion() {
+        assertEquals(pluginManager.getSystemVersion(), wrappedPluginManager.getSystemVersion());
+    }
+
+    @Test
+    public void getUnresolvedPlugins() {
+        assertNotNull(wrappedPluginManager);
+        assertNotNull(wrappedPluginManager.getUnresolvedPlugins());
+        assertTrue(wrappedPluginManager.getUnresolvedPlugins().isEmpty());
+    }
+
+    @Test
+    public void getVersionManager() {
+        assertEquals(pluginManager.getVersionManager(), wrappedPluginManager.getVersionManager());
+    }
+
+    @Test
+    public void isDevelopment() {
+        assertEquals(pluginManager.isDevelopment(), wrappedPluginManager.isDevelopment());
+    }
+
+    @Test
+    public void isNotDevelopment() {
+        assertEquals(pluginManager.isNotDevelopment(), wrappedPluginManager.isNotDevelopment());
+    }
+
+    @Test
+    public void loadPlugin() {
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.loadPlugin(thisPlugin.path()));
+    }
+
+    @Test
+    public void loadPlugins() {
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.loadPlugins());
+    }
+
+    @Test
+    public void setSystemVersion() {
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.setSystemVersion("1.0.0"));
+    }
+
+    @Test
+    public void startPlugin() {
+        pluginManager.loadPlugins();
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.startPlugin(OTHER_PLUGIN_ID));
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.startPlugin(THIS_PLUGIN_ID));
+    }
+
+    @Test
+    public void startPlugins() {
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.startPlugins());
+    }
+
+    @Test
+    public void stopPlugin() {
+        pluginManager.loadPlugins();
+        pluginManager.startPlugins();
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.stopPlugin(OTHER_PLUGIN_ID));
+        assertEquals(PluginState.STOPPED, wrappedPluginManager.stopPlugin(THIS_PLUGIN_ID));
+    }
+
+    @Test
+    public void stopPlugins() {
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.stopPlugins());
+    }
+
+    @Test
+    public void unloadPlugin() {
+        pluginManager.loadPlugins();
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.unloadPlugin(OTHER_PLUGIN_ID));
+        assertTrue(wrappedPluginManager.unloadPlugin(THIS_PLUGIN_ID));
+    }
+
+    @Test
+    public void unloadPlugins() {
+        assertThrows(IllegalAccessError.class, () -> wrappedPluginManager.unloadPlugins());
+    }
+
+    @Test
+    public void whichPlugin() {
+        pluginManager.loadPlugins();
+        pluginManager.startPlugins();
+        assertEquals(null, wrappedPluginManager.whichPlugin(pluginManager.getExtensionClasses(OTHER_PLUGIN_ID).get(0)));
+        assertEquals(THIS_PLUGIN_ID, wrappedPluginManager.whichPlugin(pluginManager.getExtensionClasses(THIS_PLUGIN_ID).get(0)).getPluginId());
+    }
+}


=====================================
pf4j/src/test/java/org/pf4j/SingletonExtensionFactoryTest.java
=====================================
@@ -15,6 +15,8 @@
  */
 package org.pf4j;
 
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.pf4j.test.FailTestExtension;
 import org.pf4j.test.TestExtension;
@@ -33,9 +35,21 @@ import static org.junit.jupiter.api.Assertions.assertSame;
  */
 public class SingletonExtensionFactoryTest {
 
+    private PluginManager pluginManager;
+
+    @BeforeEach
+    public void setUp() {
+        pluginManager = new DefaultPluginManager();
+    }
+
+    @AfterEach
+    public void tearDown() {
+        pluginManager = null;
+    }
+
     @Test
     public void create() {
-        ExtensionFactory extensionFactory = new SingletonExtensionFactory();
+        ExtensionFactory extensionFactory = new SingletonExtensionFactory(pluginManager);
         Object extensionOne = extensionFactory.create(TestExtension.class);
         Object extensionTwo = extensionFactory.create(TestExtension.class);
         assertSame(extensionOne, extensionTwo);
@@ -43,7 +57,7 @@ public class SingletonExtensionFactoryTest {
 
     @Test
     public void createNewEachTime() {
-        ExtensionFactory extensionFactory = new SingletonExtensionFactory(FailTestExtension.class.getName());
+        ExtensionFactory extensionFactory = new SingletonExtensionFactory(pluginManager, FailTestExtension.class.getName());
         Object extensionOne = extensionFactory.create(TestExtension.class);
         Object extensionTwo = extensionFactory.create(TestExtension.class);
         assertNotSame(extensionOne, extensionTwo);
@@ -52,7 +66,7 @@ public class SingletonExtensionFactoryTest {
     @Test
     @SuppressWarnings("unchecked")
     public void createNewEachTimeFromDifferentClassLoaders() throws Exception {
-        ExtensionFactory extensionFactory = new SingletonExtensionFactory();
+        ExtensionFactory extensionFactory = new SingletonExtensionFactory(pluginManager);
 
         // Get classpath locations
         URL[] classpathReferences = getClasspathReferences();
@@ -74,7 +88,7 @@ public class SingletonExtensionFactoryTest {
     private URL[] getClasspathReferences() throws MalformedURLException {
         String classpathProperty = System.getProperty("java.class.path");
 
-        String[] classpaths = classpathProperty.split(":");
+        String[] classpaths = classpathProperty.split(File.pathSeparator);
         URL[] uris = new URL[classpaths.length];
 
         for (int index = 0; index < classpaths.length; index++) {


=====================================
pom.xml
=====================================
@@ -10,10 +10,11 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.pf4j</groupId>
     <artifactId>pf4j-parent</artifactId>
-    <version>3.6.0</version>
+    <version>3.7.0</version>
     <packaging>pom</packaging>
     <name>PF4J Parent</name>
     <description>Plugin Framework for Java</description>
+    <url>https://pf4j.org</url>
 
     <licenses>
         <license>
@@ -27,7 +28,7 @@
         <connection>scm:git:https://github.com/pf4j/pf4j.git</connection>
         <developerConnection>scm:git:git at github.com:pf4j/pf4j.git</developerConnection>
         <url>git at github.com/pf4j/pf4j.git</url>
-        <tag>release-3.6.0</tag>
+        <tag>release-3.7.0</tag>
     </scm>
 
     <distributionManagement>
@@ -45,19 +46,22 @@
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <maven.compiler.release>8</maven.compiler.release>
 
-        <slf4j.version>1.7.25</slf4j.version>
-        <log4j.version>2.13.1</log4j.version>
-        <asm.version>7.1</asm.version>
+        <slf4j.version>1.7.30</slf4j.version>
+        <log4j.version>2.17.1</log4j.version>
+        <asm.version>9.1</asm.version>
 
         <junit.version>5.4.0</junit.version>
         <hamcrest.version>2.1</hamcrest.version>
-        <mockito.version>2.24.0</mockito.version>
+        <mockito.version>3.8.0</mockito.version>
         <cobertura.version>2.7</cobertura.version>
         <coveralls.version>3.1.0</coveralls.version>
 
         <javadoc.disabled>false</javadoc.disabled>
         <deploy.disabled>false</deploy.disabled>
         <source.disabled>false</source.disabled>
+
+        <sonar.organization>pf4j</sonar.organization>
+        <sonar.host.url>https://sonarcloud.io</sonar.host.url>
     </properties>
 
     <build>



View it on GitLab: https://salsa.debian.org/java-team/libpf4j-java/-/commit/c958f6217510ab92412fbb31027e40d5a37facb2

-- 
View it on GitLab: https://salsa.debian.org/java-team/libpf4j-java/-/commit/c958f6217510ab92412fbb31027e40d5a37facb2
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20220706/33c2d2bd/attachment.htm>


More information about the pkg-java-commits mailing list