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 }