class DefaultPluginManager extends AbstractPluginManager {

    private static final Logger log = LoggerFactory.getLogger(DefaultPluginManager.class);

    public static final String PLUGINS_DIR_CONFIG_PROPERTY_NAME = "pf4j.pluginsConfigDir";

    public DefaultPluginManager() {
        super();
    }

    public DefaultPluginManager(Path... pluginsRoots) {
        super(pluginsRoots);
    }

    public DefaultPluginManager(List<Path> pluginsRoots) {
        super(pluginsRoots);
    }

    @Override
    protected PluginDescriptorFinder createPluginDescriptorFinder() {
        return new CompoundPluginDescriptorFinder()
            .add(new PropertiesPluginDescriptorFinder())
            .add(new ManifestPluginDescriptorFinder());
    }

    @Override
    protected ExtensionFinder createExtensionFinder() {
        DefaultExtensionFinder extensionFinder = new DefaultExtensionFinder(this);
        addPluginStateListener(extensionFinder);

        return extensionFinder;
    }

    @Override
    protected PluginFactory createPluginFactory() {
        return new DefaultPluginFactory();
    }

    @Override
    protected ExtensionFactory createExtensionFactory() {
        return new DefaultExtensionFactory();
    }

    @Override
    protected PluginStatusProvider createPluginStatusProvider() {
        String configDir = System.getProperty(PLUGINS_DIR_CONFIG_PROPERTY_NAME);
        Path configPath = configDir != null
            ? Paths.get(configDir)
            : getPluginsRoots().stream()
            .findFirst()
            .orElseThrow(() -> new IllegalArgumentException("No pluginsRoot configured"));

        return new DefaultPluginStatusProvider(configPath);
    }

    @Override
    protected PluginRepository createPluginRepository() {
        return new CompoundPluginRepository()
            .add(new DevelopmentPluginRepository(getPluginsRoots()), this::isDevelopment)
            .add(new JarPluginRepository(getPluginsRoots()), this::isNotDevelopment)
            .add(new DefaultPluginRepository(getPluginsRoots()), this::isNotDevelopment);
    }

    @Override
    protected PluginLoader createPluginLoader() {
        return new CompoundPluginLoader()
            .add(new DevelopmentPluginLoader(this), this::isDevelopment)
            .add(new JarPluginLoader(this), this::isNotDevelopment)
            .add(new DefaultPluginLoader(this), this::isNotDevelopment);
    }

    @Override
    protected VersionManager createVersionManager() {
        return new DefaultVersionManager();
    }

    @Override
    protected void initialize() {
        super.initialize();

        if (isDevelopment()) {
            addPluginStateListener(new LoggingPluginStateListener());
        }

        log.info("PF4J version {} in '{}' mode", getVersion(), getRuntimeMode());
    }

    /**
     * Load a plugin from disk. If the path is a zip file, first unpack.
     *
     * @param pluginPath plugin location on disk
     * @return PluginWrapper for the loaded plugin or null if not loaded
     * @throws PluginRuntimeException if problems during load
     */
    @Override
    protected PluginWrapper loadPluginFromPath(Path pluginPath) {<FILL_FUNCTION_BODY>}

}

        // First unzip any ZIP files
        try {
            pluginPath = FileUtils.expandIfZip(pluginPath);
        } catch (Exception e) {
            log.warn("Failed to unzip " + pluginPath, e);
            return null;
        }

        return super.loadPluginFromPath(pluginPath);
    
<methods>public synchronized void addPluginStateListener(org.pf4j.PluginStateListener) ,public boolean deletePlugin(java.lang.String) ,public boolean disablePlugin(java.lang.String) ,public boolean enablePlugin(java.lang.String) ,public Set<java.lang.String> getExtensionClassNames(java.lang.String) ,public List<Class<?>> getExtensionClasses(java.lang.String) ,public List<Class<? extends T>> getExtensionClasses(Class<T>) ,public List<Class<? extends T>> getExtensionClasses(Class<T>, java.lang.String) ,public org.pf4j.ExtensionFactory getExtensionFactory() ,public List<T> getExtensions(Class<T>) ,public List<T> getExtensions(Class<T>, java.lang.String) ,public List#RAW getExtensions(java.lang.String) ,public org.pf4j.PluginWrapper getPlugin(java.lang.String) ,public java.lang.ClassLoader getPluginClassLoader(java.lang.String) ,public org.pf4j.PluginLoader getPluginLoader() ,public List<org.pf4j.PluginWrapper> getPlugins() ,public List<org.pf4j.PluginWrapper> getPlugins(org.pf4j.PluginState) ,public java.nio.file.Path getPluginsRoot() ,public List<java.nio.file.Path> getPluginsRoots() ,public List<org.pf4j.PluginWrapper> getResolvedPlugins() ,public org.pf4j.RuntimeMode getRuntimeMode() ,public List<org.pf4j.PluginWrapper> getStartedPlugins() ,public java.lang.String getSystemVersion() ,public List<org.pf4j.PluginWrapper> getUnresolvedPlugins() ,public java.lang.String getVersion() ,public org.pf4j.VersionManager getVersionManager() ,public boolean isExactVersionAllowed() ,public java.lang.String loadPlugin(java.nio.file.Path) ,public void loadPlugins() ,public synchronized void removePluginStateListener(org.pf4j.PluginStateListener) ,public void setExactVersionAllowed(boolean) ,public void setSystemVersion(java.lang.String) ,public org.pf4j.PluginState startPlugin(java.lang.String) ,public void startPlugins() ,public org.pf4j.PluginState stopPlugin(java.lang.String) ,public void stopPlugins() ,public boolean unloadPlugin(java.lang.String) ,public void unloadPlugins() ,public org.pf4j.PluginWrapper whichPlugin(Class<?>) <variables>public static final java.lang.String DEFAULT_PLUGINS_DIR,public static final java.lang.String DEVELOPMENT_PLUGINS_DIR,public static final java.lang.String MODE_PROPERTY_NAME,public static final java.lang.String PLUGINS_DIR_PROPERTY_NAME,protected org.pf4j.DependencyResolver dependencyResolver,protected boolean exactVersionAllowed,protected org.pf4j.ExtensionFactory extensionFactory,protected org.pf4j.ExtensionFinder extensionFinder,private static final org.slf4j.Logger log,protected Map<java.lang.String,java.lang.ClassLoader> pluginClassLoaders,protected org.pf4j.PluginDescriptorFinder pluginDescriptorFinder,protected org.pf4j.PluginFactory pluginFactory,protected org.pf4j.PluginLoader pluginLoader,protected org.pf4j.PluginRepository pluginRepository,protected List<org.pf4j.PluginStateListener> pluginStateListeners,protected org.pf4j.PluginStatusProvider pluginStatusProvider,protected Map<java.lang.String,org.pf4j.PluginWrapper> plugins,protected final List<java.nio.file.Path> pluginsRoots,protected org.pf4j.AbstractPluginManager.ResolveRecoveryStrategy resolveRecoveryStrategy,protected List<org.pf4j.PluginWrapper> resolvedPlugins,protected org.pf4j.RuntimeMode runtimeMode,protected List<org.pf4j.PluginWrapper> startedPlugins,protected java.lang.String systemVersion,protected List<org.pf4j.PluginWrapper> unresolvedPlugins,protected org.pf4j.VersionManager versionManager