All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jorigin.plugin.PluginToolkit Maven / Gradle / Ivy

There is a newer version: 1.0.14
Show newest version
/*
  This file is part of JOrigin Common Library.

    JOrigin Common is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    JOrigin Common is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with JOrigin Common.  If not, see .
    
*/
package org.jorigin.plugin;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.logging.Level;

import javax.swing.event.EventListenerList;

import org.jorigin.Common;
import org.jorigin.lang.PathUtil;


/**
 * This class is a toolkit used for helping plugin management. Using this class, user can scan and load a list of plugins
 * related to a given package ({@link #setPluginPackage(String)}) from given locations on the system ({@link #addPluginDir(String)}, 
 * {@link #addPluginDir(File)}). The plugin loading is launched via the {@link #loadPlugins()} method.
 * @author Julien Seinturier - COMEX S.A. - [email protected] - https://github.com/jorigin/jeometry
 * @version {@value Common#version} - b{@value Common#BUILD}
 * @since 1.0.0
 *
 */
public class PluginToolkit {
  
  ArrayList plugins         = null;
  
  ArrayList pluginPackages   = null;
  
  ArrayList pluginDirs         = null;
    
  String corePackage                 = null;
  
  int taskCurrentTime                = 0;
  
  //Liste des écouteurs informés des evenements du panneau
  protected EventListenerList idListenerList = new EventListenerList();

  
  //CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
  //CC CONSTRUCTEUR                                             CC
  //CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
  /**
   * Constuct a new default plugin toolkit.
   */
  public PluginToolkit(){
    plugins        = null;
    
    pluginPackages = new ArrayList();
    
    pluginDirs     = new ArrayList();
    
  }
  //CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
  //CC FIN CONSTRUCTEUR                                         CC
  //CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
  
  //AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  //AA ACCESSEUR                                                AA
  //AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  /**
   * Add a new path in the plugin search path.
   * @param pluginDir the path to insert in the plugin search list.
   * @return boolean true if the plugin search dir is added, false otherwise.
   */
  public boolean addPluginDir(String pluginDir){
    if (pluginDir != null){
      File f = new File(PathUtil.URIToPath(pluginDir));
      if (!pluginDirs.contains(f)){
        return pluginDirs.add(f);
      }
    }
    return false;
  }
  
  /**
   * Add a new path in the plugin search path.
   * @param pluginDir the path to insert in the plugin search list.
   * @return boolean true if the plugin search dir is added, false otherwise.
   */
  public boolean addPluginDir(File pluginDir){
    if (pluginDir != null){
      if (!pluginDirs.contains(pluginDir)){
        return pluginDirs.add(pluginDir);
      }
    }
    
    return false;
  }  
  
  /**
   * Remove the given path from the plugin search path list.
   * @param pluginDir the plugin directory to remove.
   * @return true if the directory is succesfully removed, false otherwise.
   */
  public boolean removePluginDir(String pluginDir){
    if (pluginDir !=  null){
      File f = new File(PathUtil.URIToPath(pluginDir));
      return removePluginDir(f);
    }
    return false;
  }

  /**
   * Remove the given path from the plugin search path list.
   * @param pluginDir the plugin directory to remove.
   * @return true if the directory is succesfully removed, false otherwise.
   */
  public boolean removePluginDir(File pluginDir){
    return pluginDirs.remove(pluginDir);  
  }
  
  /**
   * Set the core package of the plugins.
   * @param pluginPackage the core package of the plugins
   */
  public void  setPluginPackage(String pluginPackage){
    corePackage = pluginPackage;
  }

  //AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  //AA FIN ACCESSEUR                                            AA
  //AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  
  //EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  //EE EVENEMENT                                                EE
  //EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE

  /**
   * Add a Plugin Toolkit Listener to this plugin toolkit
   * @param l the listener to add to the toolkit
   * @see #removePluginToolkitListener(PluginToolkitListener)
   */
  public void addPluginToolkitListener(PluginToolkitListener l) {
    idListenerList.add(PluginToolkitListener.class, l);
  }

  /**
   * Remove a Plugin Toolkit Listener from this plugin toolkit
   * @param l the listener to remove
   * @see #addPluginToolkitListener(PluginToolkitListener)
   */
  public void removePluginToolkitListener(PluginToolkitListener l) {
    idListenerList.remove(PluginToolkitListener.class, l);
  }
  
  /**
   * Fire a new plugin toolkit event to all registered listeners
   * @param e the event to fire.
   * @see #addPluginToolkitListener(PluginToolkitListener)
   * @see #removePluginToolkitListener(PluginToolkitListener)
   */
  protected void fireEvent(PluginToolkitEvent e) {
    Object[] listeners = idListenerList.getListenerList();
    for (int i = listeners.length - 2; i >= 0; i -= 2) {
        if (listeners[i] == PluginToolkitListener.class) {
            ((PluginToolkitListener) listeners[i + 1]).eventDispatched(e);
        }
    }
  }
  //EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  //EE FIN EVENEMENT                                            EE
  //EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
  
  /**
   * Load all plugins available in the locations given to the toolkit. This method scan the available locations
   * and looks for plugins with given package name. When available plugins are detected, the method instanciate them
   * and store the instanciated plugins in the returned list. 
   * @return ArrayList<{@link org.jorigin.plugin.IPlugin IPlugin}> the plugins availables and instanciated.
   * @see #addPluginDir(String)
   * @see #addPluginDir(File)
   * @see #removePluginDir(String)
   * @see #removePluginDir(File)
   */
  public  ArrayList loadPlugins(){

    IPlugin ap                         = null;

    plugins                            = new ArrayList();

    String pluginClass                 = null;
    
    Iterator fileIter            = null;
    File pluginDir                     = null;
    
    ArrayList pluginClassNames = null;
    String[] corePluginFiles           = null;
    
    String archive                     = null;
    String path                        = null;
      
    File jarFile                       = null;
    JarInputStream jis                 = null;
    
    JarEntry jarEntry                  = null;
    
    // Parcours des répertoires de plugin pour trouver les plugins.
    fireEvent(new PluginToolkitEvent(this, PluginToolkitEvent.PLUGIN_DISCOVERING_START, "Plugin discovering", pluginDirs.size()));
    
    fileIter = pluginDirs.iterator();
    while(fileIter.hasNext()){
    
      pluginDir = fileIter.next();

      // Verifie si les classes sont contenues dans un jar
      if (pluginDir.getPath().contains("!")){
        archive = pluginDir.getPath().split("!")[0];
        path    = pluginDir.getPath().split("!")[1];

        archive = PathUtil.URIToPath(archive);
        path    = path.replace("\\", "/");

        if (path.startsWith("/")){
          path = path.substring(1);
        }
      } 

      // Chargement depuis une archive
      if (archive != null){

        if (archive.endsWith(".jar")){
          Common.logger.log(Level.INFO, "[PluginToolKit][loadPlugins()] Plugin load from jar file: "+archive);
          Common.logger.log(Level.INFO, "[PluginToolKit][loadPlugins()]  - directory             : "+path);
          fireEvent(new PluginToolkitEvent(this, PluginToolkitEvent.PLUGIN_DISCOVERING_ARCHIVE, archive));
          try {
            
            switch (PathUtil.getProtocol(archive)) {
              case PathUtil.SYSTEM:
              case PathUtil.URL_FILE:
        	jarFile = new File(PathUtil.URIToPath(archive));
        	jis = new JarInputStream(new BufferedInputStream(new FileInputStream(jarFile)));
        	break;
        	
              case PathUtil.URL_HTTP:
        	jis = new JarInputStream(new BufferedInputStream(PathUtil.pathToURL(archive).openStream()));
        	break;
        	
              case PathUtil.URL_FTP:
              case PathUtil.URL_SFTP:
        	break;
            }
            
            if (jis != null){
              if (pluginClassNames == null){
                pluginClassNames = new ArrayList();
              }
              
              jarEntry = jis.getNextJarEntry();
              while (jarEntry != null){
                
                if ((jarEntry.getName().startsWith(path) && (jarEntry.getName().toUpperCase().endsWith("PLUGIN.CLASS")))){

                  pluginClass = jarEntry.getName().substring(0, jarEntry.getName().lastIndexOf("."));
                  pluginClass = pluginClass.replace("/", ".");

                  pluginClassNames.add(pluginClass);

                  Common.logger.log(Level.INFO, "[PluginToolKit][loadPlugins()]  - Found plugin: "+pluginClass);
                }
                
                jarEntry = jis.getNextJarEntry();
              }

              if (pluginClassNames.size() < 1){
                Common.logger.log(Level.INFO, "[PluginToolKit][loadPlugins()]  - No plugin available");
                fireEvent(new PluginToolkitEvent(this, PluginToolkitEvent.PLUGIN_NO_DISCOVERY, archive));
              }
            } else {
              Common.logger.log(Level.SEVERE, "[PluginToolKit][loadPlugins()] Unable to open stream from archive "+archive);
            }

          } catch (IOException ex) {
            Common.logger.log(Level.SEVERE, "[PluginToolKit][loadPlugins()] Cannot open jar "+archive, ex);
          }
        }

        // Chargement directement depuis un répertoire de classes  
      } else {
        Common.logger.log(Level.INFO, "[PluginToolKit][initPlugins()] Plugin load from dir : "+pluginDir.getPath());
        fireEvent(new PluginToolkitEvent(this, PluginToolkitEvent.PLUGIN_DISCOVERING_DIR, pluginDir.getPath()));
        
        // Recuperation des fichiers presents dans le repertoire plugin d'ametist
        try {
          corePluginFiles = pluginDir.list(new FilenameFilter(){
            public boolean accept(File dir, String name) {


              if (name.endsWith("Plugin.class")){
                if (name.equals("IPlugin.class")){
                  return false;
                }
                return true;
              } else {
                return false;
              }
            }});

          if (corePluginFiles != null){
            if (pluginClassNames == null){
              pluginClassNames = new ArrayList();
            }

            for(int i = 0; i < corePluginFiles.length; i++){
              pluginClass = corePluginFiles[i].replace(File.separatorChar, '.');
              pluginClass = pluginClass.substring(0, pluginClass.length() - 6);
              pluginClass = corePackage + "." + pluginClass;

           
              
              if (pluginClass != null){
                pluginClassNames.add(pluginClass);
              }

              Common.logger.log(Level.INFO, "[PluginToolKit][loadPlugins()]  - Found plugin: "+pluginClass);
            } 
          } else {
            Common.logger.log(Level.SEVERE, "[PluginToolKit][loadPlugins()] Unable to list plugin dir: "+pluginDir.getPath());
          }
          
        } catch (Exception ex) {
          Common.logger.log(Level.SEVERE, "[PluginToolKit][loadPlugins()] Unable to list plugin dir: "+pluginDir.getPath(), ex);
        }
      }
    }
    
    fireEvent(new PluginToolkitEvent(this, PluginToolkitEvent.PLUGIN_DISCOVERING_FINISHED, "Plugin discovering finished"));
    
    if ((pluginClassNames != null) && (pluginClassNames.size() > 0)){
      
      fireEvent(new PluginToolkitEvent(this, PluginToolkitEvent.PLUGIN_LOADING_START, "", pluginClassNames.size()));
      for(int i = 0; i < pluginClassNames.size(); i++){
        try {

          pluginClass = pluginClassNames.get(i);
          
          Common.logger.log(Level.INFO, "[PluginToolkit][loadPlugins()]  - Load "+pluginClass);
          ap = (IPlugin) Class.forName(pluginClass).getDeclaredConstructor().newInstance();
          plugins.add(ap);
          taskCurrentTime += 1;
          
          fireEvent(new PluginToolkitEvent(this, PluginToolkitEvent.PLUGIN_LOADING_LOADED, ap, taskCurrentTime));
          
          Common.logger.log(Level.INFO, "[PluginToolkit][loadPlugins()]  - Load "+pluginClass+" [OK]");
        } catch (ClassNotFoundException ex) {
          Common.logger.log(Level.SEVERE, "[PluginToolkit][loadPlugins()]  - Load "+pluginClass+" [FAIL]");
          Common.logger.log(Level.SEVERE, "PluginToolkit Cannot register plugin "+pluginClass);
          Common.logger.log(Level.SEVERE, "the plugin is not available", ex);
          taskCurrentTime += 1;
          fireEvent(new PluginToolkitEvent(this, PluginToolkitEvent.PLUGIN_LOADING_ERROR, pluginDir.getPath(), taskCurrentTime));
          
        } catch (IllegalAccessException ex) {
          Common.logger.log(Level.SEVERE, "[PluginToolkit][loadPlugins()]  - Load "+pluginClass+" [FAIL]");
          Common.logger.log(Level.SEVERE, "Cannot register plugin "+pluginClass);
          Common.logger.log(Level.SEVERE, "the plugin cannot be accessed (illegal access)", ex);
          taskCurrentTime += 1;
          fireEvent(new PluginToolkitEvent(this, PluginToolkitEvent.PLUGIN_LOADING_ERROR, pluginDir.getPath(), taskCurrentTime));
          
        } catch (InstantiationException ex) {
          Common.logger.log(Level.SEVERE, "[PluginToolkit][loadPlugins()]  - Load "+pluginClass+" [FAIL]");
          Common.logger.log(Level.SEVERE, "Cannot register plugin "+pluginClass);
          Common.logger.log(Level.SEVERE, "the plugin cannot be instanciated", ex);
          
          taskCurrentTime += 1;
          fireEvent(new PluginToolkitEvent(this, PluginToolkitEvent.PLUGIN_LOADING_ERROR, pluginDir.getPath(), taskCurrentTime));
        } catch (IllegalArgumentException ex) {
          Common.logger.log(Level.SEVERE, "[PluginToolkit][loadPlugins()]  - Load "+pluginClass+" [FAIL]");
          Common.logger.log(Level.SEVERE, "Cannot register plugin "+pluginClass);
          Common.logger.log(Level.SEVERE, "the plugin cannot be instanciated", ex);
          taskCurrentTime += 1;
          fireEvent(new PluginToolkitEvent(this, PluginToolkitEvent.PLUGIN_LOADING_ERROR, pluginDir.getPath(), taskCurrentTime));
		} catch (InvocationTargetException ex) {
		  Common.logger.log(Level.SEVERE, "[PluginToolkit][loadPlugins()]  - Load "+pluginClass+" [FAIL]");
	      Common.logger.log(Level.SEVERE, "Cannot register plugin "+pluginClass);
	      Common.logger.log(Level.SEVERE, "the plugin cannot be instanciated", ex);
	      taskCurrentTime += 1;
	      fireEvent(new PluginToolkitEvent(this, PluginToolkitEvent.PLUGIN_LOADING_ERROR, pluginDir.getPath(), taskCurrentTime));
		} catch (NoSuchMethodException ex) {
		  Common.logger.log(Level.SEVERE, "[PluginToolkit][loadPlugins()]  - Load "+pluginClass+" [FAIL]");
	      Common.logger.log(Level.SEVERE, "Cannot register plugin "+pluginClass);
	      Common.logger.log(Level.SEVERE, "the plugin cannot be instanciated", ex);
	      taskCurrentTime += 1;
	      fireEvent(new PluginToolkitEvent(this, PluginToolkitEvent.PLUGIN_LOADING_ERROR, pluginDir.getPath(), taskCurrentTime));
		} catch (SecurityException ex) {
		  Common.logger.log(Level.SEVERE, "[PluginToolkit][loadPlugins()]  - Load "+pluginClass+" [FAIL]");
	      Common.logger.log(Level.SEVERE, "Cannot register plugin "+pluginClass);
	      Common.logger.log(Level.SEVERE, "the plugin cannot be instanciated", ex);
	      taskCurrentTime += 1;
	      fireEvent(new PluginToolkitEvent(this, PluginToolkitEvent.PLUGIN_LOADING_ERROR, pluginDir.getPath(), taskCurrentTime));
		}   
      }
    } else{
      plugins = null;
    }
    
    return plugins;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy