View Javadoc
1 /* 2 * (C) 2002 David Carr david@carr.name 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19 package net.sourceforge.mflow.impl; 20 21 import java.io.DataInputStream; 22 import java.io.File; 23 import java.io.IOException; 24 import java.io.InputStream; 25 import java.net.MalformedURLException; 26 import java.net.URL; 27 import java.util.ArrayList; 28 import java.util.HashMap; 29 import java.util.Iterator; 30 import java.util.List; 31 import java.util.Map; 32 import java.util.jar.Attributes; 33 import java.util.jar.JarEntry; 34 import java.util.jar.JarFile; 35 import java.util.jar.Manifest; 36 import java.util.logging.Logger; 37 38 import javax.swing.Icon; 39 import javax.swing.ImageIcon; 40 import javax.swing.JDialog; 41 42 import net.sourceforge.mflow.api.Plugin; 43 import net.sourceforge.mflow.api.PluginManager; 44 import net.sourceforge.mflow.reflect.ParamArgPair; 45 import net.sourceforge.mflow.reflect.ReflectionException; 46 import net.sourceforge.mflow.reflect.ReflectionUtil; 47 import net.sourceforge.mflow.util.IOUtil; 48 49 /*** 50 * <p>Used to locate plugins within JAR files. Plugins must have an activator, 51 * which serves as the entry point to the plugin. All attributes of plugins are 52 * specified in the manifest of their JAR file.</p> 53 * 54 * <p>Example: 55 * <pre>Name: net.sourceforge.mflow.folder.sftp.Activator.class 56 * PluginName: SFTP Folder 57 * Type: Folder 58 * DescriptionFile: net/sourceforge/mflow/folder/sftp/description.txt 59 * IconFile: net/sourceforge/mflow/folder/sftp/images/icon.gif 60 * ConfigurationDialog: net.sourceforge.mflow.folder.sftp.ConfigurationDialog 61 * Version: 1.0</pre> 62 * 63 * <p>The <code>Name</code> field identifies the Activator class file in the 64 * JAR. The <code>PluginName</code> field provides a textual name for the 65 * plugin, and the <code>Type</code> field identifies the type of the plugin. 66 * These fields must be present in the entry, whereas the remaining fields are 67 * optional.</p> 68 * 69 * <p>The <code>DescriptionFile</code> field identifies a text file in the JAR 70 * that contains a detailed description of the plugin (and may optionally 71 * include a copyright message or other related information). 72 * <code>IconFile</code> identifies an icon image for the plugin. 73 * <code>ConfigurationDialog</code> is the fully-qualified name of a class 74 * within the JAR that provides a GUI for configuring the plugin. 75 * Finally, <code>Version</code> specifies the version number of the plugin.</p> 76 * 77 * <p>The <code>PluginLocator</code> reads a JAR Manifest, searching for entries 78 * that include a <code>PluginName</code> field. For each valid entry that is 79 * found, a <code>Plugin</code> object is constructed which encapsulates all 80 * of the information specified in the entry.</p> 81 * 82 * @author carrd 83 */ 84 public class PluginLocator { 85 private static final Logger log = 86 Logger.getLogger(PluginLocator.class.getName()); 87 private final PluginClassLoader loader = new PluginClassLoader(); 88 private PluginManager pluginManager; 89 90 private URL[] convertFilesToURLs(List files) throws MalformedURLException { 91 URL[] ret = new URL[files.size()]; 92 for (int i = 0; i < files.size(); i++) { 93 File file = (File) files.get(i); 94 String fileURL = file.toURL().toExternalForm(); 95 URL url = new URL("jar:" + fileURL); 96 ret[i] = url; 97 } 98 return ret; 99 } 100 101 PluginLocator(PluginManager pluginManager) { 102 this.pluginManager = pluginManager; 103 } 104 105 /* 106 * Construct a plugin object from data obtained in the manifest. 107 */ 108 private Plugin constructPlugin( 109 JarFile jar, 110 String className, 111 Attributes attrs) { 112 String name = null; 113 String type = null; 114 String description = null; 115 String descriptionFile = null; 116 String version = null; 117 String iconFile = null; 118 Icon icon = null; 119 String dialogClass = null; 120 JDialog dialog = null; 121 for (Iterator it = attrs.keySet().iterator(); it.hasNext();) { 122 Attributes.Name attrNameObj = (Attributes.Name) it.next(); 123 String attrName = attrNameObj.toString(); 124 String attrValue = attrs.getValue(attrName); 125 if (attrName.equals("PluginName")) { 126 name = attrValue; 127 } else if (attrName.equals("Type")) { 128 type = attrValue; 129 } else if (attrName.equals("DescriptionFile")) { 130 descriptionFile = attrValue; 131 } else if (attrName.equals("IconFile")) { 132 iconFile = attrValue; 133 } else if (attrName.equals("Version")) { 134 version = attrValue; 135 } else if (attrName.equals("ConfigurationDialog")) { 136 dialogClass = attrValue; 137 } 138 } 139 if ((type == null) || (name == null)) { 140 return null; //Can't construct a plugin without the mandatory attributes 141 } 142 icon = getIcon(jar, iconFile); 143 description = getDescription(jar, descriptionFile); 144 dialog = getDialog(dialogClass); 145 return new PluginImpl( 146 this.pluginManager, 147 className, 148 name, 149 type, 150 description, 151 version, 152 icon, 153 dialog); 154 } 155 156 private JDialog getDialog(String dialogClass) { 157 JDialog ret = null; 158 if (dialogClass != null) { //load the configuration dialog 159 Class[] paramType = new Class[] { PluginManager.class }; 160 Object[] arg = new Object[] { this.pluginManager }; 161 List sigs = new ArrayList(); 162 ParamArgPair pair = new ParamArgPair(paramType, arg); 163 sigs.add(pair); 164 sigs.add(new ParamArgPair()); 165 try { 166 ret = (JDialog) ReflectionUtil.instantiate(dialogClass, sigs); 167 } catch (ReflectionException re) { 168 log.throwing(getClass().getName(), "getDialog", re); 169 } 170 } 171 return ret; 172 } 173 174 private Icon getIcon(JarFile jar, String iconFile) { 175 if ((iconFile != null)) { //load the icon 176 JarEntry entry = (JarEntry) jar.getEntry(iconFile); 177 if (entry != null) { 178 InputStream is = null; 179 try { 180 is = jar.getInputStream(entry); 181 byte[] data = IOUtil.readStreamToByteArray(is); 182 return new ImageIcon(data); 183 } catch (IOException ioe) { 184 log.throwing(getClass().getName(), "getIcon", ioe); 185 } finally { 186 IOUtil.closeStream(is); 187 } 188 } 189 } 190 return null; 191 } 192 193 private String getDescription(JarFile jar, String descriptionFile) { 194 if (descriptionFile != null) { //load the description 195 JarEntry entry = (JarEntry) jar.getEntry(descriptionFile); 196 if (entry != null) { 197 InputStream is = null; 198 try { 199 is = jar.getInputStream(entry); 200 return IOUtil.readStreamToString(new DataInputStream(is)); 201 } catch (IOException ioe) { 202 log.throwing(getClass().getName(), "getDescription", ioe); 203 } finally { 204 IOUtil.closeStream(is); 205 } 206 } 207 } 208 return null; 209 } 210 211 /*** 212 * @param files 213 */ 214 public void addFiles(List files) { 215 try { 216 URL[] urls = convertFilesToURLs(files); 217 this.loader.addURLs(urls); 218 } catch (MalformedURLException mue) { 219 log.throwing(getClass().getName(), "addFiles", mue); 220 } 221 } 222 223 /*** 224 * Find all plugins in the specified JAR file. 225 * 226 * @param file The path of a JAR file. 227 * @return A (possibly empty) <code>Iterator</code> of <code>Plugin</code> 228 * objects representing the plugins found in the JAR file. 229 */ 230 public Iterator findPlugins(File file) { 231 List entries = new ArrayList(); 232 JarFile jarFile = null; 233 Map map = null; 234 try { 235 jarFile = new JarFile(file); 236 Manifest manifest = jarFile.getManifest(); 237 map = manifest.getEntries(); 238 } catch (IOException ioe) { 239 map = new HashMap(); //just return an empty iterator 240 } 241 for (Iterator it = map.keySet().iterator(); it.hasNext();) { 242 String classFile = (String) it.next(); 243 Attributes attrs = (Attributes) map.get(classFile); 244 String className = PluginClassLoader.classPathToName(classFile); 245 Plugin p = constructPlugin(jarFile, className, attrs); 246 if (p != null) { 247 entries.add(p); 248 } 249 } 250 return entries.iterator(); 251 } 252 }

This page was automatically generated by Maven