📄 pluginjar.java
字号:
/* * PluginJAR.java - Controls JAR loading and unloading * :tabSize=8:indentSize=8:noTabs=false: * :folding=explicit:collapseFolds=1: * * Copyright (C) 1999, 2004 Slava Pestov * * This program 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 2 * of the License, or any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */package org.gjt.sp.jedit;//{{{ Importsimport javax.swing.SwingUtilities;import java.io.*;import java.lang.reflect.Modifier;import java.net.URL;import java.util.*;import java.util.zip.*;import org.gjt.sp.jedit.browser.VFSBrowser;import org.gjt.sp.jedit.buffer.*;import org.gjt.sp.jedit.gui.DockableWindowManager;import org.gjt.sp.jedit.msg.*;import org.gjt.sp.util.Log;//}}}/** * Loads and unloads plugins.<p> * * <h3>JAR file contents</h3> * * When loading a plugin, jEdit looks for the following resources: * * <ul> * <li>A file named <code>actions.xml</code> defining plugin actions. * Only one such file per plugin is allowed. See {@link ActionSet} for * syntax.</li> * <li>A file named <code>browser.actions.xml</code> defining file system * browser actions. * Only one such file per plugin is allowed. See {@link ActionSet} for * syntax.</li> * <li>A file named <code>dockables.xml</code> defining dockable windows. * Only one such file per plugin is allowed. See {@link * org.gjt.sp.jedit.gui.DockableWindowManager} for * syntax.</li> * <li>A file named <code>services.xml</code> defining additional services * offered by the plugin, such as virtual file systems. * Only one such file per plugin is allowed. See {@link * org.gjt.sp.jedit.ServiceManager} for * syntax.</li> * <li>File with extension <code>.props</code> containing name/value pairs * separated by an equals sign. * A plugin can supply any number of property files. Property files are used * to define plugin men items, plugin option panes, as well as arbitriary * settings and strings used by the plugin. See {@link EditPlugin} for * information about properties used by jEdit. See * <code>java.util.Properties</code> for property file syntax.</li> * </ul> * * For a plugin to actually do something once it is resident in memory, * it must contain a class whose name ends with <code>Plugin</code>. * This class, known as the <i>plugin core class</i> must extend * {@link EditPlugin} and define a few required properties, otherwise it is * ignored. * * <h3>Dynamic and deferred loading</h3> * * Unlike in prior jEdit versions, jEdit 4.2 and later allow * plugins to be added and removed to the resident set at any time using * the {@link jEdit#addPluginJAR(String)} and * {@link jEdit#removePluginJAR(PluginJAR,boolean)} methods. Furthermore, the * plugin core class might not be loaded until the plugin is first used. See * {@link EditPlugin#start()} for a full description. * * @see org.gjt.sp.jedit.jEdit#getProperty(String) * @see org.gjt.sp.jedit.jEdit#getPlugin(String) * @see org.gjt.sp.jedit.jEdit#getPlugins() * @see org.gjt.sp.jedit.jEdit#getPluginJAR(String) * @see org.gjt.sp.jedit.jEdit#getPluginJARs() * @see org.gjt.sp.jedit.jEdit#addPluginJAR(String) * @see org.gjt.sp.jedit.jEdit#removePluginJAR(PluginJAR,boolean) * @see org.gjt.sp.jedit.ActionSet * @see org.gjt.sp.jedit.gui.DockableWindowManager * @see org.gjt.sp.jedit.OptionPane * @see org.gjt.sp.jedit.PluginJAR * @see org.gjt.sp.jedit.ServiceManager * * @author Slava Pestov * @version $Id: PluginJAR.java,v 1.44 2004/03/19 22:42:21 spestov Exp $ * @since jEdit 4.2pre1 */public class PluginJAR{ //{{{ getPath() method /** * Returns the full path name of this plugin's JAR file. */ public String getPath() { return path; } //}}} //{{{ getCachePath() method /** * Returns the full path name of this plugin's summary file. * The summary file is used to store certain information which allows * loading of the plugin's resources and core class to be deferred * until the plugin is first used. As long as a plugin is using the * jEdit 4.2 plugin API, no extra effort is required to take advantage * of the summary cache. */ public String getCachePath() { return cachePath; } //}}} //{{{ getFile() method /** * Returns a file pointing to the plugin JAR. */ public File getFile() { return file; } //}}} //{{{ getClassLoader() method /** * Returns the plugin's class loader. */ public JARClassLoader getClassLoader() { return classLoader; } //}}} //{{{ getZipFile() method /** * Returns the plugin's JAR file, opening it if necessary. * @since jEdit 4.2pre1 */ public synchronized ZipFile getZipFile() throws IOException { if(zipFile == null) { Log.log(Log.DEBUG,this,"Opening " + path); zipFile = new ZipFile(path); } return zipFile; } //}}} //{{{ getActions() method /** * @deprecated Call getActionSet() instead */ public ActionSet getActions() { return getActionSet(); } //}}} //{{{ getActionSet() method /** * Returns the plugin's action set for the jEdit action context * {@link jEdit#getActionContext()}. These actions are loaded from * the <code>actions.xml</code> file; see {@link ActionSet}. *. * @since jEdit 4.2pre1 */ public ActionSet getActionSet() { return actions; } //}}} //{{{ getBrowserActionSet() method /** * Returns the plugin's action set for the file system browser action * context {@link * org.gjt.sp.jedit.browser.VFSBrowser#getActionContext()}. * These actions are loaded from * the <code>browser.actions.xml</code> file; see {@link ActionSet}. *. * @since jEdit 4.2pre1 */ public ActionSet getBrowserActionSet() { return browserActions; } //}}} //{{{ checkDependencies() method /** * Returns true if all dependencies are satisified, false otherwise. * Also if dependencies are not satisfied, the plugin is marked as * "broken". */ public boolean checkDependencies() { if(plugin == null) return true; int i = 0; boolean ok = true; boolean optional = false; String name = plugin.getClassName(); String dep; while((dep = jEdit.getProperty("plugin." + name + ".depend." + i++)) != null) { if(dep.startsWith("optional ")) { optional = true; dep = dep.substring("optional ".length()); } int index = dep.indexOf(' '); if(index == -1) { Log.log(Log.ERROR,this,name + " has an invalid" + " dependency: " + dep); ok = false; continue; } String what = dep.substring(0,index); String arg = dep.substring(index + 1); if(what.equals("jdk")) { if(!optional && MiscUtilities.compareStrings( System.getProperty("java.version"), arg,false) < 0) { String[] args = { arg, System.getProperty("java.version") }; jEdit.pluginError(path,"plugin-error.dep-jdk",args); ok = false; } } else if(what.equals("jedit")) { if(arg.length() != 11) { Log.log(Log.ERROR,this,"Invalid jEdit version" + " number: " + arg); ok = false; } if(!optional && MiscUtilities.compareStrings( jEdit.getBuild(),arg,false) < 0) { String needs = MiscUtilities.buildToVersion(arg); String[] args = { needs, jEdit.getVersion() }; jEdit.pluginError(path, "plugin-error.dep-jedit",args); ok = false; } } else if(what.equals("plugin")) { int index2 = arg.indexOf(' '); if(index2 == -1) { Log.log(Log.ERROR,this,name + " has an invalid dependency: " + dep + " (version is missing)"); ok = false; continue; } String pluginName = arg.substring(0,index2); String needVersion = arg.substring(index2 + 1); String currVersion = jEdit.getProperty("plugin." + pluginName + ".version"); EditPlugin plugin = jEdit.getPlugin(pluginName); if(plugin == null) { if(!optional) { String[] args = { needVersion, pluginName }; jEdit.pluginError(path, "plugin-error.dep-plugin.no-version", args); ok = false; } } else if(MiscUtilities.compareStrings( currVersion,needVersion,false) < 0) { if(!optional) { String[] args = { needVersion, pluginName, currVersion }; jEdit.pluginError(path, "plugin-error.dep-plugin",args); ok = false; } } else if(plugin instanceof EditPlugin.Broken) { if(!optional) { String[] args = { pluginName }; jEdit.pluginError(path, "plugin-error.dep-plugin.broken",args); ok = false; } } else { PluginJAR jar = plugin.getPluginJAR(); jar.theseRequireMe.add(path); weRequireThese.add(jar.getPath()); } } else if(what.equals("class")) { if(!optional) { try { classLoader.loadClass(arg,false); } catch(Exception e) { String[] args = { arg }; jEdit.pluginError(path, "plugin-error.dep-class",args); ok = false; } } } else { Log.log(Log.ERROR,this,name + " has unknown" + " dependency: " + dep); ok = false; } } // each JAR file listed in the plugin's jars property // needs to know that we need them String jars = jEdit.getProperty("plugin." + plugin.getClassName() + ".jars"); if(jars != null) { String dir = MiscUtilities.getParentOfPath(path); StringTokenizer st = new StringTokenizer(jars); while(st.hasMoreTokens()) { String jarPath = MiscUtilities.constructPath( dir,st.nextToken()); PluginJAR jar = jEdit.getPluginJAR(jarPath); if(jar == null) { String[] args = { jarPath }; jEdit.pluginError(path, "plugin-error.missing-jar",args); ok = false; } else { weRequireThese.add(jarPath); jar.theseRequireMe.add(path); } } } if(!ok) breakPlugin(); return ok; } //}}} //{{{ getDependentPlugins() method /** * Returns an array of all plugins that depend on this one. * @since jEdit 4.2pre2 */ public String[] getDependentPlugins() { return (String[])theseRequireMe.toArray( new String[theseRequireMe.size()]); } //}}} //{{{ getPlugin() method /** * Returns the plugin core class for this JAR file. Note that if the * plugin has not been activated, this will return an instance of * {@link EditPlugin.Deferred}. If you need the actual plugin core * class instance, call {@link #activatePlugin()} first. * * @since jEdit 4.2pre1 */ public EditPlugin getPlugin() { return plugin; } //}}} //{{{ activatePlugin() method /** * Loads the plugin core class. Does nothing if the plugin core class * has already been loaded. This method might be called on startup, * depending on what properties are set. See {@link EditPlugin#start()}. * This method is thread-safe. * * @since jEdit 4.2pre1 */ public void activatePlugin() { synchronized(this) { if(activated) { // recursive call return; } activated = true; if(!(plugin instanceof EditPlugin.Deferred)) return; String className = plugin.getClassName(); try { Class clazz = classLoader.loadClass(className,false); int modifiers = clazz.getModifiers(); if(Modifier.isInterface(modifiers) || Modifier.isAbstract(modifiers) || !EditPlugin.class.isAssignableFrom(clazz)) { Log.log(Log.ERROR,this,"Plugin has properties but does not extend EditPlugin: " + className); breakPlugin(); return; } plugin = (EditPlugin)clazz.newInstance(); plugin.jar = (EditPlugin.JAR)this; } catch(Throwable t) { breakPlugin(); Log.log(Log.ERROR,this,"Error while starting plugin " + className); Log.log(Log.ERROR,this,t); String[] args = { t.toString() }; jEdit.pluginError(path,"plugin-error.start-error",args); return; } } if(jEdit.isMainThread() || SwingUtilities.isEventDispatchThread()) { startPlugin(); } else { // for thread safety startPluginLater(); } EditBus.send(new PluginUpdate(this,PluginUpdate.ACTIVATED,false)); } //}}} //{{{ activateIfNecessary() method /** * Should be called after a new plugin is installed. * @since jEdit 4.2pre2 */ public void activatePluginIfNecessary() { if(!(plugin instanceof EditPlugin.Deferred && plugin != null)) return; String className = plugin.getClassName(); // default for plugins that don't specify this property (ie,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -