001    package org.maltparser.core.plugin;
002    
003    import java.io.File;
004    import java.lang.reflect.Constructor;
005    import java.lang.reflect.InvocationTargetException;
006    import java.util.HashMap;
007    import java.util.Iterator;
008    import java.util.TreeSet;
009    import org.maltparser.core.exception.MaltChainedException;
010    
011    /**
012    Loads MaltParser plug-ins and makes new instances of classes within these plug-ins. 
013    
014    @author Johan Hall
015    
016    @since 1.0
017     */
018    public class PluginLoader implements Iterable<Plugin> {
019            private HashMap<String, Plugin> plugins;
020            private TreeSet<String> pluginNames;
021            private File[] directories;
022            private JarLoader jarLoader;
023            private static PluginLoader uniqueInstance = new PluginLoader();
024            
025            /**
026             * Creates a PluginLoader
027             * 
028             * @throws PluginException
029             */
030            private PluginLoader() {
031                    pluginNames = new TreeSet<String>();
032                    plugins = new HashMap<String, Plugin>();
033                    jarLoader = null;
034            }
035            
036            /**
037            * Returns a reference to the single instance.
038            */
039            public static PluginLoader instance() {
040                    return uniqueInstance;
041            }
042            
043            /**
044             * Loads plug-ins from one directory
045             * 
046             * @param pluginDirectory The directory that contains all plug-ins
047             * @throws MaltChainedException
048             */
049            public void loadPlugins(File pluginDirectory) throws MaltChainedException {
050                    this.loadPlugins(new File[] {pluginDirectory});
051            }
052            
053            /**
054             * Loads plug-ins from one or more directories
055             * 
056             * @param pluginDirectories An array of directories that contains all plug-ins
057             * @throws MaltChainedException
058             */
059            public void loadPlugins(File[] pluginDirectories) throws MaltChainedException {
060                    directories = new File[pluginDirectories.length];
061                    for (int i = 0; i < directories.length; i++) {
062                            directories[i] = pluginDirectories[i];
063                    }
064                    
065                    try {
066                            Class<?> self = Class.forName("org.maltparser.core.plugin.PluginLoader");
067                            jarLoader = new JarLoader(self.getClassLoader());               
068                    } catch (ClassNotFoundException e) {
069                            throw new PluginException("The class 'org.maltparser.core.plugin.PluginLoader' not found. ", e);
070                    }       
071                    traverseDirectories();
072            }
073            
074            /**
075             * Traverse all the plug-in directories
076             * 
077             * @throws MaltChainedException
078             */
079            private void traverseDirectories() throws MaltChainedException {
080                    for (int i = 0; i < directories.length; i++) {
081                            traverseDirectory(directories[i]);
082                    }
083            }
084            
085            /**
086             * Traverse all plug-ins and sub-directories within one plug-in directory.
087             * 
088             * @param directory The directory that contains plug-ins
089             * @throws MaltChainedException
090             */
091            private void traverseDirectory(File directory) throws MaltChainedException {
092                    if (!directory.isDirectory() && directory.getName().endsWith(".jar")) {
093                            pluginNames.add(directory.getAbsolutePath());
094                            Plugin plugin = new Plugin(directory);
095                            plugins.put(directory.getAbsolutePath(), plugin);
096                            if (jarLoader.readJarFile(plugin.getUrl()) == false) {
097                                    plugins.remove(directory.getAbsolutePath());
098                            }
099                    }
100            
101            if (directory.isDirectory()) {
102                String[] children = directory.list();
103                for (int i=0; i<children.length; i++) {
104                    traverseDirectory(new File(directory, children[i]));
105                }
106            }
107            }
108            
109            /**
110             * Returns the Class object for the class with the specified name.
111             * 
112             * @param classname the fully qualified name of the desired class
113             * @return the Class object for the class with the specified name.
114             */
115            public Class<?> getClass(String classname) {
116                    if (jarLoader != null) {
117                            return jarLoader.getClass(classname);
118                    } else {
119                            return null;
120                    }
121            }
122            
123            /**
124             * Creates a new instance of a class within one of the plug-ins
125             * 
126             * @param classname The fully qualified name of the desired class
127             * @param argTypes An array of classes (fully qualified name) that specify the arguments to the constructor 
128             * @param args An array of objects that will be the actual parameters to the constructor (the type should corresponds to the argTypes).
129             * @return a reference to the created instance.
130             * @throws MaltChainedException
131             */
132            public Object newInstance(String classname, Class<?>[] argTypes, Object[] args) throws MaltChainedException {
133                    try {
134                            if (jarLoader == null) {
135                                    return null;
136                            }
137                            Class<?> clazz = jarLoader.getClass(classname);
138                            Object o = null;
139                            if (clazz == null)
140                                    return null;
141                            if (argTypes != null) {
142                                    Constructor<?> constructor = clazz.getConstructor(argTypes);
143                                    o = constructor.newInstance(args);
144                            } else {
145                                    o = clazz.newInstance();
146                            }
147                            return o;
148                    } catch (NoSuchMethodException e) {
149                            throw new PluginException("The plugin loader was not able to create an instance of the class '"+classname+"'. ", e);
150                    } catch (InstantiationException e) {
151                            throw new PluginException("The plugin loader was not able to create an instance of the class '"+classname+"'. ", e);
152                    } catch (IllegalAccessException e) {
153                            throw new PluginException("The plugin loader was not able to create an instance of the class '"+classname+"'. ", e);
154                    } catch (InvocationTargetException e) {
155                            throw new PluginException("The plugin loader was not able to create an instance of the class '"+classname+"'. ", e);
156                    }
157            }
158            
159            public Iterator<Plugin> iterator() {
160                    return plugins.values().iterator();
161            }
162            
163            
164            public String toString() {
165                    StringBuilder sb = new StringBuilder();
166                    for (Plugin plugin : this) {
167                            sb.append(plugin.toString() + "\n");
168                    }
169                    return sb.toString();
170            }
171    }