You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hop.apache.org by ha...@apache.org on 2021/02/01 19:14:59 UTC

[incubator-hop] branch master updated: HOP-2479 Remove IPluginFolder - Move the construction of the plugin folders list to the JarCache class - Removes the need to call populateFolders() in each PluginType - Replace usage List to Set in JarCache - Add HOP_PLUGIN_BASE_FOLDERS, HOP_SHARED_JDBC_FOLDER to AboutDialog

This is an automated email from the ASF dual-hosted git repository.

hansva pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-hop.git


The following commit(s) were added to refs/heads/master by this push:
     new 303613a  HOP-2479 Remove IPluginFolder - Move the construction of the plugin folders list to the JarCache class - Removes the need to call populateFolders() in each PluginType - Replace usage List to Set in JarCache - Add HOP_PLUGIN_BASE_FOLDERS,HOP_SHARED_JDBC_FOLDER to AboutDialog
     new f07314f  Merge pull request #589 from nadment/HOP-2479
303613a is described below

commit 303613a5c623925c60076f98259e3fb5763a4ee0
Author: nadment <na...@gmail.com>
AuthorDate: Sat Jan 30 13:02:57 2021 +0100

    HOP-2479 Remove IPluginFolder
    - Move the construction of the plugin folders list to the JarCache class
    - Removes the need to call populateFolders() in each PluginType
    - Replace usage List to Set in JarCache
    - Add HOP_PLUGIN_BASE_FOLDERS,HOP_SHARED_JDBC_FOLDER to AboutDialog
---
 core/src/main/java/org/apache/hop/core/Const.java  |   2 +
 .../hop/core/config/plugin/ConfigPluginType.java   |   3 +-
 .../hop/core/database/DatabasePluginType.java      |   5 +-
 .../TwoWayPasswordEncoderPluginType.java           |   8 +-
 .../core/extension/ExtensionPointPluginType.java   |   4 +-
 .../apache/hop/core/gui/plugin/GuiPluginType.java  |   3 +-
 .../apache/hop/core/logging/LoggingPluginType.java |   4 +-
 .../apache/hop/core/plugins/BaseFragmentType.java  |   1 -
 .../apache/hop/core/plugins/BasePluginType.java    | 199 ++++++-----------
 .../org/apache/hop/core/plugins/IPluginFolder.java |  53 -----
 .../org/apache/hop/core/plugins/IPluginType.java   |   5 -
 .../java/org/apache/hop/core/plugins/JarCache.java | 243 +++++++++++++++++++++
 .../org/apache/hop/core/plugins/JarFileCache.java  | 142 ------------
 .../{JarFilePlugin.java => PluginClassFile.java}   |  21 +-
 .../org/apache/hop/core/plugins/PluginFolder.java  | 212 ------------------
 .../apache/hop/core/plugins/PluginRegistry.java    |   5 +-
 .../hop/core/row/value/ValueMetaPluginType.java    |   3 +-
 .../core/search/SearchableAnalyserPluginType.java  |   4 +-
 .../apache/hop/core/vfs/plugin/VfsPluginType.java  |   4 +-
 .../hop/metadata/plugin/MetadataPluginType.java    |   4 +-
 .../apache/hop/core/plugins/PluginFolderTest.java  | 233 --------------------
 .../auth/AuthenticationConsumerPluginType.java     |   4 +-
 .../auth/AuthenticationProviderPluginType.java     |   4 +-
 .../hop/core/compress/CompressionPluginType.java   |   4 +-
 .../apache/hop/core/plugins/ActionPluginType.java  |   3 +-
 .../hop/core/plugins/HopServerPluginType.java      |   3 +-
 .../hop/core/plugins/PartitionerPluginType.java    |   4 +-
 .../hop/core/plugins/TransformPluginType.java      |   3 +-
 .../pipeline/engine/PipelineEnginePluginType.java  |   6 +-
 .../transform/RowDistributionPluginType.java       |   3 +-
 .../workflow/engine/WorkflowEnginePluginType.java  |   5 +-
 .../HopPipelineMetaToBeamPipelineConverter.java    |  17 +-
 .../hop/beam/pipeline/fatjar/FatJarBuilder.java    |   6 +-
 .../apache/hop/ui/hopgui/dialog/AboutDialog.java   |   2 +-
 .../hop/ui/hopgui/file/HopFileTypePluginType.java  |   5 +-
 .../perspective/HopPerspectivePluginType.java      |   6 +-
 .../pipeline/dialog/PipelineDialogPluginType.java  |   5 +-
 .../workflow/dialog/WorkflowDialogPluginType.java  |   4 +-
 38 files changed, 357 insertions(+), 885 deletions(-)

diff --git a/core/src/main/java/org/apache/hop/core/Const.java b/core/src/main/java/org/apache/hop/core/Const.java
index ef98894..30b77c6 100644
--- a/core/src/main/java/org/apache/hop/core/Const.java
+++ b/core/src/main/java/org/apache/hop/core/Const.java
@@ -512,6 +512,8 @@ public class Const {
    */
   public static final String HOP_PLUGIN_PACKAGES = "HOP_PLUGIN_PACKAGES";
 
+  public static final String HOP_PLUGIN_BASE_FOLDERS = "HOP_PLUGIN_BASE_FOLDERS";
+  
   /**
    * Name of the environment variable that contains the size of the pipeline rowset size. This
    * overwrites values that you set pipeline settings.
diff --git a/core/src/main/java/org/apache/hop/core/config/plugin/ConfigPluginType.java b/core/src/main/java/org/apache/hop/core/config/plugin/ConfigPluginType.java
index 5761d90..4a19ebd 100644
--- a/core/src/main/java/org/apache/hop/core/config/plugin/ConfigPluginType.java
+++ b/core/src/main/java/org/apache/hop/core/config/plugin/ConfigPluginType.java
@@ -31,12 +31,11 @@ import java.util.Map;
  */
 @PluginMainClassType( IConfigOptions.class )
 @PluginAnnotationType( ConfigPlugin.class )
-public class ConfigPluginType extends BasePluginType<ConfigPlugin> implements IPluginType<ConfigPlugin> {
+public class ConfigPluginType extends BasePluginType<ConfigPlugin> {
   private static ConfigPluginType pluginType;
 
   private ConfigPluginType() {
     super( ConfigPlugin.class, "CONFIG", "Configuration" );
-    populateFolders();
   }
 
   public static ConfigPluginType getInstance() {
diff --git a/core/src/main/java/org/apache/hop/core/database/DatabasePluginType.java b/core/src/main/java/org/apache/hop/core/database/DatabasePluginType.java
index e51e4fe..765d613 100644
--- a/core/src/main/java/org/apache/hop/core/database/DatabasePluginType.java
+++ b/core/src/main/java/org/apache/hop/core/database/DatabasePluginType.java
@@ -29,16 +29,15 @@ import java.util.Map;
  *
  * @author matt
  */
-public class DatabasePluginType extends BasePluginType<DatabaseMetaPlugin> implements IPluginType<DatabaseMetaPlugin> {
+public class DatabasePluginType extends BasePluginType<DatabaseMetaPlugin> {
   private static DatabasePluginType pluginType;
 
   private DatabasePluginType() {
     super( DatabaseMetaPlugin.class, "DATABASE", "Database" );
-    populateFolders();
 
     String sharedJdbcDirectory = System.getProperty( Const.HOP_SHARED_JDBC_FOLDER );
     if ( StringUtils.isNotEmpty(sharedJdbcDirectory)) {
-      extraLibraryFolders.add(sharedJdbcDirectory);
+      getExtraLibraryFolders().add(sharedJdbcDirectory);
     }
   }
 
diff --git a/core/src/main/java/org/apache/hop/core/encryption/TwoWayPasswordEncoderPluginType.java b/core/src/main/java/org/apache/hop/core/encryption/TwoWayPasswordEncoderPluginType.java
index e6b1656..af6d2c0 100644
--- a/core/src/main/java/org/apache/hop/core/encryption/TwoWayPasswordEncoderPluginType.java
+++ b/core/src/main/java/org/apache/hop/core/encryption/TwoWayPasswordEncoderPluginType.java
@@ -32,13 +32,12 @@ import java.util.Map;
 
 @PluginMainClassType( ITwoWayPasswordEncoder.class )
 @PluginAnnotationType( TwoWayPasswordEncoderPlugin.class )
-public class TwoWayPasswordEncoderPluginType extends BasePluginType<TwoWayPasswordEncoderPlugin> implements IPluginType<TwoWayPasswordEncoderPlugin> {
+public class TwoWayPasswordEncoderPluginType extends BasePluginType<TwoWayPasswordEncoderPlugin> {
 
   private static TwoWayPasswordEncoderPluginType twoWayPasswordEncoderPluginType;
 
   private TwoWayPasswordEncoderPluginType() {
     super( TwoWayPasswordEncoderPlugin.class, "TWOWAYPASSWORDENCODERPLUGIN", "TwoWayPasswordEncoder" );
-    populateFolders();
   }
 
   public static TwoWayPasswordEncoderPluginType getInstance() {
@@ -49,11 +48,6 @@ public class TwoWayPasswordEncoderPluginType extends BasePluginType<TwoWayPasswo
   }
 
   @Override
-  protected boolean isReturn() {
-    return true;
-  }
-
-  @Override
   protected String extractCategory( TwoWayPasswordEncoderPlugin annotation ) {
     return null;
   }
diff --git a/core/src/main/java/org/apache/hop/core/extension/ExtensionPointPluginType.java b/core/src/main/java/org/apache/hop/core/extension/ExtensionPointPluginType.java
index 0eabb51..e2020be 100644
--- a/core/src/main/java/org/apache/hop/core/extension/ExtensionPointPluginType.java
+++ b/core/src/main/java/org/apache/hop/core/extension/ExtensionPointPluginType.java
@@ -18,7 +18,6 @@
 package org.apache.hop.core.extension;
 
 import org.apache.hop.core.plugins.BasePluginType;
-import org.apache.hop.core.plugins.IPluginType;
 import org.apache.hop.core.plugins.PluginAnnotationType;
 import org.apache.hop.core.plugins.PluginMainClassType;
 
@@ -31,12 +30,11 @@ import java.util.Map;
  */
 @PluginMainClassType( IExtensionPoint.class )
 @PluginAnnotationType( ExtensionPoint.class )
-public class ExtensionPointPluginType extends BasePluginType<ExtensionPoint> implements IPluginType<ExtensionPoint> {
+public class ExtensionPointPluginType extends BasePluginType<ExtensionPoint> {
   private static ExtensionPointPluginType pluginType;
 
   private ExtensionPointPluginType() {
     super( ExtensionPoint.class, "EXTENSION_POINT", "Extension point" );
-    populateFolders();
   }
 
   public static ExtensionPointPluginType getInstance() {
diff --git a/core/src/main/java/org/apache/hop/core/gui/plugin/GuiPluginType.java b/core/src/main/java/org/apache/hop/core/gui/plugin/GuiPluginType.java
index 7ad48ed..fd9ec3c 100644
--- a/core/src/main/java/org/apache/hop/core/gui/plugin/GuiPluginType.java
+++ b/core/src/main/java/org/apache/hop/core/gui/plugin/GuiPluginType.java
@@ -29,12 +29,11 @@ import java.util.Map;
  * @author matt
  */
 @PluginAnnotationType( GuiPlugin.class )
-public class GuiPluginType extends BasePluginType<GuiPlugin> implements IPluginType<GuiPlugin> {
+public class GuiPluginType extends BasePluginType<GuiPlugin> {
   private static GuiPluginType pluginType;
 
   private GuiPluginType() {
     super( GuiPlugin.class, "GUI", "GUI" );
-    populateFolders();
   }
 
   public static GuiPluginType getInstance() {
diff --git a/core/src/main/java/org/apache/hop/core/logging/LoggingPluginType.java b/core/src/main/java/org/apache/hop/core/logging/LoggingPluginType.java
index 67db52a..191d7dc 100644
--- a/core/src/main/java/org/apache/hop/core/logging/LoggingPluginType.java
+++ b/core/src/main/java/org/apache/hop/core/logging/LoggingPluginType.java
@@ -18,7 +18,6 @@
 package org.apache.hop.core.logging;
 
 import org.apache.hop.core.plugins.BasePluginType;
-import org.apache.hop.core.plugins.IPluginType;
 import org.apache.hop.core.plugins.PluginAnnotationType;
 import org.apache.hop.core.plugins.PluginMainClassType;
 import org.apache.hop.core.util.Utils;
@@ -32,13 +31,12 @@ import java.util.Map;
  */
 @PluginMainClassType( ILoggingPlugin.class )
 @PluginAnnotationType( LoggingPlugin.class )
-public class LoggingPluginType extends BasePluginType<LoggingPlugin> implements IPluginType<LoggingPlugin> {
+public class LoggingPluginType extends BasePluginType<LoggingPlugin> {
 
   private static LoggingPluginType loggingPluginType;
 
   private LoggingPluginType() {
     super( LoggingPlugin.class, "LOGGING", "Logging Plugin" );
-    populateFolders();
   }
 
   public static LoggingPluginType getInstance() {
diff --git a/core/src/main/java/org/apache/hop/core/plugins/BaseFragmentType.java b/core/src/main/java/org/apache/hop/core/plugins/BaseFragmentType.java
index 9350de4..e31c272 100644
--- a/core/src/main/java/org/apache/hop/core/plugins/BaseFragmentType.java
+++ b/core/src/main/java/org/apache/hop/core/plugins/BaseFragmentType.java
@@ -26,7 +26,6 @@ public abstract class BaseFragmentType<T extends Annotation> extends BasePluginT
 
   BaseFragmentType( Class<T> pluginType, String id, String name, Class<? extends IPluginType> typeToTrack ) {
     super( pluginType, id, name );
-    populateFolders();
     initListeners( this.getClass(), typeToTrack );
   }
 
diff --git a/core/src/main/java/org/apache/hop/core/plugins/BasePluginType.java b/core/src/main/java/org/apache/hop/core/plugins/BasePluginType.java
index 18279eb..9f268fe 100644
--- a/core/src/main/java/org/apache/hop/core/plugins/BasePluginType.java
+++ b/core/src/main/java/org/apache/hop/core/plugins/BasePluginType.java
@@ -33,6 +33,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 import org.apache.commons.io.FileUtils;
@@ -59,25 +60,21 @@ import com.google.common.annotations.VisibleForTesting;
 public abstract class BasePluginType<T extends Annotation> implements IPluginType<T> {
   protected static Class<?> classFromResourcesPackage = BasePluginType.class; // For Translator
 
-  protected String id;
-  protected String name;
-  protected List<IPluginFolder> pluginFolders;
-
-  protected PluginRegistry registry;
-
-  protected LogChannel log;
+  protected final PluginRegistry registry;
+  
+  private String id;
+  
+  private String name;
 
-  protected Map<Class<?>, String> objectTypes = new HashMap<>();
+  private LogChannel log;
 
-  protected boolean searchLibDir;
+  private Map<Class<?>, String> objectTypes = new HashMap<>();
 
   private Class<T> pluginClass;
 
-  protected List<String> extraLibraryFolders;
-
+  private List<String> extraLibraryFolders;
   
   public BasePluginType( Class<T> pluginClazz ) {
-    this.pluginFolders = new ArrayList<>();
     this.log = new LogChannel( "Plugin type" );
 
     registry = PluginRegistry.getInstance();
@@ -96,31 +93,6 @@ public abstract class BasePluginType<T extends Annotation> implements IPluginTyp
     this.name = name;
   }
 
-  /**
-   * This method return parameter for registerPlugins() method
-   *
-   * @return Path
-   */
-  protected String getPath() {
-    return null;
-  }
-
-  /**
-   * This method return parameter for registerNatives() method
-   *
-   * @return Flag ("return;" or "throw exception")
-   */
-  protected boolean isReturn() {
-    return false;
-  }
-
-  /**
-   * this is a utility method for subclasses so they can easily register which folders contain plugins
-   */
-  protected void populateFolders() {
-    pluginFolders.addAll( PluginFolder.populateFolders() );
-  }
-
   public Map<Class<?>, String> getAdditionalRuntimeObjectTypes() {
     return objectTypes;
   }
@@ -138,28 +110,28 @@ public abstract class BasePluginType<T extends Annotation> implements IPluginTyp
   /** Let's put in code here to search for the transform plugins.. */
   @Override
   public void searchPlugins() throws HopPluginException {
-      
-    StopWatch watch = new StopWatch();
-    watch.start();
+
+    StopWatch watch = new StopWatch();    
+    if ( log.isDebug() ) {
+      watch.start();
+    }    
     
     // Register natives plugins
     registerNatives();
     
-    // Register plugins from plugin folder
+    // Register plugins from plugin folders
     registerPluginJars();
-    
-    watch.stop();
-    
-    List<Plugin> plugins = registry.getPlugins(this.getClass());
-    
-//    if ( log.isBasic() ) {
-//	log.logBasic(pluginClass.getSimpleName()+" register " + plugins.size()+ " plugins (Time Elapsed: " + watch.getTime()+"ms)"); 
-//    }
+     
+    if ( log.isDebug() ) {
+      watch.stop();
+      List<Plugin> plugins = registry.getPlugins(this.getClass());
+      log.logBasic(pluginClass.getSimpleName()+" register " + plugins.size()+ " plugins (Time Elapsed: " + watch.getTime()+"ms)"); 
+    }
   }
 
   protected void registerNatives() throws HopPluginException {
     try {
-      JarFileCache cache = JarFileCache.getInstance();
+      JarCache cache = JarCache.getInstance();
       DotName pluginName = DotName.createSimple(pluginClass.getName());
       for (File jarFile : cache.getNativeJars()) {
         IndexView index = cache.getIndex(jarFile);
@@ -236,21 +208,6 @@ public abstract class BasePluginType<T extends Annotation> implements IPluginTyp
     this.name = name;
   }
 
-  /**
-   * @return the pluginFolders
-   */
-  @Override
-  public List<IPluginFolder> getPluginFolders() {
-    return pluginFolders;
-  }
-
-  /**
-   * @param pluginFolders the pluginFolders to set
-   */
-  public void setPluginFolders( List<IPluginFolder> pluginFolders ) {
-    this.pluginFolders = pluginFolders;
-  }
-
   protected static String getCodedTranslation( String codedString ) {
     if ( codedString == null ) {
       return null;
@@ -344,49 +301,44 @@ public abstract class BasePluginType<T extends Annotation> implements IPluginTyp
     }
   }
 
-  protected List<JarFilePlugin> findAnnotatedClassFiles(String annotationClassName) throws HopPluginException {
-    JarFileCache cache = JarFileCache.getInstance();
-   
-    List<JarFilePlugin> classFiles = new ArrayList<>();
+  protected List<PluginClassFile> findAnnotatedClassFiles(String annotationClassName)
+      throws HopPluginException {
+    JarCache cache = JarCache.getInstance();
 
-    // Scan the plugins folder for annotation index files...
-    //
-    for (IPluginFolder pluginFolder : getPluginFolders()) {
+    List<PluginClassFile> classFiles = new ArrayList<>();
 
-      if (pluginFolder.isPluginAnnotationsFolder()) {
+    try {
+      // Get all the jar files with annotation index files...
+      //      
+      for (File jarFile : cache.getPluginJars()) {
 
-        try {
-          // Get all the jar files in the plugin folder...
-          //
-          for (File jarFile : cache.getJars(pluginFolder)) {
-
-            // These are the jar files : find annotations in it...
-            //
-            IndexView index = cache.getIndex(jarFile);
-            // find annotations annotated with this meta-annotation
-            for (AnnotationInstance instance :
-                index.getAnnotations(DotName.createSimple(pluginClass.getName()))) {
-              if (instance.target() instanceof ClassInfo) {
-                try {
-                  ClassInfo classInfo = (ClassInfo) instance.target();
-                  String className = classInfo.name().toString();
-                  
-                  File folder = jarFile.getParentFile();
-                  
-                  classFiles.add(new JarFilePlugin(className, jarFile.toURI().toURL(), folder.toURI().toURL()));
-
-                } catch (Exception e) {
-                  System.out.println(
-                      "Error searching annotation for " + pluginClass + " in " + jarFile);
-                }
-              }
+        // These are the jar files : find annotations in it...
+        //
+        IndexView index = cache.getIndex(jarFile);
+        // find annotations annotated with this meta-annotation
+        for (AnnotationInstance instance :
+            index.getAnnotations(DotName.createSimple(pluginClass.getName()))) {
+          if (instance.target() instanceof ClassInfo) {
+            try {
+              ClassInfo classInfo = (ClassInfo) instance.target();
+              String className = classInfo.name().toString();
+
+              File folder = jarFile.getParentFile();
+
+              classFiles.add(
+                  new PluginClassFile(className, jarFile.toURI().toURL(), folder.toURI().toURL()));
+
+            } catch (Exception e) {
+              System.out.println(
+                  "Error searching annotation for " + pluginClass + " in " + jarFile);
             }
           }
-        } catch (Exception e) {
-            throw new HopPluginException("Error finding plugin annotation "+annotationClassName, e);
         }
       }
+    } catch (Exception e) {
+      throw new HopPluginException("Error finding plugin annotation " + annotationClassName, e);
     }
+
     return classFiles;
   }
 
@@ -471,14 +423,13 @@ public abstract class BasePluginType<T extends Annotation> implements IPluginTyp
     // Also append all the files in the underlying lib folder if it exists...
     //
     try {
-
+      JarCache jarCache = JarCache.getInstance();
+      
       String parentFolderName = new File( URLDecoder.decode( jarFileUrl.getFile(), "UTF-8" ) ).getParent();
 
-      String libFolderName = parentFolderName + Const.FILE_SEPARATOR + "lib";
-      if ( new File( libFolderName ).exists() ) {
-        PluginFolder pluginFolder = new PluginFolder( libFolderName, false, true, searchLibDir );
-        File[] libFiles = pluginFolder.findJarFiles( true );
-        for ( File libFile : libFiles ) {
+      File libFolder = new File(parentFolderName + Const.FILE_SEPARATOR + "lib");
+      if ( libFolder.exists() ) {        
+        for ( File libFile : jarCache.findJarFiles(libFolder) ) {
           urls.add( libFile.toURI().toURL() );
         }
       }
@@ -501,10 +452,8 @@ public abstract class BasePluginType<T extends Annotation> implements IPluginTyp
           if ( dependenciesFolder.exists() ) {
             // Now get the jar files in this dependency folder
             // This includes the possible lib/ folder dependencies in there
-            //
-            PluginFolder pluginFolder = new PluginFolder( dependenciesFolderName, false, false, true );
-            File[] libFiles = pluginFolder.findJarFiles( true );
-            for ( File libFile : libFiles ) {
+            //            
+            for ( File libFile : jarCache.findJarFiles(dependenciesFolder) ) {
               urls.add( libFile.toURI().toURL() );
             }
           }
@@ -575,40 +524,28 @@ public abstract class BasePluginType<T extends Annotation> implements IPluginTyp
     return new String[] {};
   }
 
-  /**
-   * When set to true the PluginFolder objects created by this type will be instructed to search for additional plugins
-   * in the lib directory of plugin folders.
-   *
-   * @param searchLibDir
-   */
-  protected void setSearchLibDirs( boolean searchLibDir ) {
-    this.searchLibDir = searchLibDir;
-  }
-
   protected void registerPluginJars() throws HopPluginException {
-      
-    //System.out.println("Register folder plugins: " + pluginClass.getName());
-          
-    List<JarFilePlugin> jarFilePlugins = findAnnotatedClassFiles(pluginClass.getName());
-    for ( JarFilePlugin jarFilePlugin : jarFilePlugins ) {
+                
+    List<PluginClassFile> pluginClassFiles = findAnnotatedClassFiles(pluginClass.getName());
+    for ( PluginClassFile pluginClassFile : pluginClassFiles ) {
 
-      URLClassLoader urlClassLoader = createUrlClassLoader( jarFilePlugin.getJarFile(), getClass().getClassLoader() );
+      URLClassLoader urlClassLoader = createUrlClassLoader( pluginClassFile.getJarFile(), getClass().getClassLoader() );
 
       try {
-        Class<?> clazz = urlClassLoader.loadClass( jarFilePlugin.getClassName() );
+        Class<?> clazz = urlClassLoader.loadClass( pluginClassFile.getClassName() );
         if ( clazz == null ) {
-          throw new HopPluginException( "Unable to load class: " + jarFilePlugin.getClassName() );
+          throw new HopPluginException( "Unable to load class: " + pluginClassFile.getClassName() );
         }
         List<String> libraries = Arrays.stream( urlClassLoader.getURLs() )
           .map( URL::getFile )
           .collect( Collectors.toList() );
         T annotation = clazz.getAnnotation( pluginClass );
         
-        handlePluginAnnotation( clazz, annotation, libraries, false, jarFilePlugin.getPluginFolder() );
+        handlePluginAnnotation( clazz, annotation, libraries, false, pluginClassFile.getFolder() );
       } catch ( Exception e ) {
         // Ignore for now, don't know if it's even possible.
         LogChannel.GENERAL.logError(
-          "Unexpected error registering jar plugin file: " + jarFilePlugin.getJarFile(), e );
+          "Unexpected error registering jar plugin file: " + pluginClassFile.getJarFile(), e );
       } finally {
         if ( urlClassLoader instanceof HopURLClassLoader ) {
           ( (HopURLClassLoader) urlClassLoader ).closeClassLoader();
@@ -627,7 +564,7 @@ public abstract class BasePluginType<T extends Annotation> implements IPluginTyp
    * @param pluginFolder     The plugin folder to use
    * @throws HopPluginException
    */
-  @Override
+  //@Override
   public void handlePluginAnnotation( Class<?> clazz, T annotation, List<String> libraries, boolean nativePluginType, URL pluginFolder ) throws HopPluginException {
 
     String idList = extractID( annotation );
diff --git a/core/src/main/java/org/apache/hop/core/plugins/IPluginFolder.java b/core/src/main/java/org/apache/hop/core/plugins/IPluginFolder.java
deleted file mode 100644
index 96a666f..0000000
--- a/core/src/main/java/org/apache/hop/core/plugins/IPluginFolder.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.hop.core.plugins;
-
-import org.apache.hop.core.exception.HopFileException;
-
-import java.io.File;
-
-/**
- * Describes a possible location for a plugin
- *
- * @author matt
- */
-public interface IPluginFolder {
-
-  /**
-   * @return The folder location
-   */
-  String getFolder();
-
-  /**
-   * @return true if the folder needs to be searched for plugin.xml appearances
-   */
-  boolean isPluginXmlFolder();
-
-  /**
-   * @return true if the folder needs to be searched for jar files with plugin annotations
-   */
-  boolean isPluginAnnotationsFolder();
-
-  /**
-   * Find all the jar files in this plugin folder
-   *
-   * @return The jar files
-   * @throws HopFileException In case there is a problem reading
-   */
-  File[] findJarFiles() throws HopFileException;
-}
diff --git a/core/src/main/java/org/apache/hop/core/plugins/IPluginType.java b/core/src/main/java/org/apache/hop/core/plugins/IPluginType.java
index 983f04f..3f481a5 100644
--- a/core/src/main/java/org/apache/hop/core/plugins/IPluginType.java
+++ b/core/src/main/java/org/apache/hop/core/plugins/IPluginType.java
@@ -52,11 +52,6 @@ public interface IPluginType<T extends Annotation> {
   String getName();
 
   /**
-   * @return The places where we should look for plugins, both as plugin.xml and as
-   */
-  List<IPluginFolder> getPluginFolders();
-
-  /**
    * @throws HopPluginException
    */
   void searchPlugins() throws HopPluginException;
diff --git a/core/src/main/java/org/apache/hop/core/plugins/JarCache.java b/core/src/main/java/org/apache/hop/core/plugins/JarCache.java
new file mode 100644
index 0000000..e2b6f6d
--- /dev/null
+++ b/core/src/main/java/org/apache/hop/core/plugins/JarCache.java
@@ -0,0 +1,243 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.hop.core.plugins;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.hop.core.Const;
+import org.apache.hop.core.exception.HopFileException;
+import org.apache.hop.core.util.EnvUtil;
+import org.apache.hop.core.variables.Variables;
+import org.jboss.jandex.Index;
+import org.jboss.jandex.IndexReader;
+
+public class JarCache {
+  
+  public static final String ANNOTATION_INDEX_LOCATION = "META-INF/jandex.idx";
+
+  private static JarCache instance;
+
+  private final Map<File, Index> indexCache;
+  private final Map<File, Set<File>> jarFiles;
+  private final Set<File> nativeFiles;
+  private final Set<File> pluginFiles;
+  
+  private JarCache() {
+    nativeFiles = new HashSet<>();
+    pluginFiles = new HashSet<>();
+    jarFiles = new HashMap<>();
+    indexCache = new HashMap<>();
+  }
+
+  public static JarCache getInstance() {
+    if (instance == null) {
+      instance = new JarCache();
+    }
+    return instance;
+  }
+    
+  /**
+   * Create a list of plugin folders based on the default or variable HOP_PLUGIN_BASE_FOLDERS
+   *
+   * @return The list of plugin folders found
+   */
+  public  List<String> getPluginFolders() {
+    List<String> pluginFolders = new ArrayList<>();
+
+    String folderPaths = Const.NVL( Variables.getADefaultVariableSpace().getVariable( Const.HOP_PLUGIN_BASE_FOLDERS ), EnvUtil.getSystemProperty( Const.HOP_PLUGIN_BASE_FOLDERS ) );
+    if ( folderPaths == null ) {
+      folderPaths = Const.DEFAULT_PLUGIN_BASE_FOLDERS;
+    }
+
+    // for each folder in the list of plugin base folders
+    String[] folders = folderPaths.split( "," );
+    for ( String folder : folders ) {
+     // trim the folder - we don't need leading and trailing spaces
+      pluginFolders.add( folder.trim() );
+    }
+    return pluginFolders;
+  }
+
+  
+  public Set<File> getNativeJars() throws HopFileException {
+
+      // Scan native jars only once
+      //
+      if (nativeFiles.isEmpty()) {
+        try {
+          Enumeration<URL> indexFiles  = getClass().getClassLoader().getResources(JarCache.ANNOTATION_INDEX_LOCATION);
+          while (indexFiles.hasMoreElements()) {
+            URL url = indexFiles.nextElement();          
+            
+            // Relative path
+            String path = url.getFile();            
+
+            File file = new File(StringUtils.substringBefore(path,  "!/"));            
+            
+            nativeFiles.add(file);
+            
+            // Read annotation index from resource
+            //
+            try (InputStream stream = url.openStream()) {
+                IndexReader reader = new IndexReader(stream);
+                Index index = reader.read();                
+                indexCache.put(file, index);
+              } catch (IOException e) {
+                throw new HopFileException(
+                    MessageFormat.format("Error reading annotation index from url ''{0}''", url), e);
+              }
+            
+          }
+        } catch (Exception e) {
+          throw new HopFileException("Error finding native plugin jar", e);
+        }
+      }
+
+      return nativeFiles;
+    }
+
+  /**
+   * Get all the jar files with annotation index
+   * 
+   * @return list of jar files
+   * @throws HopFileException
+   */  
+  public Set<File> getPluginJars() throws HopFileException {
+    // Scan plugin jars only once
+    //
+    if (pluginFiles.isEmpty()) {
+            
+      for (String pluginFolder : getPluginFolders()) {
+        
+        // System.out.println("Search plugin in folder: " + pluginFolder );
+        
+        for (File file : this.findJarFiles(new File(pluginFolder))) {
+          Index index = this.getIndex(file);
+          if (index != null) {
+            pluginFiles.add(file);
+          }
+        }
+      }
+    }
+    return pluginFiles;
+  }
+
+  public Index getIndex(File jarFile) throws HopFileException {
+    
+    // Search annotation index from cache
+    //
+    Index index = indexCache.get(jarFile);
+    
+    if (index == null) {
+
+      try (JarFile jar = new JarFile(jarFile)) {
+        ZipEntry entry = jar.getEntry(ANNOTATION_INDEX_LOCATION);
+        if (entry != null) {
+          // System.out.println("- Plugin jar indexed " + jarFile);
+          try (InputStream stream = jar.getInputStream(entry)) {
+            IndexReader reader = new IndexReader(stream);
+            index = reader.read();
+            indexCache.put(jarFile, index);
+          }
+        }
+      } catch (IOException e) {
+        throw new HopFileException(
+            MessageFormat.format("Error reading annotation index from file ''{0}''", jarFile), e);
+      }
+
+      // Cache annotation index of jars
+      //
+      indexCache.put(jarFile, index);
+    }
+
+    return index;
+  }
+
+  public void clear() {
+    nativeFiles.clear();
+    pluginFiles.clear();
+    indexCache.clear();
+    jarFiles.clear();
+  }
+
+  public Set<File> findJarFiles(final File folder) throws HopFileException {
+
+    Set<File> files = jarFiles.get(folder);
+
+    if (files == null) {
+
+      try {
+        // Find all the jar files in this folder...
+        //
+        files = findFiles(folder);
+
+        // Cache list of jars in the folder
+        //
+        jarFiles.put(folder, files);
+
+      } catch (Exception e) {
+        throw new HopFileException("Unable to list jar files in plugin folder '" + folder + "'", e);
+      }
+    }
+
+    return files;
+  }
+
+  /**
+   * Find all the jar files in the folder and sub-folders exception for lib folder.
+   * 
+   * @param folder
+   * 
+   * @return the list of jar files
+   */
+  private  static Set<File> findFiles(final File folder ) {
+    Set<File> files = new HashSet<>();
+    File[] children = folder.listFiles();
+    if (children!=null) {
+      for ( File child : children ) {
+        if ( child.isFile() ) {
+          if ( child.getName().endsWith( ".jar" ) ) {
+            files.add( child );
+          }
+        }
+        else if ( child.isDirectory() ) {
+          if ( !"lib".equals( child.getName() ) ) {
+            files.addAll( findFiles( child ) );
+          }
+        }
+      }
+    }
+
+    return files;
+  }
+
+}
diff --git a/core/src/main/java/org/apache/hop/core/plugins/JarFileCache.java b/core/src/main/java/org/apache/hop/core/plugins/JarFileCache.java
deleted file mode 100644
index 77751a2..0000000
--- a/core/src/main/java/org/apache/hop/core/plugins/JarFileCache.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.hop.core.plugins;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.jar.JarFile;
-import java.util.zip.ZipEntry;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.hop.core.exception.HopFileException;
-import org.jboss.jandex.Index;
-import org.jboss.jandex.IndexReader;
-
-public class JarFileCache {
-
-  public static final String ANNOTATION_INDEX_LOCATION = "META-INF/jandex.idx";
-
-  private static JarFileCache instance;
-
-  private final Map<File, Index> indexCache;
-  private final Map<IPluginFolder, List<File>> folderFiles;
-  private final List<File> nativeFiles;
-
-  private JarFileCache() {
-    nativeFiles = new ArrayList<>();
-    folderFiles = new HashMap<>();
-    indexCache = new HashMap<>();
-  }
-
-  public static JarFileCache getInstance() {
-    if (instance == null) {
-      instance = new JarFileCache();
-    }
-    return instance;
-  }
-  
-  public List<File> getNativeJars() throws HopFileException {
-
-      // Scan native jars only once
-      //
-      if (nativeFiles.isEmpty()) {
-        try {
-          Enumeration<URL> indexFiles  = getClass().getClassLoader().getResources(JarFileCache.ANNOTATION_INDEX_LOCATION);
-          while (indexFiles .hasMoreElements()) {
-            URL url = indexFiles .nextElement();          
-            
-            // Relative path
-            String path = url.getFile();            
-
-            File file = new File(StringUtils.substringBefore(path,  "!/"));            
-            
-            //System.out.println("- Native jar indexed " + file);
-            nativeFiles.add(file);
-            
-            // Read index from resource
-            try (InputStream stream = url.openStream()) {
-                IndexReader reader = new IndexReader(stream);
-                Index index = reader.read();                
-                indexCache.put(file, index);
-              } catch (IOException e) {
-                throw new HopFileException(
-                    MessageFormat.format("Error reading annotation index from url ''{0}''", url), e);
-              }
-            
-          }
-        } catch (Exception e) {
-          throw new HopFileException("Error finding native plugin jar", e);
-        }
-      }
-
-      return nativeFiles;
-    }
-
-
-  public List<File> getJars(IPluginFolder pluginFolder) throws HopFileException {
-    List<File> jarFiles = folderFiles.get(pluginFolder);
-
-    if (jarFiles == null) {
-      jarFiles = Arrays.asList(pluginFolder.findJarFiles());
-      folderFiles.put(pluginFolder, jarFiles);
-    }
-    return jarFiles;
-  }
-
-  public Index getIndex(File jarFile) throws HopFileException {
-    Index index = indexCache.get(jarFile);
-    
-    if (index == null) {
-
-
-      try (JarFile jar = new JarFile(jarFile)) {
-        ZipEntry entry = jar.getEntry(ANNOTATION_INDEX_LOCATION);
-        if (entry != null) {
-          //System.out.println("- Plugin jar indexed " + jarFile);
-          try (InputStream stream = jar.getInputStream(entry)) {
-            IndexReader reader = new IndexReader(stream);
-            index = reader.read();
-            indexCache.put(jarFile, index);
-          }
-        }
-      } catch (IOException e) {
-        throw new HopFileException(
-            MessageFormat.format("Error reading annotation index from file ''{0}''", jarFile), e);
-      }
-
-      indexCache.put(jarFile, index);
-    }
-
-    return index;
-  }
-
-  public void clear() {
-    nativeFiles.clear();
-    indexCache.clear();
-    folderFiles.clear();
-  }
-}
diff --git a/core/src/main/java/org/apache/hop/core/plugins/JarFilePlugin.java b/core/src/main/java/org/apache/hop/core/plugins/PluginClassFile.java
similarity index 75%
rename from core/src/main/java/org/apache/hop/core/plugins/JarFilePlugin.java
rename to core/src/main/java/org/apache/hop/core/plugins/PluginClassFile.java
index d319a56..93271f9 100644
--- a/core/src/main/java/org/apache/hop/core/plugins/JarFilePlugin.java
+++ b/core/src/main/java/org/apache/hop/core/plugins/PluginClassFile.java
@@ -19,7 +19,7 @@ package org.apache.hop.core.plugins;
 
 import java.net.URL;
 
-public class JarFilePlugin {
+public class PluginClassFile {
   private URL jarFile;
   private URL pluginFolder;
   private String className;
@@ -27,12 +27,12 @@ public class JarFilePlugin {
   /**
    * @param className
    * @param jarFile
-   * @param pluginFolder
+   * @param folder
    */
-  public JarFilePlugin( String className, URL jarFile, URL pluginFolder ) {
+  public PluginClassFile( String className, URL jarFile, URL folder ) {
     this.className = className;
     this.jarFile = jarFile;
-    this.pluginFolder = pluginFolder;
+    this.pluginFolder = folder;
   }
 
   @Override
@@ -47,21 +47,10 @@ public class JarFilePlugin {
     return jarFile;
   }
 
-  /**
-   * @param jarFile the jarFile to set
-   */
-  public void setJarFile( URL jarFile ) {
-    this.jarFile = jarFile;
-  }
-
-  public URL getPluginFolder() {
+  public URL getFolder() {
     return pluginFolder;
   }
 
-  public void setPluginFolder( URL pluginFolder ) {
-    this.pluginFolder = pluginFolder;
-  }
-
   public String getClassName() {
     return className;
   }
diff --git a/core/src/main/java/org/apache/hop/core/plugins/PluginFolder.java b/core/src/main/java/org/apache/hop/core/plugins/PluginFolder.java
deleted file mode 100644
index 3f5ae82..0000000
--- a/core/src/main/java/org/apache/hop/core/plugins/PluginFolder.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.hop.core.plugins;
-
-import org.apache.commons.lang.builder.EqualsBuilder;
-import org.apache.commons.lang.builder.HashCodeBuilder;
-import org.apache.hop.core.Const;
-import org.apache.hop.core.exception.HopFileException;
-import org.apache.hop.core.util.EnvUtil;
-import org.apache.hop.core.util.Utils;
-import org.apache.hop.core.variables.Variables;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * A folder to search plugins in.
- *
- * @author matt
- */
-public class PluginFolder implements IPluginFolder {
-
-  public static final String VAR_HOP_PLUGIN_BASE_FOLDERS = "HOP_PLUGIN_BASE_FOLDERS";
-  private String folder;
-  private boolean pluginXmlFolder;
-  private boolean pluginAnnotationsFolder;
-  private boolean searchLibDir;
-
-  /**
-   * @param folder                  The folder location
-   * @param pluginXmlFolder         set to true if the folder needs to be searched for plugin.xml appearances
-   * @param pluginAnnotationsFolder set to true if the folder needs to be searched for jar files with plugin annotations
-   */
-  public PluginFolder( String folder, boolean pluginXmlFolder, boolean pluginAnnotationsFolder ) {
-    this( folder, pluginXmlFolder, pluginAnnotationsFolder, false );
-  }
-
-  /**
-   * @param folder                  The folder location
-   * @param pluginXmlFolder         set to true if the folder needs to be searched for plugin.xml appearances
-   * @param pluginAnnotationsFolder set to true if the folder needs to be searched for jar files with plugin annotations
-   * @param searchLibDir            look inside the plugins lib dir for additional plugins
-   */
-  public PluginFolder( String folder, boolean pluginXmlFolder, boolean pluginAnnotationsFolder,
-                       boolean searchLibDir ) {
-    this.folder = folder;
-    this.pluginXmlFolder = pluginXmlFolder;
-    this.pluginAnnotationsFolder = pluginAnnotationsFolder;
-    this.searchLibDir = searchLibDir;
-  }
-
-  /**
-   * Create a list of plugin folders based on the default or variable HOP_PLUGIN_BASE_FOLDERS
-   *
-   * @return The list of plugin folders found
-   */
-  public static List<IPluginFolder> populateFolders() {
-    List<IPluginFolder> pluginFolders = new ArrayList<>();
-
-    String folderPaths = Const.NVL( Variables.getADefaultVariableSpace().getVariable( VAR_HOP_PLUGIN_BASE_FOLDERS ), EnvUtil.getSystemProperty( VAR_HOP_PLUGIN_BASE_FOLDERS ) );
-    if ( folderPaths == null ) {
-      folderPaths = Const.DEFAULT_PLUGIN_BASE_FOLDERS;
-    }
-    String[] folders = folderPaths.split( "," );
-    // for each folder in the list of plugin base folders
-    // add an annotation and xml path for searching
-    // trim the folder - we don't need leading and trailing spaces
-    for ( String folder : folders ) {
-      folder = folder.trim();
-      pluginFolders.add( new PluginFolder( folder, false, true ) );
-    }
-    return pluginFolders;
-  }
-
-  @Override
-  public String toString() {
-    return folder;
-  }
-
-  @Override
-  public File[] findJarFiles() throws HopFileException {
-    return findJarFiles( searchLibDir );
-  }
-
-  public File[] findJarFiles( final boolean includeLibJars ) throws HopFileException {
-
-    try {
-      // Find all the jar files in this folder...
-      //
-      File folderFile = new File( this.getFolder() );
-
-      Set<File> pluginJarFiles = findFiles(folderFile);
-
-      return pluginJarFiles.toArray(new File[0]);
-    } catch ( Exception e ) {
-      throw new HopFileException( "Unable to list jar files in plugin folder '" + toString() + "'", e );
-    }
-  }
-
-  private Set<File> findFiles( File folder ) {
-    Set<File> files = new HashSet<>();
-    File[] children = folder.listFiles();
-    if (children!=null) {
-      for ( File child : children ) {
-        if ( child.isFile() ) {
-          if ( child.getName().endsWith( ".jar" ) ) {
-            files.add( child );
-          }
-        }
-        if ( child.isDirectory() ) {
-          if ( !"lib".equals( child.getName() ) ) {
-            files.addAll( findFiles( child ) );
-          }
-        }
-      }
-    }
-
-    return files;
-  }
-
-  /**
-   * @return the folder
-   */
-  @Override
-  public String getFolder() {
-    return folder;
-  }
-
-  /**
-   * @param folder the folder to set
-   */
-  public void setFolder( String folder ) {
-    this.folder = folder;
-  }
-
-  /**
-   * @return the pluginXmlFolder
-   */
-  @Override
-  public boolean isPluginXmlFolder() {
-    return pluginXmlFolder;
-  }
-
-  /**
-   * @param pluginXmlFolder the pluginXmlFolder to set
-   */
-  public void setPluginXmlFolder( boolean pluginXmlFolder ) {
-    this.pluginXmlFolder = pluginXmlFolder;
-  }
-
-  /**
-   * @return the pluginAnnotationsFolder
-   */
-  @Override
-  public boolean isPluginAnnotationsFolder() {
-    return pluginAnnotationsFolder;
-  }
-
-  /**
-   * @param pluginAnnotationsFolder the pluginAnnotationsFolder to set
-   */
-  public void setPluginAnnotationsFolder( boolean pluginAnnotationsFolder ) {
-    this.pluginAnnotationsFolder = pluginAnnotationsFolder;
-  }
-
-  @Override public int hashCode() {
-    return new HashCodeBuilder()
-      .append( folder )
-      .append( pluginAnnotationsFolder )
-      .append( pluginXmlFolder )
-      .append( searchLibDir )
-      .hashCode();
-  }
-
-  @Override public boolean equals( Object obj ) {
-    if ( obj == null ) {
-      return false;
-    }
-    if ( obj == this ) {
-      return true;
-    }
-    if ( obj.getClass() != getClass() ) {
-      return false;
-    }
-
-    PluginFolder other = (PluginFolder) obj;
-    return new EqualsBuilder()
-      .append( folder, other.getFolder() )
-      .append( pluginAnnotationsFolder, other.isPluginAnnotationsFolder() )
-      .append( pluginXmlFolder, other.isPluginXmlFolder() )
-      .append( searchLibDir, other.searchLibDir )
-      .isEquals();
-  }
-}
diff --git a/core/src/main/java/org/apache/hop/core/plugins/PluginRegistry.java b/core/src/main/java/org/apache/hop/core/plugins/PluginRegistry.java
index 6b34ccf..9a61017 100644
--- a/core/src/main/java/org/apache/hop/core/plugins/PluginRegistry.java
+++ b/core/src/main/java/org/apache/hop/core/plugins/PluginRegistry.java
@@ -24,7 +24,6 @@ import org.apache.hop.core.exception.HopPluginException;
 import org.apache.hop.core.logging.HopLogStore;
 import org.apache.hop.core.logging.ILogChannel;
 import org.apache.hop.core.logging.LogChannel;
-import org.apache.hop.core.logging.Metrics;
 import org.apache.hop.core.row.IRowMeta;
 import org.apache.hop.core.row.RowBuffer;
 import org.apache.hop.core.row.RowMeta;
@@ -499,7 +498,7 @@ public class PluginRegistry {
     // Clear the jar file cache so that we don't waste memory...
     //
     if ( !keepCache ) {
-      JarFileCache.getInstance().clear();
+      JarCache.getInstance().clear();
     }
   }
 
@@ -981,7 +980,7 @@ public class PluginRegistry {
       inverseClassLoaderLookup.clear();
       parentClassloaderPatternMap.clear();
       listeners.clear();
-      JarFileCache.getInstance().clear();
+      JarCache.getInstance().clear();
     } finally {
       lock.writeLock().unlock();
     }
diff --git a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaPluginType.java b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaPluginType.java
index 1f8b248..be12f6d 100644
--- a/core/src/main/java/org/apache/hop/core/row/value/ValueMetaPluginType.java
+++ b/core/src/main/java/org/apache/hop/core/row/value/ValueMetaPluginType.java
@@ -33,13 +33,12 @@ import java.util.Map;
 
 @PluginMainClassType( IValueMeta.class )
 @PluginAnnotationType( ValueMetaPlugin.class )
-public class ValueMetaPluginType extends BasePluginType<ValueMetaPlugin> implements IPluginType<ValueMetaPlugin> {
+public class ValueMetaPluginType extends BasePluginType<ValueMetaPlugin> {
 
   private static ValueMetaPluginType valueMetaPluginType;
 
   private ValueMetaPluginType() {
     super( ValueMetaPlugin.class, "VALUEMETA", "ValueMeta" );
-    populateFolders();
   }
 
   public static ValueMetaPluginType getInstance() {
diff --git a/core/src/main/java/org/apache/hop/core/search/SearchableAnalyserPluginType.java b/core/src/main/java/org/apache/hop/core/search/SearchableAnalyserPluginType.java
index 09e8876..39cae7a 100644
--- a/core/src/main/java/org/apache/hop/core/search/SearchableAnalyserPluginType.java
+++ b/core/src/main/java/org/apache/hop/core/search/SearchableAnalyserPluginType.java
@@ -18,17 +18,15 @@
 package org.apache.hop.core.search;
 
 import org.apache.hop.core.plugins.BasePluginType;
-import org.apache.hop.core.plugins.IPluginType;
 
 import java.util.Map;
 
-public class SearchableAnalyserPluginType extends BasePluginType<SearchableAnalyserPlugin> implements IPluginType<SearchableAnalyserPlugin> {
+public class SearchableAnalyserPluginType extends BasePluginType<SearchableAnalyserPlugin> {
 
   private static SearchableAnalyserPluginType pluginType;
 
   private SearchableAnalyserPluginType() {
     super( SearchableAnalyserPlugin.class, "SEARCH_ANALYSER", "SearchAnalyser" );
-    populateFolders();
   }
 
   public static SearchableAnalyserPluginType getInstance() {
diff --git a/core/src/main/java/org/apache/hop/core/vfs/plugin/VfsPluginType.java b/core/src/main/java/org/apache/hop/core/vfs/plugin/VfsPluginType.java
index 98b91ee..668e668 100644
--- a/core/src/main/java/org/apache/hop/core/vfs/plugin/VfsPluginType.java
+++ b/core/src/main/java/org/apache/hop/core/vfs/plugin/VfsPluginType.java
@@ -18,7 +18,6 @@
 package org.apache.hop.core.vfs.plugin;
 
 import org.apache.hop.core.plugins.BasePluginType;
-import org.apache.hop.core.plugins.IPluginType;
 import org.apache.hop.core.plugins.PluginAnnotationType;
 import org.apache.hop.core.plugins.PluginMainClassType;
 
@@ -31,12 +30,11 @@ import java.util.Map;
  */
 @PluginMainClassType( IVfs.class )
 @PluginAnnotationType( VfsPlugin.class )
-public class VfsPluginType extends BasePluginType<VfsPlugin> implements IPluginType<VfsPlugin> {
+public class VfsPluginType extends BasePluginType<VfsPlugin> {
   private static VfsPluginType pluginType;
 
   private VfsPluginType() {
     super( VfsPlugin.class, "VFS", "VFS" );
-    populateFolders();
   }
 
   public static VfsPluginType getInstance() {
diff --git a/core/src/main/java/org/apache/hop/metadata/plugin/MetadataPluginType.java b/core/src/main/java/org/apache/hop/metadata/plugin/MetadataPluginType.java
index 2937665..dbbfd7a 100644
--- a/core/src/main/java/org/apache/hop/metadata/plugin/MetadataPluginType.java
+++ b/core/src/main/java/org/apache/hop/metadata/plugin/MetadataPluginType.java
@@ -19,7 +19,6 @@ package org.apache.hop.metadata.plugin;
 
 import org.apache.hop.core.Const;
 import org.apache.hop.core.plugins.BasePluginType;
-import org.apache.hop.core.plugins.IPluginType;
 import org.apache.hop.core.plugins.PluginAnnotationType;
 import org.apache.hop.core.plugins.PluginMainClassType;
 import org.apache.hop.metadata.api.HopMetadata;
@@ -32,12 +31,11 @@ import java.util.Map;
  */
 @PluginMainClassType( IHopMetadata.class )
 @PluginAnnotationType( HopMetadata.class )
-public class MetadataPluginType extends BasePluginType<HopMetadata> implements IPluginType<HopMetadata> {
+public class MetadataPluginType extends BasePluginType<HopMetadata> {
   private static MetadataPluginType pluginType;
 
   private MetadataPluginType() {
     super( HopMetadata.class, "METADATA", "Metadata" );
-    populateFolders();
   }
 
   public static MetadataPluginType getInstance() {
diff --git a/core/src/test/java/org/apache/hop/core/plugins/PluginFolderTest.java b/core/src/test/java/org/apache/hop/core/plugins/PluginFolderTest.java
deleted file mode 100644
index 716f99e..0000000
--- a/core/src/test/java/org/apache/hop/core/plugins/PluginFolderTest.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.hop.core.plugins;
-
-import org.apache.hop.core.exception.HopFileException;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.FileVisitResult;
-import java.nio.file.FileVisitor;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.BasicFileAttributes;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-/**
- * @author Tatsiana_Kasiankova
- */
-public class PluginFolderTest {
-
-  private static final String BASE_TEMP_DIR = System.getProperty( "java.io.tmpdir" );
-  private static final String PLUGINS_DIR_NAME = "plugins";
-  private static final String WITH_JAR_IN_NAME_DIR_NAME = "workflow.jar";
-  private static final String TEST_DIR_NAME = "test_dir";
-  /**
-   *
-   */
-  private static final String JAR_FILE1_NAME = "workflow.jar";
-  private static final String JAR_FILE2_NAME = "test.jar";
-  /**
-   *
-   */
-  private static final Path PATH_TO_JAR_IN_LIB_DIR = Paths.get( BASE_TEMP_DIR, PLUGINS_DIR_NAME, "lib", JAR_FILE2_NAME );
-  private static final String NOT_JAR_FILE_NAME = "test.txt";
-  private static final Path PATH_TO_PLUGIN_DIR = Paths.get( BASE_TEMP_DIR, PLUGINS_DIR_NAME );
-  /**
-   * Paths below represent the following structure of the folder and files in them:
-   * <p>
-   * <TMP_DIR>/plugins/workflow.jar - folder
-   * <p>
-   * <TMP_DIR>/plugins/workflow.jar/workflow.jar - file
-   * <p>
-   * <TMP_DIR>/plugins/workflow.jar/test.txt - file
-   */
-  private static final Path PATH_TO_DIR_WITH_JAR_IN_NAME = Paths.get( BASE_TEMP_DIR, PLUGINS_DIR_NAME, WITH_JAR_IN_NAME_DIR_NAME );
-  private static final Path PATH_TO_JAR_FILE1 = Paths.get( BASE_TEMP_DIR, PLUGINS_DIR_NAME, WITH_JAR_IN_NAME_DIR_NAME, JAR_FILE1_NAME );
-  private static final Path PATH_TO_NOT_JAR_FILE = Paths.get( BASE_TEMP_DIR, PLUGINS_DIR_NAME, WITH_JAR_IN_NAME_DIR_NAME, NOT_JAR_FILE_NAME );
-
-  /**
-   * Paths below represent the following structure of the folder and files in them:
-   * <p>
-   * <TMP_DIR>/plugins/test_dir - folder
-   * <p>
-   * <TMP_DIR>/plugins/test_dir/workflow.jar - file
-   * <p>
-   * <TMP_DIR>/plugins/test_dir/test.txt - file
-   */
-  private static final Path PATH_TO_TEST_DIR_NAME = Paths.get( BASE_TEMP_DIR, PLUGINS_DIR_NAME, TEST_DIR_NAME );
-  private static final Path PATH_TO_JAR_FILE2 = Paths.get( BASE_TEMP_DIR, PLUGINS_DIR_NAME, TEST_DIR_NAME, JAR_FILE2_NAME );
-  private static final Path PATH_TO_NOT_JAR_FILE_IN_TEST_DIR = Paths.get( BASE_TEMP_DIR, PLUGINS_DIR_NAME, TEST_DIR_NAME, NOT_JAR_FILE_NAME );
-
-  private PluginFolder plFolder;
-
-  @Before
-  public void setUp() throws IOException {
-    cleanTempDir( PATH_TO_PLUGIN_DIR );
-    plFolder = new PluginFolder( PATH_TO_PLUGIN_DIR.toAbsolutePath().toString(), false, true );
-  }
-
-  @After
-  public void clean() throws IOException {
-    cleanTempDir( PATH_TO_PLUGIN_DIR );
-    plFolder = null;
-  }
-
-  @Test
-  public void testIsPluginXmlFolder_SetPluginXmlFolder() throws IOException, HopFileException {
-    plFolder = new PluginFolder( PLUGINS_DIR_NAME, false, true );
-    assertNotNull( plFolder );
-    assertFalse( plFolder.isPluginXmlFolder() );
-    plFolder.setPluginXmlFolder( true );
-    assertTrue( plFolder.isPluginXmlFolder() );
-    plFolder.setPluginXmlFolder( false );
-    assertFalse( plFolder.isPluginXmlFolder() );
-  }
-
-  @Test
-  public void testIsPluginAnnotationsFolder_SetPluginAnnotationsFolder() throws IOException, HopFileException {
-    plFolder = new PluginFolder( PLUGINS_DIR_NAME, false, true );
-    assertNotNull( plFolder );
-    assertTrue( plFolder.isPluginAnnotationsFolder() );
-    plFolder.setPluginAnnotationsFolder( false );
-    assertFalse( plFolder.isPluginAnnotationsFolder() );
-    plFolder.setPluginAnnotationsFolder( true );
-    assertTrue( plFolder.isPluginAnnotationsFolder() );
-  }
-
-  @Test
-  public void testGetFolder_SetFolder() throws IOException, HopFileException {
-    plFolder = new PluginFolder( null, false, true );
-    assertNotNull( plFolder );
-    assertNull( plFolder.getFolder() );
-    plFolder.setFolder( PLUGINS_DIR_NAME );
-    assertEquals( PLUGINS_DIR_NAME, plFolder.getFolder() );
-  }
-
-  @Test
-  public void testFindJarFiles_DirWithJarInNameNotAdded() throws IOException, HopFileException {
-    Files.createDirectories( PATH_TO_DIR_WITH_JAR_IN_NAME );
-
-    File[] findJarFiles = plFolder.findJarFiles();
-    assertNotNull( findJarFiles );
-    assertEquals( 0, findJarFiles.length );
-  }
-
-  @Test
-  public void testFindJarFiles_DirWithJarInNameNotAddedButJarFileAdded() throws IOException, HopFileException {
-    Files.createDirectories( PATH_TO_DIR_WITH_JAR_IN_NAME );
-    Files.createFile( PATH_TO_JAR_FILE1 );
-
-    File[] findJarFiles = plFolder.findJarFiles();
-    assertNotNull( findJarFiles );
-    assertEquals( 1, findJarFiles.length );
-    assertTrue( findJarFiles[ 0 ].isFile() );
-    assertEquals( PATH_TO_JAR_FILE1.toUri().toString(), findJarFiles[ 0 ].toPath().toUri().toString() );
-  }
-
-  @Test
-  public void testFindJarFiles_DirWithJarInNameNotAddedAndTxtFileNotAdded() throws IOException, HopFileException {
-    Files.createDirectories( PATH_TO_DIR_WITH_JAR_IN_NAME );
-    Files.createFile( PATH_TO_NOT_JAR_FILE );
-
-    File[] findJarFiles = plFolder.findJarFiles();
-    assertNotNull( findJarFiles );
-    assertEquals( 0, findJarFiles.length );
-  }
-
-  @Test
-  public void testFindJarFiles_SeveralJarsInDifferentDirs() throws IOException, HopFileException {
-    // Files in plugins/workflow.jar folder
-    Files.createDirectories( PATH_TO_DIR_WITH_JAR_IN_NAME );
-    Files.createFile( PATH_TO_JAR_FILE1 );
-    Files.createFile( PATH_TO_NOT_JAR_FILE );
-    // Files in plugins/test_dir folder
-    Files.createDirectories( PATH_TO_TEST_DIR_NAME );
-    Files.createFile( PATH_TO_JAR_FILE2 );
-    Files.createFile( PATH_TO_NOT_JAR_FILE_IN_TEST_DIR );
-    // Files in plugins folder
-    Files.createFile( Paths.get( BASE_TEMP_DIR, PLUGINS_DIR_NAME, JAR_FILE2_NAME ) );
-    Files.createFile( Paths.get( BASE_TEMP_DIR, PLUGINS_DIR_NAME, NOT_JAR_FILE_NAME ) );
-
-    File[] findJarFiles = plFolder.findJarFiles();
-    assertNotNull( findJarFiles );
-    assertEquals( 3, findJarFiles.length );
-  }
-
-  @Test
-  public void testFindJarFiles_LibDirIgnored() throws IOException, HopFileException {
-    Files.createDirectories( Paths.get( BASE_TEMP_DIR, PLUGINS_DIR_NAME, "lib" ) );
-    Files.createFile( PATH_TO_JAR_IN_LIB_DIR );
-
-    File[] findJarFiles = plFolder.findJarFiles();
-    assertNotNull( findJarFiles );
-    assertEquals( 0, findJarFiles.length );
-  }
-
-
-  @Test
-  public void testFindJarFiles_ExceptionThrows() {
-    String nullFolder = null;
-    String expectedMessage = "Unable to list jar files in plugin folder '" + nullFolder + "'";
-
-    plFolder = new PluginFolder( nullFolder, false, true );
-    try {
-      plFolder.findJarFiles();
-      fail( "HopFileException was not occured but expected." );
-    } catch ( HopFileException e ) {
-      assertTrue( e instanceof HopFileException );
-      assertTrue( e.getLocalizedMessage().trim().startsWith( expectedMessage ) );
-    }
-  }
-
-  private void cleanTempDir( Path path ) throws IOException {
-    Files.walkFileTree( path, new FileVisitor<Path>() {
-      @Override
-      public FileVisitResult postVisitDirectory( Path dir, IOException exc ) throws IOException {
-        Files.delete( dir );
-        return FileVisitResult.CONTINUE;
-      }
-
-      @Override
-      public FileVisitResult preVisitDirectory( Path dir, BasicFileAttributes attrs ) {
-        return FileVisitResult.CONTINUE;
-      }
-
-      @Override
-      public FileVisitResult visitFile( Path file, BasicFileAttributes attrs ) throws IOException {
-        Files.delete( file );
-        return FileVisitResult.CONTINUE;
-      }
-
-      @Override
-      public FileVisitResult visitFileFailed( Path file, IOException exc ) throws IOException {
-        return FileVisitResult.CONTINUE;
-      }
-    } );
-  }
-
-}
diff --git a/engine/src/main/java/org/apache/hop/core/auth/AuthenticationConsumerPluginType.java b/engine/src/main/java/org/apache/hop/core/auth/AuthenticationConsumerPluginType.java
index a1f4aa0..7bbfe2e 100644
--- a/engine/src/main/java/org/apache/hop/core/auth/AuthenticationConsumerPluginType.java
+++ b/engine/src/main/java/org/apache/hop/core/auth/AuthenticationConsumerPluginType.java
@@ -18,7 +18,6 @@
 package org.apache.hop.core.auth;
 
 import org.apache.hop.core.plugins.BasePluginType;
-import org.apache.hop.core.plugins.IPluginType;
 import org.apache.hop.core.plugins.PluginAnnotationType;
 import org.apache.hop.core.plugins.PluginMainClassType;
 
@@ -29,12 +28,11 @@ import java.util.Map;
  */
 @PluginMainClassType( IAuthenticationConsumerType.class )
 @PluginAnnotationType( AuthenticationConsumerPlugin.class )
-public class AuthenticationConsumerPluginType extends BasePluginType<AuthenticationConsumerPlugin> implements IPluginType<AuthenticationConsumerPlugin> {
+public class AuthenticationConsumerPluginType extends BasePluginType<AuthenticationConsumerPlugin> {
   protected static AuthenticationConsumerPluginType pluginType = new AuthenticationConsumerPluginType();
 
   private AuthenticationConsumerPluginType() {
     super( AuthenticationConsumerPlugin.class, "AUTHENTICATION_CONSUMER", "Authentication Consumer" );
-    populateFolders();
   }
 
   public static AuthenticationConsumerPluginType getInstance() {
diff --git a/engine/src/main/java/org/apache/hop/core/auth/AuthenticationProviderPluginType.java b/engine/src/main/java/org/apache/hop/core/auth/AuthenticationProviderPluginType.java
index 9186025..9153895 100644
--- a/engine/src/main/java/org/apache/hop/core/auth/AuthenticationProviderPluginType.java
+++ b/engine/src/main/java/org/apache/hop/core/auth/AuthenticationProviderPluginType.java
@@ -18,7 +18,6 @@
 package org.apache.hop.core.auth;
 
 import org.apache.hop.core.plugins.BasePluginType;
-import org.apache.hop.core.plugins.IPluginType;
 import org.apache.hop.core.plugins.PluginAnnotationType;
 import org.apache.hop.core.plugins.PluginMainClassType;
 
@@ -29,12 +28,11 @@ import java.util.Map;
  */
 @PluginMainClassType( IAuthenticationProviderType.class )
 @PluginAnnotationType( AuthenticationProviderPlugin.class )
-public class AuthenticationProviderPluginType extends BasePluginType<AuthenticationProviderPlugin> implements IPluginType<AuthenticationProviderPlugin> {
+public class AuthenticationProviderPluginType extends BasePluginType<AuthenticationProviderPlugin> {
   protected static AuthenticationProviderPluginType pluginType = new AuthenticationProviderPluginType();
 
   private AuthenticationProviderPluginType() {
     super( AuthenticationProviderPlugin.class, "AUTHENTICATION_PROVIDER", "Authentication Provider" );
-    populateFolders();
   }
 
   public static AuthenticationProviderPluginType getInstance() {
diff --git a/engine/src/main/java/org/apache/hop/core/compress/CompressionPluginType.java b/engine/src/main/java/org/apache/hop/core/compress/CompressionPluginType.java
index 254a8e7..d1eb660 100644
--- a/engine/src/main/java/org/apache/hop/core/compress/CompressionPluginType.java
+++ b/engine/src/main/java/org/apache/hop/core/compress/CompressionPluginType.java
@@ -18,7 +18,6 @@
 package org.apache.hop.core.compress;
 
 import org.apache.hop.core.plugins.BasePluginType;
-import org.apache.hop.core.plugins.IPluginType;
 import org.apache.hop.core.plugins.PluginAnnotationType;
 import org.apache.hop.core.plugins.PluginMainClassType;
 
@@ -29,12 +28,11 @@ import java.util.Map;
  */
 @PluginMainClassType( ICompressionProvider.class )
 @PluginAnnotationType( CompressionPlugin.class )
-public class CompressionPluginType extends BasePluginType<CompressionPlugin> implements IPluginType<CompressionPlugin> {
+public class CompressionPluginType extends BasePluginType<CompressionPlugin> {
   protected static CompressionPluginType pluginType;
 
   private CompressionPluginType() {
     super( CompressionPlugin.class, "COMPRESSION", "Compression" );
-    populateFolders();
   }
 
   public static CompressionPluginType getInstance() {
diff --git a/engine/src/main/java/org/apache/hop/core/plugins/ActionPluginType.java b/engine/src/main/java/org/apache/hop/core/plugins/ActionPluginType.java
index 1445e2f..6b00d4a 100644
--- a/engine/src/main/java/org/apache/hop/core/plugins/ActionPluginType.java
+++ b/engine/src/main/java/org/apache/hop/core/plugins/ActionPluginType.java
@@ -32,7 +32,7 @@ import java.util.Map;
  */
 @PluginMainClassType( IAction.class )
 @PluginAnnotationType( Action.class )
-public class ActionPluginType extends BasePluginType<Action> implements IPluginType<Action> {
+public class ActionPluginType extends BasePluginType<Action> {
   private static final Class<?> PKG = WorkflowMeta.class; // For Translator
 
   public static final String ID = "ACTION";
@@ -42,7 +42,6 @@ public class ActionPluginType extends BasePluginType<Action> implements IPluginT
 
   private ActionPluginType() {
     super( Action.class, ID, "Action" );
-    populateFolders();
   }
 
   protected ActionPluginType( Class<Action> pluginType, String id, String name ) {
diff --git a/engine/src/main/java/org/apache/hop/core/plugins/HopServerPluginType.java b/engine/src/main/java/org/apache/hop/core/plugins/HopServerPluginType.java
index 8cafbf1..e485017 100644
--- a/engine/src/main/java/org/apache/hop/core/plugins/HopServerPluginType.java
+++ b/engine/src/main/java/org/apache/hop/core/plugins/HopServerPluginType.java
@@ -29,13 +29,12 @@ import java.util.Map;
  */
 @PluginMainClassType( IHopServerPlugin.class )
 @PluginAnnotationType( HopServerServlet.class )
-public class HopServerPluginType extends BasePluginType<HopServerServlet> implements IPluginType<HopServerServlet> {
+public class HopServerPluginType extends BasePluginType<HopServerServlet> {
 
   private static HopServerPluginType hopServerPluginType;
 
   private HopServerPluginType() {
     super( HopServerServlet.class, "HOP_SERVER_SERVLET", "HopServer Servlet" );
-    populateFolders();
   }
 
   public static HopServerPluginType getInstance() {
diff --git a/engine/src/main/java/org/apache/hop/core/plugins/PartitionerPluginType.java b/engine/src/main/java/org/apache/hop/core/plugins/PartitionerPluginType.java
index ab1fa85..b2d4b2c 100644
--- a/engine/src/main/java/org/apache/hop/core/plugins/PartitionerPluginType.java
+++ b/engine/src/main/java/org/apache/hop/core/plugins/PartitionerPluginType.java
@@ -18,7 +18,6 @@
 package org.apache.hop.core.plugins;
 
 import org.apache.hop.core.annotations.PartitionerPlugin;
-import org.apache.hop.core.exception.HopPluginException;
 import org.apache.hop.pipeline.IPartitioner;
 
 import java.util.Map;
@@ -30,13 +29,12 @@ import java.util.Map;
  */
 @PluginMainClassType( IPartitioner.class )
 @PluginAnnotationType( PartitionerPlugin.class )
-public class PartitionerPluginType extends BasePluginType<PartitionerPlugin> implements IPluginType<PartitionerPlugin> {
+public class PartitionerPluginType extends BasePluginType<PartitionerPlugin> {
 
   private static PartitionerPluginType pluginType;
 
   private PartitionerPluginType() {
     super( PartitionerPlugin.class, "PARTITIONER", "Partitioner" );
-    populateFolders();
   }
 
   public static PartitionerPluginType getInstance() {
diff --git a/engine/src/main/java/org/apache/hop/core/plugins/TransformPluginType.java b/engine/src/main/java/org/apache/hop/core/plugins/TransformPluginType.java
index a0fe7c0..1390070 100644
--- a/engine/src/main/java/org/apache/hop/core/plugins/TransformPluginType.java
+++ b/engine/src/main/java/org/apache/hop/core/plugins/TransformPluginType.java
@@ -30,13 +30,12 @@ import java.util.Map;
  */
 @PluginMainClassType( ITransformMeta.class )
 @PluginAnnotationType( Transform.class )
-public class TransformPluginType extends BasePluginType<Transform> implements IPluginType<Transform> {
+public class TransformPluginType extends BasePluginType<Transform> {
 
   private static TransformPluginType transformPluginType;
 
   protected TransformPluginType() {
     super( Transform.class, "TRANSFORM", "Transform" );
-    populateFolders();
   }
 
   public static TransformPluginType getInstance() {
diff --git a/engine/src/main/java/org/apache/hop/pipeline/engine/PipelineEnginePluginType.java b/engine/src/main/java/org/apache/hop/pipeline/engine/PipelineEnginePluginType.java
index a66e26e..0c34a0b 100644
--- a/engine/src/main/java/org/apache/hop/pipeline/engine/PipelineEnginePluginType.java
+++ b/engine/src/main/java/org/apache/hop/pipeline/engine/PipelineEnginePluginType.java
@@ -18,21 +18,17 @@
 package org.apache.hop.pipeline.engine;
 
 import org.apache.hop.core.plugins.BasePluginType;
-import org.apache.hop.core.plugins.IPluginType;
 import org.apache.hop.core.plugins.PluginAnnotationType;
-import org.apache.hop.core.plugins.PluginFolder;
 import org.apache.hop.core.plugins.PluginMainClassType;
 
 import java.util.Map;
 
 @PluginMainClassType( IPipelineEngine.class )
 @PluginAnnotationType( PipelineEnginePlugin.class )
-public class PipelineEnginePluginType extends BasePluginType<PipelineEnginePlugin> implements IPluginType<PipelineEnginePlugin> {
+public class PipelineEnginePluginType extends BasePluginType<PipelineEnginePlugin> {
 
   private PipelineEnginePluginType() {
     super( PipelineEnginePlugin.class, "HOP_PIPELINE_ENGINES", "Hop Pipeline Engines" );
-
-    pluginFolders.add( new PluginFolder( "plugins", false, true ) );
   }
 
   private static PipelineEnginePluginType pluginType;
diff --git a/engine/src/main/java/org/apache/hop/pipeline/transform/RowDistributionPluginType.java b/engine/src/main/java/org/apache/hop/pipeline/transform/RowDistributionPluginType.java
index 68ddaab..7352fe5 100644
--- a/engine/src/main/java/org/apache/hop/pipeline/transform/RowDistributionPluginType.java
+++ b/engine/src/main/java/org/apache/hop/pipeline/transform/RowDistributionPluginType.java
@@ -31,12 +31,11 @@ import java.util.Map;
  */
 @PluginMainClassType( IRowDistribution.class )
 @PluginAnnotationType( RowDistributionPlugin.class )
-public class RowDistributionPluginType extends BasePluginType<RowDistributionPlugin> implements IPluginType<RowDistributionPlugin> {
+public class RowDistributionPluginType extends BasePluginType<RowDistributionPlugin> {
   private static RowDistributionPluginType instance;
 
   private RowDistributionPluginType() {
     super( RowDistributionPlugin.class, "ROW_DISTRIBUTION", "Row Distribution" );
-    populateFolders();
   }
 
   public static RowDistributionPluginType getInstance() {
diff --git a/engine/src/main/java/org/apache/hop/workflow/engine/WorkflowEnginePluginType.java b/engine/src/main/java/org/apache/hop/workflow/engine/WorkflowEnginePluginType.java
index 385c03e..d62616a 100644
--- a/engine/src/main/java/org/apache/hop/workflow/engine/WorkflowEnginePluginType.java
+++ b/engine/src/main/java/org/apache/hop/workflow/engine/WorkflowEnginePluginType.java
@@ -20,19 +20,16 @@ package org.apache.hop.workflow.engine;
 import org.apache.hop.core.plugins.BasePluginType;
 import org.apache.hop.core.plugins.IPluginType;
 import org.apache.hop.core.plugins.PluginAnnotationType;
-import org.apache.hop.core.plugins.PluginFolder;
 import org.apache.hop.core.plugins.PluginMainClassType;
 
 import java.util.Map;
 
 @PluginMainClassType( IWorkflowEngine.class )
 @PluginAnnotationType( WorkflowEnginePlugin.class )
-public class WorkflowEnginePluginType extends BasePluginType<WorkflowEnginePlugin> implements IPluginType<WorkflowEnginePlugin> {
+public class WorkflowEnginePluginType extends BasePluginType<WorkflowEnginePlugin> {
 
   private WorkflowEnginePluginType() {
     super( WorkflowEnginePlugin.class, "HOP_WORKFLOW_ENGINES", "Hop Workflow Engines" );
-
-    pluginFolders.add( new PluginFolder( "plugins", false, true ) );
   }
 
   private static WorkflowEnginePluginType pluginType;
diff --git a/plugins/engines/beam/src/main/java/org/apache/hop/beam/pipeline/HopPipelineMetaToBeamPipelineConverter.java b/plugins/engines/beam/src/main/java/org/apache/hop/beam/pipeline/HopPipelineMetaToBeamPipelineConverter.java
index 9d9d884..880cd77 100644
--- a/plugins/engines/beam/src/main/java/org/apache/hop/beam/pipeline/HopPipelineMetaToBeamPipelineConverter.java
+++ b/plugins/engines/beam/src/main/java/org/apache/hop/beam/pipeline/HopPipelineMetaToBeamPipelineConverter.java
@@ -55,8 +55,7 @@ import org.apache.hop.core.extension.ExtensionPoint;
 import org.apache.hop.core.logging.ILogChannel;
 import org.apache.hop.core.logging.LogChannel;
 import org.apache.hop.core.metadata.SerializableMetadataProvider;
-import org.apache.hop.core.plugins.JarFileCache;
-import org.apache.hop.core.plugins.PluginFolder;
+import org.apache.hop.core.plugins.JarCache;
 import org.apache.hop.core.row.IRowMeta;
 import org.apache.hop.core.row.RowMeta;
 import org.apache.hop.core.variables.IVariables;
@@ -74,12 +73,12 @@ import org.jboss.jandex.IndexView;
 
 import java.io.File;
 import java.io.IOException;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 public class HopPipelineMetaToBeamPipelineConverter<T extends IBeamPipelineEngineRunConfiguration> {
 
@@ -127,6 +126,7 @@ public class HopPipelineMetaToBeamPipelineConverter<T extends IBeamPipelineEngin
     //
     if ( StringUtils.isNotEmpty( pluginsToStage ) ) {
       String[] pluginFolders = pluginsToStage.split( "," );
+      // Scan only jar files with @Transform and @ExtensionPointPlugin annotations
       for ( String pluginFolder : pluginFolders ) {
         List<String> transformClasses = findAnnotatedClasses( pluginFolder, Transform.class.getName() );
         transformPluginClasses.addAll( transformClasses );
@@ -156,24 +156,23 @@ public class HopPipelineMetaToBeamPipelineConverter<T extends IBeamPipelineEngin
   }
 
   public static List<String> findAnnotatedClasses( String folder, String annotationClassName ) throws HopException {
-    JarFileCache jarFileCache = JarFileCache.getInstance();
+    JarCache jarCache = JarCache.getInstance();
     List<String> classNames = new ArrayList<>();
 
     // Scan only jar files with @Transform and @ExtensionPointPlugin annotations
-    // No plugin.xml format supported for the moment
     //
-    PluginFolder pluginFolder = new PluginFolder( "plugins/" + folder, false, true, false );
+    File pluginFolder = new File( "plugins/" + folder );
 
     try {
       // Get all the jar files in the plugin folder...
       //
-      List<File> files = jarFileCache.getJars(pluginFolder);
+      Set<File> files = jarCache.findJarFiles(pluginFolder);
       if ( !files.isEmpty() )
         for ( File file : files ) {
 
           // These are the jar files : find annotations in it...
           //
-          IndexView index = jarFileCache.getIndex(file);
+          IndexView index = jarCache.getIndex(file);
 
           // find annotations annotated with this meta-annotation
           for (AnnotationInstance instance : index.getAnnotations(DotName.createSimple(annotationClassName))) {
@@ -183,7 +182,7 @@ public class HopPipelineMetaToBeamPipelineConverter<T extends IBeamPipelineEngin
             }
         }
       } else {
-        System.out.println( "No jar files found in plugin folder " + pluginFolder.getFolder() );
+        System.out.println( "No jar files found in plugin folder " + pluginFolder );
       }
     } catch ( Exception e ) {
       throw new HopException( "Unable to find annotated classes of class " + annotationClassName, e );
diff --git a/plugins/engines/beam/src/main/java/org/apache/hop/beam/pipeline/fatjar/FatJarBuilder.java b/plugins/engines/beam/src/main/java/org/apache/hop/beam/pipeline/fatjar/FatJarBuilder.java
index dd474cd..6bf93fe 100644
--- a/plugins/engines/beam/src/main/java/org/apache/hop/beam/pipeline/fatjar/FatJarBuilder.java
+++ b/plugins/engines/beam/src/main/java/org/apache/hop/beam/pipeline/fatjar/FatJarBuilder.java
@@ -39,7 +39,7 @@ import org.apache.commons.lang.StringUtils;
 import org.apache.hop.beam.pipeline.HopPipelineMetaToBeamPipelineConverter;
 import org.apache.hop.core.Const;
 import org.apache.hop.core.exception.HopException;
-import org.apache.hop.core.plugins.JarFileCache;
+import org.apache.hop.core.plugins.JarCache;
 import org.apache.hop.core.variables.IVariables;
 import org.jboss.jandex.IndexWriter;
 import org.jboss.jandex.Indexer;
@@ -75,7 +75,7 @@ public class FatJarBuilder {
     //
     String realTargetJarFile = variables.resolve(targetJarFile);
 
-    JarFileCache cache = JarFileCache.getInstance();
+    JarCache cache = JarCache.getInstance();
     Indexer indexer = new Indexer();
     
     try {
@@ -189,7 +189,7 @@ public class FatJarBuilder {
 
       // Add META-INF/jandex.idx file
       //
-      zipOutputStream.putNextEntry( new ZipEntry( JarFileCache.ANNOTATION_INDEX_LOCATION ) );
+      zipOutputStream.putNextEntry( new ZipEntry( JarCache.ANNOTATION_INDEX_LOCATION ) );
       IndexWriter indexWriter = new IndexWriter(zipOutputStream); 
       indexWriter.write(indexer.complete());      
       zipOutputStream.closeEntry();
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/dialog/AboutDialog.java b/ui/src/main/java/org/apache/hop/ui/hopgui/dialog/AboutDialog.java
index 39c4ec9..e2defa1 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/dialog/AboutDialog.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/dialog/AboutDialog.java
@@ -47,7 +47,7 @@ import org.eclipse.swt.widgets.Text;
 public class AboutDialog extends Dialog {
   private static final Class<?> PKG = AboutDialog.class; // For Translator
 
-  private static final String[] PROPERTIES =  new String[] { "os.name","os.version","os.arch", "java.version", "java.vm.vendor", "java.specification.version","java.class.path","file.encoding","HOP_PLATFORM_RUNTIME","HOP_CONFIG_FOLDER"}; 
+  private static final String[] PROPERTIES =  new String[] { "os.name","os.version","os.arch", "java.version", "java.vm.vendor", "java.specification.version","java.class.path","file.encoding", "HOP_CONFIG_FOLDER", Const.HOP_PLATFORM_RUNTIME, Const.HOP_PLUGIN_BASE_FOLDERS, Const.HOP_SHARED_JDBC_FOLDER}; 
 
   private Shell shell;
 
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/file/HopFileTypePluginType.java b/ui/src/main/java/org/apache/hop/ui/hopgui/file/HopFileTypePluginType.java
index 8eaeb14c..240de97 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/file/HopFileTypePluginType.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/file/HopFileTypePluginType.java
@@ -20,17 +20,14 @@ package org.apache.hop.ui.hopgui.file;
 import org.apache.hop.core.plugins.BasePluginType;
 import org.apache.hop.core.plugins.IPluginType;
 import org.apache.hop.core.plugins.PluginAnnotationType;
-import org.apache.hop.core.plugins.PluginFolder;
 import org.apache.hop.core.plugins.PluginMainClassType;
 
 @PluginMainClassType( IHopFileType.class )
 @PluginAnnotationType( HopFileTypePlugin.class )
-public class HopFileTypePluginType extends BasePluginType<HopFileTypePlugin> implements IPluginType<HopFileTypePlugin> {
+public class HopFileTypePluginType extends BasePluginType<HopFileTypePlugin> {
 
   private HopFileTypePluginType() {
     super( HopFileTypePlugin.class, "HOP_FILE_TYPES", "Hop File Type" );
-
-    pluginFolders.add( new PluginFolder( "plugins", false, true ) );
   }
 
   private static HopFileTypePluginType pluginType;
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/HopPerspectivePluginType.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/HopPerspectivePluginType.java
index d181594..bc5deb4 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/HopPerspectivePluginType.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/HopPerspectivePluginType.java
@@ -19,18 +19,14 @@ package org.apache.hop.ui.hopgui.perspective;
 
 import org.apache.hop.core.plugins.BasePluginType;
 import org.apache.hop.core.plugins.PluginAnnotationType;
-import org.apache.hop.core.plugins.PluginFolder;
 import org.apache.hop.core.plugins.PluginMainClassType;
-import org.apache.hop.core.plugins.IPluginType;
 
 @PluginMainClassType( IHopPerspective.class )
 @PluginAnnotationType( HopPerspectivePlugin.class )
-public class HopPerspectivePluginType extends BasePluginType<HopPerspectivePlugin> implements IPluginType<HopPerspectivePlugin> {
+public class HopPerspectivePluginType extends BasePluginType<HopPerspectivePlugin> {
 
   private HopPerspectivePluginType() {
     super( HopPerspectivePlugin.class, "HOP_PERSPECTIVES", "Hop Perspective" );
-
-    pluginFolders.add( new PluginFolder( "plugins", false, true ) );
   }
 
   private static HopPerspectivePluginType pluginType;
diff --git a/ui/src/main/java/org/apache/hop/ui/pipeline/dialog/PipelineDialogPluginType.java b/ui/src/main/java/org/apache/hop/ui/pipeline/dialog/PipelineDialogPluginType.java
index 221bca6..1ebea78 100644
--- a/ui/src/main/java/org/apache/hop/ui/pipeline/dialog/PipelineDialogPluginType.java
+++ b/ui/src/main/java/org/apache/hop/ui/pipeline/dialog/PipelineDialogPluginType.java
@@ -17,9 +17,7 @@
 
 package org.apache.hop.ui.pipeline.dialog;
 
-import org.apache.hop.core.exception.HopPluginException;
 import org.apache.hop.core.plugins.BasePluginType;
-import org.apache.hop.core.plugins.IPluginType;
 import org.apache.hop.core.plugins.PluginAnnotationType;
 import org.apache.hop.core.plugins.PluginMainClassType;
 
@@ -32,13 +30,12 @@ import java.util.Map;
  */
 @PluginMainClassType( IPipelineDialogPlugin.class )
 @PluginAnnotationType( PipelineDialogPlugin.class )
-public class PipelineDialogPluginType extends BasePluginType<PipelineDialogPlugin> implements IPluginType<PipelineDialogPlugin> {
+public class PipelineDialogPluginType extends BasePluginType<PipelineDialogPlugin> {
 
   private static PipelineDialogPluginType pluginType;
 
   private PipelineDialogPluginType() {
     super( PipelineDialogPlugin.class, "PIPELINE_DIALOG", "Pipeline dialog" );
-    populateFolders();
   }
 
   public static PipelineDialogPluginType getInstance() {
diff --git a/ui/src/main/java/org/apache/hop/ui/workflow/dialog/WorkflowDialogPluginType.java b/ui/src/main/java/org/apache/hop/ui/workflow/dialog/WorkflowDialogPluginType.java
index 68e9ee6..2f21423 100644
--- a/ui/src/main/java/org/apache/hop/ui/workflow/dialog/WorkflowDialogPluginType.java
+++ b/ui/src/main/java/org/apache/hop/ui/workflow/dialog/WorkflowDialogPluginType.java
@@ -18,7 +18,6 @@
 package org.apache.hop.ui.workflow.dialog;
 
 import org.apache.hop.core.plugins.BasePluginType;
-import org.apache.hop.core.plugins.IPluginType;
 import org.apache.hop.core.plugins.PluginAnnotationType;
 import org.apache.hop.core.plugins.PluginMainClassType;
 
@@ -31,14 +30,13 @@ import java.util.Map;
  */
 @PluginMainClassType( IWorkflowDialogPlugin.class )
 @PluginAnnotationType( WorkflowDialogPlugin.class )
-public class WorkflowDialogPluginType extends BasePluginType<WorkflowDialogPlugin> implements IPluginType<WorkflowDialogPlugin> {
+public class WorkflowDialogPluginType extends BasePluginType<WorkflowDialogPlugin> {
   private static final Class<?> PKG = WorkflowDialogPluginType.class; // For Translator
 
   private static WorkflowDialogPluginType pluginType;
 
   private WorkflowDialogPluginType() {
     super( WorkflowDialogPlugin.class, "WORKFLOW_DIALOG", "Workflow dialog" );
-    populateFolders();
   }
 
   public static WorkflowDialogPluginType getInstance() {