|
What this is
Other links
The source code/* * 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; //{{{ Imports import 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.
Plugin .
* This class, known as the plugin core class must extend
* {@link EditPlugin} and define a few required properties, otherwise it is
* ignored.
*
* Dynamic and deferred loading* * 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.47 2004/04/20 19:58:39 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 * theactions.xml 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 browser.actions.xml 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,
// 4.1-style plugins) is to load them on startup
String activate = jEdit.getProperty("plugin."
+ className + ".activate");
if(activate == null)
{
// 4.1 plugin
if(!jEdit.isMainThread())
{
breakPlugin();
jEdit.pluginError(path,"plugin-error.not-42",null);
}
else
activatePlugin();
}
else
{
// 4.2 plugin
// if at least one property listed here is true,
// load the plugin
boolean load = false;
StringTokenizer st = new StringTokenizer(activate);
while(st.hasMoreTokens())
{
String prop = st.nextToken();
boolean value = jEdit.getBooleanProperty(prop);
if(value)
{
Log.log(Log.DEBUG,this,"Activating "
+ className + " because of " + prop);
load = true;
break;
}
}
if(load)
activatePlugin();
}
} //}}}
//{{{ deactivatePlugin() method
/**
* Unloads the plugin core class. Does nothing if the plugin core class
* has not been loaded.
* This method can only be called from the AWT event dispatch thread!
* @see EditPlugin#stop()
*
* @since jEdit 4.2pre3
*/
public void deactivatePlugin(boolean exit)
{
if(!activated)
return;
if(!exit)
{
// buffers retain a reference to the fold handler in
// question... and the easiest way to handle fold
// handler unloading is this...
Buffer buffer = jEdit.getFirstBuffer();
while(buffer != null)
{
if(buffer.getFoldHandler() != null
&& buffer.getFoldHandler().getClass()
.getClassLoader() == classLoader)
{
buffer.setFoldHandler(
new DummyFoldHandler());
}
buffer = buffer.getNext();
}
}
if(plugin != null && !(plugin instanceof EditPlugin.Broken))
{
if(plugin instanceof EBPlugin)
EditBus.removeFromBus((EBPlugin)plugin);
try
{
plugin.stop();
}
catch(Throwable t)
{
Log.log(Log.ERROR,this,"Error while "
+ "stopping plugin:");
Log.log(Log.ERROR,this,t);
}
plugin = new EditPlugin.Deferred(
plugin.getClassName());
plugin.jar = (EditPlugin.JAR)this;
EditBus.send(new PluginUpdate(this,
PluginUpdate.DEACTIVATED,exit));
if(!exit)
{
// see if this is a 4.1-style plugin
String activate = jEdit.getProperty("plugin."
+ plugin.getClassName() + ".activate");
if(activate == null)
{
breakPlugin();
jEdit.pluginError(path,"plugin-error.not-42",null);
}
}
}
activated = false;
} //}}}
//{{{ getDockablesURI() method
/**
* Returns the location of the plugin's
* dockables.xml file.
* @since jEdit 4.2pre1
*/
public URL getDockablesURI()
{
return dockablesURI;
} //}}}
//{{{ getServicesURI() method
/**
* Returns the location of the plugin's
* services.xml file.
* @since jEdit 4.2pre1
*/
public URL getServicesURI()
{
return servicesURI;
} //}}}
//{{{ toString() method
public String toString()
{
if(plugin == null)
return path;
else
return path + ",class=" + plugin.getClassName();
} //}}}
//{{{ Package-private members
//{{{ Static methods
//{{{ getPluginCache() method
static PluginCacheEntry getPluginCache(PluginJAR plugin)
{
String jarCachePath = plugin.getCachePath();
if(jarCachePath == null)
return null;
DataInputStream din = null;
try
{
PluginCacheEntry cache = new PluginCacheEntry();
cache.plugin = plugin;
cache.modTime = plugin.getFile().lastModified();
din = new DataInputStream(
new BufferedInputStream(
new FileInputStream(jarCachePath)));
if(cache.read(din))
return cache;
else
{
// returns false with outdated cache
return null;
}
}
catch(FileNotFoundException fnf)
{
return null;
}
catch(IOException io)
{
Log.log(Log.ERROR,PluginJAR.class,io);
return null;
}
finally
{
try
{
if(din != null)
din.close();
}
catch(IOException io)
{
Log.log(Log.ERROR,PluginJAR.class,io);
}
}
} //}}}
//{{{ setPluginCache() method
static void setPluginCache(PluginJAR plugin, PluginCacheEntry cache)
{
String jarCachePath = plugin.getCachePath();
if(jarCachePath == null)
return;
Log.log(Log.DEBUG,PluginJAR.class,"Writing " + jarCachePath);
DataOutputStream dout = null;
try
{
dout = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(jarCachePath)));
cache.write(dout);
dout.close();
}
catch(IOException io)
{
Log.log(Log.ERROR,PluginJAR.class,io);
try
{
if(dout != null)
dout.close();
}
catch(IOException io2)
{
Log.log(Log.ERROR,PluginJAR.class,io2);
}
new File(jarCachePath).delete();
}
} //}}}
//}}}
//{{{ PluginJAR constructor
PluginJAR(File file)
{
this.path = file.getPath();
String jarCacheDir = jEdit.getJARCacheDirectory();
if(jarCacheDir != null)
{
cachePath = MiscUtilities.constructPath(
jarCacheDir,file.getName() + ".summary");
}
this.file = file;
classLoader = new JARClassLoader(this);
actions = new ActionSet();
} //}}}
//{{{ init() method
void init()
{
boolean initialized = false;
PluginCacheEntry cache = getPluginCache(this);
if(cache != null)
{
loadCache(cache);
classLoader.activate();
initialized = true;
}
else
{
try
{
cache = generateCache();
if(cache != null)
{
setPluginCache(this,cache);
classLoader.activate();
initialized = true;
}
}
catch(IOException io)
{
Log.log(Log.ERROR,this,"Cannot load"
+ " plugin " + path);
Log.log(Log.ERROR,this,io);
String[] args = { io.toString() };
jEdit.pluginError(path,"plugin-error.load-error",args);
uninit(false);
}
}
} //}}}
//{{{ uninit() method
void uninit(boolean exit)
{
deactivatePlugin(exit);
if(!exit)
{
Iterator iter = weRequireThese.iterator();
while(iter.hasNext())
{
String path = (String)iter.next();
PluginJAR jar = jEdit.getPluginJAR(path);
if(jar != null)
jar.theseRequireMe.remove(this.path);
}
classLoader.deactivate();
BeanShell.resetClassManager();
if(actions != null)
jEdit.getActionContext().removeActionSet(actions);
if(browserActions != null)
VFSBrowser.getActionContext().removeActionSet(browserActions);
DockableWindowManager.unloadDockableWindows(this);
ServiceManager.unloadServices(this);
jEdit.removePluginProps(properties);
try
{
if(zipFile != null)
{
zipFile.close();
zipFile = null;
}
}
catch(IOException io)
{
Log.log(Log.ERROR,this,io);
}
}
} //}}}
//{{{ getClasses() method
String[] getClasses()
{
return classes;
} //}}}
//}}}
//{{{ Private members
//{{{ Instance variables
private String path;
private String cachePath;
private File file;
private JARClassLoader classLoader;
private ZipFile zipFile;
private Properties properties;
private String[] classes;
private ActionSet actions;
private ActionSet browserActions;
private EditPlugin plugin;
private URL dockablesURI;
private URL servicesURI;
private boolean activated;
private List theseRequireMe = new LinkedList();
private List weRequireThese = new LinkedList();
//}}}
//{{{ actionsPresentButNotCoreClass() method
private void actionsPresentButNotCoreClass()
{
Log.log(Log.WARNING,this,getPath() + " has an actions.xml but no plugin core class");
actions.setLabel("MISSING PLUGIN CORE CLASS");
} //}}}
//{{{ loadCache() method
private void loadCache(PluginCacheEntry cache)
{
classes = cache.classes;
/* this should be before dockables are initialized */
if(cache.cachedProperties != null)
{
properties = cache.cachedProperties;
jEdit.addPluginProps(cache.cachedProperties);
}
if(cache.actionsURI != null
&& cache.cachedActionNames != null)
{
actions = new ActionSet(this,
cache.cachedActionNames,
cache.cachedActionToggleFlags,
cache.actionsURI);
}
if(cache.browserActionsURI != null
&& cache.cachedBrowserActionNames != null)
{
browserActions = new ActionSet(this,
cache.cachedBrowserActionNames,
cache.cachedBrowserActionToggleFlags,
cache.browserActionsURI);
VFSBrowser.getActionContext().addActionSet(browserActions);
}
if(cache.dockablesURI != null
&& cache.cachedDockableNames != null
&& cache.cachedDockableActionFlags != null)
{
dockablesURI = cache.dockablesURI;
DockableWindowManager.cacheDockableWindows(this,
cache.cachedDockableNames,
cache.cachedDockableActionFlags);
}
if(actions.size() != 0)
jEdit.addActionSet(actions);
if(cache.servicesURI != null
&& cache.cachedServices != null)
{
servicesURI = cache.servicesURI;
for(int i = 0; i < cache.cachedServices.length;
i++)
{
ServiceManager.Descriptor d
= cache.cachedServices[i];
ServiceManager.registerService(d);
}
}
if(cache.pluginClass != null)
{
// Check if a plugin with the same name
// is already loaded
if(jEdit.getPlugin(cache.pluginClass) != null)
{
jEdit.pluginError(path,
"plugin-error.already-loaded",
null);
uninit(false);
}
else
{
String label = jEdit.getProperty(
"plugin." + cache.pluginClass
+ ".name");
actions.setLabel(jEdit.getProperty(
"action-set.plugin",
new String[] { label }));
plugin = new EditPlugin.Deferred(
cache.pluginClass);
plugin.jar = (EditPlugin.JAR)this;
}
}
else
{
if(actions.size() != 0)
actionsPresentButNotCoreClass();
}
} //}}}
//{{{ generateCache() method
private PluginCacheEntry generateCache() throws IOException
{
properties = new Properties();
LinkedList classes = new LinkedList();
ZipFile zipFile = getZipFile();
List plugins = new LinkedList();
PluginCacheEntry cache = new PluginCacheEntry();
cache.modTime = file.lastModified();
cache.cachedProperties = new Properties();
Enumeration entries = zipFile.entries();
while(entries.hasMoreElements())
{
ZipEntry entry = (ZipEntry)
entries.nextElement();
String name = entry.getName();
String lname = name.toLowerCase();
if(lname.equals("actions.xml"))
{
cache.actionsURI = classLoader.getResource(name);
}
else if(lname.equals("browser.actions.xml"))
{
cache.browserActionsURI = classLoader.getResource(name);
}
else if(lname.equals("dockables.xml"))
{
dockablesURI = classLoader.getResource(name);
cache.dockablesURI = dockablesURI;
}
else if(lname.equals("services.xml"))
{
servicesURI = classLoader.getResource(name);
cache.servicesURI = servicesURI;
}
else if(lname.endsWith(".props"))
{
InputStream in = classLoader.getResourceAsStream(name);
properties.load(in);
in.close();
}
else if(name.endsWith(".class"))
{
String className = MiscUtilities
.fileToClass(name);
if(className.endsWith("Plugin"))
{
plugins.add(className);
}
classes.add(className);
}
}
cache.cachedProperties = properties;
jEdit.addPluginProps(properties);
this.classes = cache.classes =
(String[])classes.toArray(
new String[classes.size()]);
String label = null;
Iterator iter = plugins.iterator();
while(iter.hasNext())
{
String className = (String)iter.next();
String _label = jEdit.getProperty("plugin."
+ className + ".name");
String version = jEdit.getProperty("plugin."
+ className + ".version");
if(_label == null || version == null)
{
Log.log(Log.WARNING,this,"Ignoring: "
+ className);
}
else
{
cache.pluginClass = className;
// Check if a plugin with the same name
// is already loaded
if(jEdit.getPlugin(className) != null)
{
jEdit.pluginError(path,
"plugin-error.already-loaded",
null);
return null;
}
else
{
plugin = new EditPlugin.Deferred(
className);
plugin.jar = (EditPlugin.JAR)this;
label = _label;
}
break;
}
}
if(cache.actionsURI != null)
{
actions = new ActionSet(this,null,null,
cache.actionsURI);
actions.load();
cache.cachedActionNames =
actions.getCacheableActionNames();
cache.cachedActionToggleFlags = new boolean[
cache.cachedActionNames.length];
for(int i = 0; i < cache.cachedActionNames.length; i++)
{
cache.cachedActionToggleFlags[i]
= jEdit.getBooleanProperty(
cache.cachedActionNames[i]
+ ".toggle");
}
}
if(cache.browserActionsURI != null)
{
browserActions = new ActionSet(this,null,null,
cache.browserActionsURI);
browserActions.load();
VFSBrowser.getActionContext().addActionSet(browserActions);
cache.cachedBrowserActionNames =
browserActions.getCacheableActionNames();
cache.cachedBrowserActionToggleFlags = new boolean[
cache.cachedBrowserActionNames.length];
for(int i = 0;
i < cache.cachedBrowserActionNames.length;
i++)
{
cache.cachedBrowserActionToggleFlags[i]
= jEdit.getBooleanProperty(
cache.cachedBrowserActionNames[i]
+ ".toggle");
}
}
if(dockablesURI != null)
{
DockableWindowManager.loadDockableWindows(this,
dockablesURI,cache);
}
if(actions.size() != 0)
{
if(label != null)
{
actions.setLabel(jEdit.getProperty(
"action-set.plugin",
new String[] { label }));
}
else
actionsPresentButNotCoreClass();
jEdit.addActionSet(actions);
}
if(servicesURI != null)
{
ServiceManager.loadServices(this,servicesURI,cache);
}
return cache;
} //}}}
//{{{ startPlugin() method
private void startPlugin()
{
try
{
plugin.start();
}
catch(Throwable t)
{
breakPlugin();
Log.log(Log.ERROR,PluginJAR.this,
"Error while starting plugin " + plugin.getClassName());
Log.log(Log.ERROR,PluginJAR.this,t);
String[] args = { t.toString() };
jEdit.pluginError(path,"plugin-error.start-error",args);
}
if(plugin instanceof EBPlugin)
{
if(jEdit.getProperty("plugin."
+ plugin.getClassName() + ".activate")
== null)
{
// old plugins expected jEdit 4.1-style
// behavior, where a PropertiesChanged
// was sent after plugins were started
((EBComponent)plugin).handleMessage(
new org.gjt.sp.jedit.msg.PropertiesChanged(null));
}
EditBus.addToBus((EBPlugin)plugin);
}
// buffers retain a reference to the fold handler in
// question... and the easiest way to handle fold
// handler loading is this...
Buffer buffer = jEdit.getFirstBuffer();
while(buffer != null)
{
FoldHandler handler =
FoldHandler.getFoldHandler(
buffer.getStringProperty("folding"));
// == null before loaded
if(buffer.getFoldHandler() != null
&& handler != null
&& handler != buffer.getFoldHandler())
{
buffer.setFoldHandler(handler);
}
buffer = buffer.getNext();
}
} //}}}
//{{{ startPluginLater() method
private void startPluginLater()
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
if(!activated)
return;
startPlugin();
}
});
} //}}}
//{{{ breakPlugin() method
private void breakPlugin()
{
plugin = new EditPlugin.Broken(plugin.getClassName());
plugin.jar = (EditPlugin.JAR)this;
// remove action sets, dockables, etc so that user doesn't
// see the broken plugin
uninit(false);
// but we want properties to hang around
jEdit.addPluginProps(properties);
} //}}}
//}}}
//{{{ PluginCacheEntry class
/**
* Used by the DockableWindowManager and
* ServiceManager to handle caching.
* @since jEdit 4.2pre1
*/
public static class PluginCacheEntry
{
public static final int MAGIC = 0xB7A2E420;
//{{{ Instance variables
public PluginJAR plugin;
public long modTime;
public String[] classes;
public URL actionsURI;
public String[] cachedActionNames;
public boolean[] cachedActionToggleFlags;
public URL browserActionsURI;
public String[] cachedBrowserActionNames;
public boolean[] cachedBrowserActionToggleFlags;
public URL dockablesURI;
public String[] cachedDockableNames;
public boolean[] cachedDockableActionFlags;
public URL servicesURI;
public ServiceManager.Descriptor[] cachedServices;
public Properties cachedProperties;
public String pluginClass;
//}}}
/* read() and write() must be kept perfectly in sync...
* its a very simple file format. doing it this way is
* faster than serializing since serialization calls
* reflection, etc. */
//{{{ read() method
public boolean read(DataInputStream din) throws IOException
{
int cacheMagic = din.readInt();
if(cacheMagic != MAGIC)
return false;
String cacheBuild = readString(din);
if(!cacheBuild.equals(jEdit.getBuild()))
return false;
long cacheModTime = din.readLong();
if(cacheModTime != modTime)
return false;
actionsURI = readURI(din);
cachedActionNames = readStringArray(din);
cachedActionToggleFlags = readBooleanArray(din);
browserActionsURI = readURI(din);
cachedBrowserActionNames = readStringArray(din);
cachedBrowserActionToggleFlags = readBooleanArray(din);
dockablesURI = readURI(din);
cachedDockableNames = readStringArray(din);
cachedDockableActionFlags = readBooleanArray(din);
servicesURI = readURI(din);
int len = din.readInt();
if(len == 0)
cachedServices = null;
else
{
cachedServices = new ServiceManager.Descriptor[len];
for(int i = 0; i < len; i++)
{
ServiceManager.Descriptor d = new
ServiceManager.Descriptor(
readString(din),
readString(din),
null,
plugin);
cachedServices[i] = d;
}
}
classes = readStringArray(din);
cachedProperties = readMap(din);
pluginClass = readString(din);
return true;
} //}}}
//{{{ write() method
public void write(DataOutputStream dout) throws IOException
{
dout.writeInt(MAGIC);
writeString(dout,jEdit.getBuild());
dout.writeLong(modTime);
writeString(dout,actionsURI);
writeStringArray(dout,cachedActionNames);
writeBooleanArray(dout,cachedActionToggleFlags);
writeString(dout,browserActionsURI);
writeStringArray(dout,cachedBrowserActionNames);
writeBooleanArray(dout,cachedBrowserActionToggleFlags);
writeString(dout,dockablesURI);
writeStringArray(dout,cachedDockableNames);
writeBooleanArray(dout,cachedDockableActionFlags);
writeString(dout,servicesURI);
if(cachedServices == null)
dout.writeInt(0);
else
{
dout.writeInt(cachedServices.length);
for(int i = 0; i < cachedServices.length; i++)
{
writeString(dout,cachedServices[i].clazz);
writeString(dout,cachedServices[i].name);
}
}
writeStringArray(dout,classes);
writeMap(dout,cachedProperties);
writeString(dout,pluginClass);
} //}}}
//{{{ Private members
//{{{ readString() method
private String readString(DataInputStream din)
throws IOException
{
int len = din.readInt();
if(len == 0)
return null;
char[] str = new char[len];
for(int i = 0; i < len; i++)
str[i] = din.readChar();
return new String(str);
} //}}}
//{{{ readURI() method
private URL readURI(DataInputStream din)
throws IOException
{
String str = readString(din);
if(str == null)
return null;
else
return new URL(str);
} //}}}
//{{{ readStringArray() method
private String[] readStringArray(DataInputStream din)
throws IOException
{
int len = din.readInt();
if(len == 0)
return null;
String[] str = new String[len];
for(int i = 0; i < len; i++)
{
str[i] = readString(din);
}
return str;
} //}}}
//{{{ readBooleanArray() method
private boolean[] readBooleanArray(DataInputStream din)
throws IOException
{
int len = din.readInt();
if(len == 0)
return null;
boolean[] bools = new boolean[len];
for(int i = 0; i < len; i++)
{
bools[i] = din.readBoolean();
}
return bools;
} //}}}
//{{{ readMap() method
private Properties readMap(DataInputStream din)
throws IOException
{
Properties returnValue = new Properties();
int count = din.readInt();
for(int i = 0; i < count; i++)
{
String key = readString(din);
String value = readString(din);
if(value == null)
value = "";
returnValue.put(key,value);
}
return returnValue;
} //}}}
//{{{ writeString() method
private void writeString(DataOutputStream dout,
Object obj) throws IOException
{
if(obj == null)
{
dout.writeInt(0);
}
else
{
String str = obj.toString();
dout.writeInt(str.length());
dout.writeChars(str);
}
} //}}}
//{{{ writeStringArray() method
private void writeStringArray(DataOutputStream dout,
String[] str) throws IOException
{
if(str == null)
{
dout.writeInt(0);
}
else
{
dout.writeInt(str.length);
for(int i = 0; i < str.length; i++)
{
writeString(dout,str[i]);
}
}
} //}}}
//{{{ writeBooleanArray() method
private void writeBooleanArray(DataOutputStream dout,
boolean[] bools) throws IOException
{
if(bools == null)
{
dout.writeInt(0);
}
else
{
dout.writeInt(bools.length);
for(int i = 0; i < bools.length; i++)
{
dout.writeBoolean(bools[i]);
}
}
} //}}}
//{{{ writeMap() method
private void writeMap(DataOutputStream dout, Map map)
throws IOException
{
dout.writeInt(map.size());
Iterator iter = map.keySet().iterator();
while(iter.hasNext())
{
String key = (String)iter.next();
writeString(dout,key);
writeString(dout,map.get(key));
}
} //}}}
//}}}
} //}}}
}
|
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.