KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > gjt > sp > jedit > PluginJAR


1 /*
2  * PluginJAR.java - Controls JAR loading and unloading
3  * :tabSize=8:indentSize=8:noTabs=false:
4  * :folding=explicit:collapseFolds=1:
5  *
6  * Copyright (C) 1999, 2004 Slava Pestov
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  */

22
23 package org.gjt.sp.jedit;
24
25 //{{{ Imports
26
import java.io.BufferedInputStream JavaDoc;
27 import java.io.BufferedOutputStream JavaDoc;
28 import java.io.DataInputStream JavaDoc;
29 import java.io.DataOutputStream JavaDoc;
30 import java.io.File JavaDoc;
31 import java.io.FileInputStream JavaDoc;
32 import java.io.FileNotFoundException JavaDoc;
33 import java.io.FileOutputStream JavaDoc;
34 import java.io.IOException JavaDoc;
35 import java.io.InputStream JavaDoc;
36 import java.lang.reflect.Modifier JavaDoc;
37 import java.net.URL JavaDoc;
38 import java.util.Enumeration JavaDoc;
39 import java.util.LinkedHashSet JavaDoc;
40 import java.util.LinkedList JavaDoc;
41 import java.util.List JavaDoc;
42 import java.util.Map JavaDoc;
43 import java.util.Properties JavaDoc;
44 import java.util.Set JavaDoc;
45 import java.util.StringTokenizer JavaDoc;
46 import java.util.zip.ZipEntry JavaDoc;
47 import java.util.zip.ZipFile JavaDoc;
48
49 import javax.swing.SwingUtilities JavaDoc;
50
51 import org.gjt.sp.jedit.browser.VFSBrowser;
52 import org.gjt.sp.jedit.buffer.DummyFoldHandler;
53 import org.gjt.sp.jedit.buffer.FoldHandler;
54 import org.gjt.sp.jedit.gui.DockableWindowFactory;
55 import org.gjt.sp.jedit.msg.PluginUpdate;
56 import org.gjt.sp.util.Log;
57 import org.gjt.sp.util.PropertiesBean;
58 import org.gjt.sp.util.StandardUtilities;
59 import org.gjt.sp.util.IOUtilities;
60 //}}}
61

62 /**
63  * Loads and unloads plugins.<p>
64  *
65  * <h3>JAR file contents</h3>
66  *
67  * When loading a plugin, jEdit looks for the following resources:
68  *
69  * <ul>
70  * <li>A file named <code>actions.xml</code> defining plugin actions.
71  * Only one such file per plugin is allowed. See {@link ActionSet} for
72  * syntax.</li>
73  * <li>A file named <code>browser.actions.xml</code> defining file system
74  * browser actions.
75  * Only one such file per plugin is allowed. See {@link ActionSet} for
76  * syntax.</li>
77  * <li>A file named <code>dockables.xml</code> defining dockable windows.
78  * Only one such file per plugin is allowed. See {@link
79  * org.gjt.sp.jedit.gui.DockableWindowManager} for
80  * syntax.</li>
81  * <li>A file named <code>services.xml</code> defining additional services
82  * offered by the plugin, such as virtual file systems.
83  * Only one such file per plugin is allowed. See {@link
84  * org.gjt.sp.jedit.ServiceManager} for
85  * syntax.</li>
86  * <li>File with extension <code>.props</code> containing name/value pairs
87  * separated by an equals sign.
88  * A plugin can supply any number of property files. Property files are used
89  * to define plugin men items, plugin option panes, as well as arbitriary
90  * settings and strings used by the plugin. See {@link EditPlugin} for
91  * information about properties used by jEdit. See
92  * <code>java.util.Properties</code> for property file syntax.</li>
93  * </ul>
94  *
95  * For a plugin to actually do something once it is resident in memory,
96  * it must contain a class whose name ends with <code>Plugin</code>.
97  * This class, known as the <i>plugin core class</i> must extend
98  * {@link EditPlugin} and define a few required properties, otherwise it is
99  * ignored.
100  *
101  * <h3>Dynamic and deferred loading</h3>
102  *
103  * Unlike in prior jEdit versions, jEdit 4.2 and later allow
104  * plugins to be added and removed to the resident set at any time using
105  * the {@link jEdit#addPluginJAR(String)} and
106  * {@link jEdit#removePluginJAR(PluginJAR,boolean)} methods. Furthermore, the
107  * plugin core class might not be loaded until the plugin is first used. See
108  * {@link EditPlugin#start()} for a full description.
109  *
110  *
111  * @see org.gjt.sp.jedit.jEdit#getProperty(String)
112  * @see org.gjt.sp.jedit.jEdit#getPlugin(String)
113  * @see org.gjt.sp.jedit.jEdit#getPlugins()
114  * @see org.gjt.sp.jedit.jEdit#getPluginJAR(String)
115  * @see org.gjt.sp.jedit.jEdit#getPluginJARs()
116  * @see org.gjt.sp.jedit.jEdit#addPluginJAR(String)
117  * @see org.gjt.sp.jedit.jEdit#removePluginJAR(PluginJAR,boolean)
118  * @see org.gjt.sp.jedit.ActionSet
119  * @see org.gjt.sp.jedit.gui.DockableWindowManager
120  * @see org.gjt.sp.jedit.OptionPane
121  * @see org.gjt.sp.jedit.PluginJAR
122  * @see org.gjt.sp.jedit.ServiceManager
123  *
124  * @author Slava Pestov
125  * @version $Id: PluginJAR.java 8660 2007-01-17 21:25:11Z kpouer $
126  * @since jEdit 4.2pre1
127  */

128 public class PluginJAR
129 {
130     //{{{ Instance variables
131
private final String JavaDoc path;
132     private String JavaDoc cachePath;
133     private final File JavaDoc file;
134
135     private final JARClassLoader classLoader;
136     private ZipFile JavaDoc zipFile;
137     private Properties JavaDoc properties;
138     private String JavaDoc[] classes;
139     private ActionSet actions;
140     private ActionSet browserActions;
141     private EditPlugin plugin;
142     private URL JavaDoc dockablesURI;
143     private URL JavaDoc servicesURI;
144     private boolean activated;
145
146     // Lists of jarPaths
147
private final Set JavaDoc<String JavaDoc> theseRequireMe = new LinkedHashSet JavaDoc<String JavaDoc>();
148     /** The plugins that uses me as optional dependency. */
149     private final Set JavaDoc<String JavaDoc> theseUseMe = new LinkedHashSet JavaDoc<String JavaDoc>();
150     private final Set JavaDoc<String JavaDoc> weRequireThese = new LinkedHashSet JavaDoc<String JavaDoc>();
151     private final Set JavaDoc<String JavaDoc> weUseThese = new LinkedHashSet JavaDoc<String JavaDoc>();
152     //}}}
153

154     // {{{ load(String jarPath, boolean activateDependentIfNecessary)
155
/**
156      * Loads a plugin, and its dependent plugins if necessary.
157      *
158      * @since jEdit 4.3pre7
159      *
160      */

161     public static PluginJAR load(String JavaDoc path, boolean loadDependents) {
162         PluginJAR jar = jEdit.getPluginJAR(path);
163         if (jar != null && jar.getPlugin() != null) {
164             return jar;
165         }
166         jEdit.addPluginJAR(path);
167         jar = jEdit.getPluginJAR(path);
168         String JavaDoc className = jar.getPlugin().getClassName();
169         if (loadDependents) {
170             Set JavaDoc<String JavaDoc> pluginLoadList = getDependencySet(className);
171             for (String JavaDoc jarName: pluginLoadList)
172             {
173                 String JavaDoc jarPath = findPlugin(jarName);
174                 load(jarPath, false);
175             }
176         }
177         // Load extra jars that are part of this plugin
178
String JavaDoc jars = jEdit.getProperty("plugin." + className + ".jars");
179         if(jars != null)
180         {
181             String JavaDoc dir = MiscUtilities.getParentOfPath(path);
182             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(jars);
183             while(st.hasMoreTokens())
184             {
185                 String JavaDoc _jarPath = MiscUtilities.constructPath(dir,st.nextToken());
186                 PluginJAR _jar = jEdit.getPluginJAR(_jarPath);
187                 if(_jar == null)
188                 {
189                     jEdit.addPluginJAR(_jarPath);
190                 }
191             }
192         }
193         jar.checkDependencies();
194         jar.activatePluginIfNecessary();
195         return jar;
196     } // }}}
197

198     //{{{ getPath() method
199
/**
200      * Returns the full path name of this plugin's JAR file.
201      */

202     public String JavaDoc getPath()
203     {
204         return path;
205     } //}}}
206

207     // {{{ findPlugin() method
208
/**
209      * Unlike getPlugin(), will return a PluginJAR that is not yet loaded,
210      * given its classname.
211      *
212      * @param className a class name
213      * @return the JARpath of the first PluginJAR it can find which contains this className,
214      * or null if not found.
215      * @since 4.3pre7
216      */

217     public static String JavaDoc findPlugin(String JavaDoc className)
218     {
219         EditPlugin ep = jEdit.getPlugin(className);
220         if (ep != null) return ep.getPluginJAR().getPath();
221
222         for (String JavaDoc JARpath: jEdit.getNotLoadedPluginJARs())
223         {
224             PluginJAR pjar = new PluginJAR(new File JavaDoc(JARpath));
225             if (pjar.containsClass(className))
226             {
227                 return JARpath;
228             }
229         }
230         return null;
231     } // }}}
232

233     // {{{ containsClass() function
234
/**
235      * @param className a class name
236      * @return true if this jar contains a class with that classname.
237      * @since jedit 4.3pre7
238      */

239     boolean containsClass(String JavaDoc className)
240     {
241         try
242         {
243             getZipFile();
244         }
245         catch (IOException JavaDoc ioe) { throw new RuntimeException JavaDoc(ioe);}
246         Enumeration JavaDoc itr = zipFile.entries();
247         while (itr.hasMoreElements())
248         {
249             String JavaDoc entry = itr.nextElement().toString();
250             if (jarCompare(entry, className)) return true;
251         }
252         return false;
253
254     } // }}}
255

256     // {{{ jarCompare() - compare function for a classname in a jarfile.
257

258     private static boolean jarCompare(String JavaDoc name1, String JavaDoc name2)
259     {
260         name1 = name1.replace('/','.');
261         name2 = name2.replace('/','.');
262         if (name1.contains(name2)) return true;
263         if (name2.contains(name1)) return true;
264         return false;
265     } // }}}
266

267     //{{{ getCachePath() method
268
/**
269      * Returns the full path name of this plugin's summary file.
270      * The summary file is used to store certain information which allows
271      * loading of the plugin's resources and core class to be deferred
272      * until the plugin is first used. As long as a plugin is using the
273      * jEdit 4.2 plugin API, no extra effort is required to take advantage
274      * of the summary cache.
275      */

276     public String JavaDoc getCachePath()
277     {
278         return cachePath;
279     } //}}}
280

281     // {{{ getDependencySet() method
282
/**
283      *
284      * @param className of a plugin that we wish to load
285      * @return an ordered set of JARpaths that contains the
286      * plugins that need to be (re)loaded, in the correct order.
287      */

288     public static Set JavaDoc<String JavaDoc> getDependencySet(String JavaDoc className) {
289         String JavaDoc dep;
290         Set JavaDoc<String JavaDoc> retval = new LinkedHashSet JavaDoc<String JavaDoc>();
291         int i=0;
292         while((dep = jEdit.getProperty("plugin." + className + ".depend." + i++)) != null)
293         {
294             PluginDepends pluginDepends;
295             try
296             {
297                 pluginDepends = getPluginDepends(dep);
298             }
299             catch (IllegalArgumentException JavaDoc e)
300             {
301                 Log.log(Log.ERROR, PluginJAR.class,
302                     className + " has an invalid dependency: " + dep);
303                 continue;
304             }
305
306             if(pluginDepends.what.equals("plugin"))
307             {
308                 int index2 = pluginDepends.arg.indexOf(' ');
309                 if ( index2 == -1)
310                 {
311                     Log.log(Log.ERROR, PluginJAR.class, className
312                         + " has an invalid dependency: "
313                         + dep + " (version is missing)");
314                     continue;
315                 }
316
317                 String JavaDoc pluginName = pluginDepends.arg.substring(0,index2);
318                 String JavaDoc needVersion = pluginDepends.arg.substring(index2 + 1);
319                 //todo : check version ?
320
Set JavaDoc<String JavaDoc> loadTheseFirst = getDependencySet(pluginName);
321                 loadTheseFirst.add(pluginName);
322                 loadTheseFirst.addAll(retval);
323                 retval = loadTheseFirst;
324             }
325         }
326         return retval;
327     } // }}}
328

329     //{{{ getFile() method
330
/**
331      * Returns a file pointing to the plugin JAR.
332      */

333     public File JavaDoc getFile()
334     {
335         return file;
336     } //}}}
337

338     //{{{ getClassLoader() method
339
/**
340      * Returns the plugin's class loader.
341      */

342     public JARClassLoader getClassLoader()
343     {
344         return classLoader;
345     } //}}}
346

347     //{{{ getZipFile() method
348
/**
349      * Returns the plugin's JAR file, opening it if necessary.
350      * @since jEdit 4.2pre1
351      */

352     public synchronized ZipFile JavaDoc getZipFile() throws IOException JavaDoc
353     {
354         if(zipFile == null)
355         {
356             Log.log(Log.DEBUG,this,"Opening " + path);
357             zipFile = new ZipFile JavaDoc(path);
358         }
359         return zipFile;
360     } //}}}
361

362     //{{{ getActions() method
363
/**
364      * @deprecated Call getActionSet() instead
365      */

366     public ActionSet getActions()
367     {
368         return getActionSet();
369     } //}}}
370

371     //{{{ getActionSet() method
372
/**
373      * Returns the plugin's action set for the jEdit action context
374      * {@link jEdit#getActionContext()}. These actions are loaded from
375      * the <code>actions.xml</code> file; see {@link ActionSet}.
376      *.
377      * @since jEdit 4.2pre1
378      */

379     public ActionSet getActionSet()
380     {
381         return actions;
382     } //}}}
383

384     //{{{ getBrowserActionSet() method
385
/**
386      * Returns the plugin's action set for the file system browser action
387      * context {@link
388      * org.gjt.sp.jedit.browser.VFSBrowser#getActionContext()}.
389      * These actions are loaded from
390      * the <code>browser.actions.xml</code> file; see {@link ActionSet}.
391      *.
392      * @since jEdit 4.2pre1
393      */

394     public ActionSet getBrowserActionSet()
395     {
396         return browserActions;
397     } //}}}
398

399     //{{{ checkDependencies() method
400
/**
401      * Returns true if all dependencies are satisified, false otherwise.
402      * Also if dependencies are not satisfied, the plugin is marked as
403      * "broken".
404      *
405      */

406     public boolean checkDependencies()
407     {
408         if(plugin == null)
409             return true;
410         int i = 0;
411         boolean ok = true;
412
413         String JavaDoc name = plugin.getClassName();
414
415         String JavaDoc dep;
416         while((dep = jEdit.getProperty("plugin." + name + ".depend." + i++)) != null)
417         {
418             PluginDepends pluginDepends;
419             try
420             {
421                 pluginDepends = getPluginDepends(dep);
422             }
423             catch (IllegalArgumentException JavaDoc e)
424             {
425                 Log.log(Log.ERROR,this,name + " has an invalid"
426                     + " dependency: " + dep);
427                 ok = false;
428                 continue;
429             }
430
431             if(pluginDepends.what.equals("jdk"))
432             {
433                 if(!pluginDepends.optional && StandardUtilities.compareStrings(
434                     System.getProperty("java.version"),
435                     pluginDepends.arg,false) < 0)
436                 {
437                     String JavaDoc[] args = { pluginDepends.arg,
438                         System.getProperty("java.version") };
439                     jEdit.pluginError(path,"plugin-error.dep-jdk",args);
440                     ok = false;
441                 }
442             }
443             else if(pluginDepends.what.equals("jedit"))
444             {
445                 if(pluginDepends.arg.length() != 11)
446                 {
447                     Log.log(Log.ERROR,this,"Invalid jEdit version"
448                         + " number: " + pluginDepends.arg);
449                     ok = false;
450                 }
451
452                 if(!pluginDepends.optional && StandardUtilities.compareStrings(
453                     jEdit.getBuild(),pluginDepends.arg,false) < 0)
454                 {
455                     String JavaDoc needs = MiscUtilities.buildToVersion(pluginDepends.arg);
456                     String JavaDoc[] args = { needs,
457                         jEdit.getVersion() };
458                     jEdit.pluginError(path,
459                         "plugin-error.dep-jedit",args);
460                     ok = false;
461                 }
462             }
463             else if(pluginDepends.what.equals("plugin"))
464             {
465                 int index2 = pluginDepends.arg.indexOf(' ');
466                 if(index2 == -1)
467                 {
468                     Log.log(Log.ERROR,this,name
469                         + " has an invalid dependency: "
470                         + dep + " (version is missing)");
471                     ok = false;
472                     continue;
473                 }
474
475                 String JavaDoc pluginName = pluginDepends.arg.substring(0,index2);
476                 String JavaDoc needVersion = pluginDepends.arg.substring(index2 + 1);
477                 String JavaDoc currVersion = jEdit.getProperty("plugin."
478                     + pluginName + ".version");
479
480                 EditPlugin editPlugin = jEdit.getPlugin(pluginName, false);
481                 if(editPlugin == null)
482                 {
483                     if(!pluginDepends.optional)
484                     {
485                         String JavaDoc[] args = { needVersion,
486                             pluginName };
487                         jEdit.pluginError(path,
488                             "plugin-error.dep-plugin.no-version",
489                             args);
490                         ok = false;
491                     }
492                 }
493                 else if(StandardUtilities.compareStrings(
494                     currVersion,needVersion,false) < 0)
495                 {
496                     if(!pluginDepends.optional)
497                     {
498                         String JavaDoc[] args = { needVersion,
499                             pluginName, currVersion };
500                         jEdit.pluginError(path, "plugin-error.dep-plugin",args);
501                         ok = false;
502                     }
503                 }
504                 else if(editPlugin instanceof EditPlugin.Broken)
505                 {
506                     if(!pluginDepends.optional)
507                     {
508                         String JavaDoc[] args = { pluginName };
509                         jEdit.pluginError(path, "plugin-error.dep-plugin.broken",args);
510                         ok = false;
511                     }
512                 }
513                 else
514                 {
515                     PluginJAR jar = editPlugin.getPluginJAR();
516                     if (pluginDepends.optional)
517                     {
518                         jar.theseUseMe.add(path);
519                         weUseThese.add(jar.getPath());
520                     }
521                     else
522                     {
523                         jar.theseRequireMe.add(path);
524                         weRequireThese.add(jar.getPath());
525                     }
526                 }
527             }
528             else if(pluginDepends.what.equals("class"))
529             {
530                 if(!pluginDepends.optional)
531                 {
532                     try
533                     {
534                         classLoader.loadClass(pluginDepends.arg,false);
535                     }
536                     catch(Exception JavaDoc e)
537                     {
538                         String JavaDoc[] args = { pluginDepends.arg };
539                         jEdit.pluginError(path, "plugin-error.dep-class",args);
540                         ok = false;
541                     }
542                 }
543             }
544             else
545             {
546                 Log.log(Log.ERROR,this,name + " has unknown"
547                     + " dependency: " + dep);
548                 ok = false;
549             }
550         }
551
552         // each JAR file listed in the plugin's jars property
553
// needs to know that we need them
554
String JavaDoc jars = jEdit.getProperty("plugin."
555             + plugin.getClassName() + ".jars");
556         if(jars != null)
557         {
558             String JavaDoc dir = MiscUtilities.getParentOfPath(path);
559
560             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(jars);
561             while(st.hasMoreTokens())
562             {
563                 String JavaDoc jarPath = MiscUtilities.constructPath(
564                     dir,st.nextToken());
565                 PluginJAR jar = jEdit.getPluginJAR(jarPath);
566                 if(jar == null)
567                 {
568                     String JavaDoc[] args = { jarPath };
569                     jEdit.pluginError(path, "plugin-error.missing-jar",args);
570                     ok = false;
571                 }
572                 else
573                 {
574                     weRequireThese.add(jarPath);
575                     jar.theseRequireMe.add(path);
576                 }
577             }
578         }
579
580         if(!ok)
581             breakPlugin();
582
583         return ok;
584     } //}}}
585

586     private static PluginDepends getPluginDepends(String JavaDoc dep) throws IllegalArgumentException JavaDoc
587     {
588         boolean optional;
589         if(dep.startsWith("optional "))
590         {
591             optional = true;
592             dep = dep.substring("optional ".length());
593         }
594         else
595         {
596             optional = false;
597         }
598
599         int index = dep.indexOf(' ');
600         if(index == -1)
601             throw new IllegalArgumentException JavaDoc("wrong dependency");
602
603         String JavaDoc what = dep.substring(0,index);
604         String JavaDoc arg = dep.substring(index + 1);
605         PluginDepends depends = new PluginDepends();
606         depends.what = what;
607         depends.arg = arg;
608         depends.optional = optional;
609         return depends;
610     }
611     private static class PluginDepends
612     {
613         String JavaDoc what;
614         String JavaDoc arg;
615         boolean optional;
616     }
617
618     // {{{ transitiveClosure()
619
/**
620      * If plugin A is needed by B, and B is needed by C, we want to
621      * tell the user that A is needed by B and C when they try to
622      * unload A.
623      *
624      * @param dependents a set of plugins which we wish to disable
625      * @param listModel a set of plugins which will be affected, and will need
626      * to be disabled also.
627      */

628     public static void transitiveClosure(String JavaDoc[] dependents, List JavaDoc<String JavaDoc> listModel)
629     {
630         for(int i = 0; i < dependents.length; i++)
631         {
632             String JavaDoc jarPath = dependents[i];
633             if(!listModel.contains(jarPath))
634             {
635                 listModel.add(jarPath);
636                 PluginJAR jar = jEdit.getPluginJAR(
637                     jarPath);
638                 transitiveClosure(jar.getDependentPlugins(),
639                     listModel);
640             }
641         }
642     } //}}}
643

644       
645     
646     //{{{ getDependentPlugins() method
647
public String JavaDoc[] getDependentPlugins()
648       {
649           return theseRequireMe.toArray(new String JavaDoc[theseRequireMe.size()]);
650       } //}}}
651

652     //{{{ getPlugin() method
653
/**
654      * Returns the plugin core class for this JAR file. Note that if the
655      * plugin has not been activated, this will return an instance of
656      * {@link EditPlugin.Deferred}. If you need the actual plugin core
657      * class instance, call {@link #activatePlugin()} first.
658      * If the plugin is not yet loaded, returns null
659      *
660      * @since jEdit 4.2pre1
661      */

662     public EditPlugin getPlugin()
663     {
664         return plugin;
665     } //}}}
666

667     //{{{ activatePlugin() method
668
/**
669      * Loads the plugin core class. Does nothing if the plugin core class
670      * has already been loaded. This method might be called on startup,
671      * depending on what properties are set. See {@link EditPlugin#start()}.
672      * This method is thread-safe.
673      *
674      * @since jEdit 4.2pre1
675      */

676     public void activatePlugin()
677     {
678         synchronized(this)
679         {
680             if(activated)
681             {
682                 // recursive call
683
return;
684             }
685
686             activated = true;
687         }
688
689         if(!(plugin instanceof EditPlugin.Deferred))
690             return;
691
692         String JavaDoc className = plugin.getClassName();
693
694         try
695         {
696             Class JavaDoc clazz = classLoader.loadClass(className,false);
697             int modifiers = clazz.getModifiers();
698             if(Modifier.isInterface(modifiers)
699                 || Modifier.isAbstract(modifiers)
700                 || !EditPlugin.class.isAssignableFrom(clazz))
701             {
702                 Log.log(Log.ERROR,this,"Plugin has properties but does not extend EditPlugin: "
703                     + className);
704                 breakPlugin();
705                 return;
706             }
707
708             plugin = (EditPlugin)clazz.newInstance();
709             String JavaDoc settingsDirectory = jEdit.getSettingsDirectory();
710             if (settingsDirectory != null)
711             {
712                 File JavaDoc file = new File JavaDoc(settingsDirectory, "plugins");
713                 plugin.pluginHome = new File JavaDoc(file, className).getPath();
714             }
715             plugin.jar = this;
716         }
717         catch(Throwable JavaDoc t)
718         {
719             breakPlugin();
720
721             Log.log(Log.ERROR,this,"Error while starting plugin " + className);
722             Log.log(Log.ERROR,this,t);
723             String JavaDoc[] args = { t.toString() };
724             jEdit.pluginError(path,"plugin-error.start-error",args);
725
726             return;
727         }
728
729         if(jEdit.isMainThread()
730             || SwingUtilities.isEventDispatchThread())
731         {
732             startPlugin();
733         }
734         else
735         {
736             // for thread safety
737
startPluginLater();
738         }
739
740         PropertiesBean.clearPropertyCache();
741         EditBus.send(new PluginUpdate(this,PluginUpdate.ACTIVATED,false));
742     } //}}}
743

744     //{{{ activateIfNecessary() method
745
/**
746      * Should be called after a new plugin is installed.
747      * @since jEdit 4.2pre2
748      */

749     public void activatePluginIfNecessary()
750     {
751         String JavaDoc filename = MiscUtilities.getFileName(getPath());
752         jEdit.setBooleanProperty("plugin-blacklist." + filename, false);
753 // jEdit.setBooleanProperty("plugin-blacklist."+MiscUtilities.getFileName(getPath()),false);
754
if(!(plugin instanceof EditPlugin.Deferred && plugin != null))
755             return;
756
757         String JavaDoc className = plugin.getClassName();
758
759         // default for plugins that don't specify this property (ie,
760
// 4.1-style plugins) is to load them on startup
761
String JavaDoc activate = jEdit.getProperty("plugin."
762             + className + ".activate");
763
764         if(activate == null)
765         {
766             // 4.1 plugin
767
if(!jEdit.isMainThread())
768             {
769                 breakPlugin();
770
771                 jEdit.pluginError(path,"plugin-error.not-42",null);
772             }
773             else
774                 activatePlugin();
775         }
776         else
777         {
778             // 4.2 plugin
779

780             // if at least one property listed here is true,
781
// load the plugin
782
boolean load = false;
783
784             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(activate);
785             while(st.hasMoreTokens())
786             {
787                 String JavaDoc prop = st.nextToken();
788                 boolean value = jEdit.getBooleanProperty(prop);
789                 if(value)
790                 {
791                     Log.log(Log.DEBUG,this,"Activating "
792                         + className + " because of " + prop);
793                     load = true;
794                     break;
795                 }
796             }
797
798             if(load)
799                 activatePlugin();
800         }
801     } //}}}
802

803     //{{{ deactivatePlugin() method
804
/**
805      * Unloads the plugin core class. Does nothing if the plugin core class
806      * has not been loaded.
807      * This method can only be called from the AWT event dispatch thread!
808      * @see EditPlugin#stop()
809      *
810      * @since jEdit 4.2pre3
811      */

812     public void deactivatePlugin(boolean exit)
813     {
814         if(!activated)
815             return;
816
817         if(!exit)
818         {
819             // buffers retain a reference to the fold handler in
820
// question... and the easiest way to handle fold
821
// handler unloading is this...
822
Buffer buffer = jEdit.getFirstBuffer();
823             while(buffer != null)
824             {
825                 if(buffer.getFoldHandler() != null
826                     && buffer.getFoldHandler().getClass()
827                     .getClassLoader() == classLoader)
828                 {
829                     buffer.setFoldHandler(
830                         new DummyFoldHandler());
831                 }
832                 buffer = buffer.getNext();
833             }
834         }
835
836         if(plugin != null && !(plugin instanceof EditPlugin.Broken))
837         {
838             if(plugin instanceof EBPlugin)
839                 EditBus.removeFromBus((EBPlugin)plugin);
840
841             try
842             {
843                 plugin.stop();
844             }
845             catch(Throwable JavaDoc t)
846             {
847                 Log.log(Log.ERROR,this,"Error while "
848                     + "stopping plugin:");
849                 Log.log(Log.ERROR,this,t);
850             }
851
852             plugin = new EditPlugin.Deferred(this,
853                 plugin.getClassName());
854
855             EditBus.send(new PluginUpdate(this,
856                 PluginUpdate.DEACTIVATED,exit));
857
858             if(!exit)
859             {
860                 // see if this is a 4.1-style plugin
861
String JavaDoc activate = jEdit.getProperty("plugin."
862                     + plugin.getClassName() + ".activate");
863
864                 if(activate == null)
865                 {
866                     breakPlugin();
867                     jEdit.pluginError(path,"plugin-error.not-42",null);
868                 }
869             }
870         }
871
872         activated = false;
873     } //}}}
874

875     //{{{ getDockablesURI() method
876
/**
877      * Returns the location of the plugin's
878      * <code>dockables.xml</code> file.
879      * @since jEdit 4.2pre1
880      */

881     public URL JavaDoc getDockablesURI()
882     {
883         return dockablesURI;
884     } //}}}
885

886     //{{{ getServicesURI() method
887
/**
888      * Returns the location of the plugin's
889      * <code>services.xml</code> file.
890      * @since jEdit 4.2pre1
891      */

892     public URL JavaDoc getServicesURI()
893     {
894         return servicesURI;
895     } //}}}
896

897     //{{{ toString() method
898
public String JavaDoc toString()
899     {
900         if(plugin == null)
901             return path;
902         else
903             return path + ",class=" + plugin.getClassName();
904     } //}}}
905

906     //{{{ Package-private members
907

908     //{{{ Static methods
909

910     //{{{ getPluginCache() method
911
static PluginCacheEntry getPluginCache(PluginJAR plugin)
912     {
913         String JavaDoc jarCachePath = plugin.getCachePath();
914         if(jarCachePath == null)
915             return null;
916
917         DataInputStream JavaDoc din = null;
918         try
919         {
920             PluginCacheEntry cache = new PluginCacheEntry();
921             cache.plugin = plugin;
922             cache.modTime = plugin.getFile().lastModified();
923             din = new DataInputStream JavaDoc(
924                 new BufferedInputStream JavaDoc(
925                 new FileInputStream JavaDoc(jarCachePath)));
926             if(cache.read(din))
927                 return cache;
928             else
929             {
930                 // returns false with outdated cache
931
return null;
932             }
933         }
934         catch(FileNotFoundException JavaDoc fnf)
935         {
936             return null;
937         }
938         catch(IOException JavaDoc io)
939         {
940             Log.log(Log.ERROR,PluginJAR.class,io);
941             return null;
942         }
943         finally
944         {
945             IOUtilities.closeQuietly(din);
946         }
947     } //}}}
948

949     //{{{ setPluginCache() method
950
static void setPluginCache(PluginJAR plugin, PluginCacheEntry cache)
951     {
952         String JavaDoc jarCachePath = plugin.getCachePath();
953         if(jarCachePath == null)
954             return;
955
956         Log.log(Log.DEBUG,PluginJAR.class,"Writing " + jarCachePath);
957
958         DataOutputStream JavaDoc dout = null;
959         try
960         {
961             dout = new DataOutputStream JavaDoc(
962                 new BufferedOutputStream JavaDoc(
963                 new FileOutputStream JavaDoc(jarCachePath)));
964             cache.write(dout);
965             dout.close();
966         }
967         catch(IOException JavaDoc io)
968         {
969             Log.log(Log.ERROR,PluginJAR.class,io);
970             IOUtilities.closeQuietly(dout);
971             new File JavaDoc(jarCachePath).delete();
972         }
973     } //}}}
974

975     //}}}
976

977     //{{{ PluginJAR constructor
978
/**
979      * Creates a PluginJAR object which is not necessarily loaded, but can be later.
980      * @see {@link #load(String, boolean)}
981      */

982     public PluginJAR(File JavaDoc file)
983     {
984         this.path = file.getPath();
985         String JavaDoc jarCacheDir = jEdit.getJARCacheDirectory();
986         if(jarCacheDir != null)
987         {
988             cachePath = MiscUtilities.constructPath(
989                 jarCacheDir,file.getName() + ".summary");
990         }
991         this.file = file;
992         classLoader = new JARClassLoader(this);
993         actions = new ActionSet();
994     } //}}}
995

996     //{{{ init() method
997
void init()
998     {
999
1000
1001        PluginCacheEntry cache = getPluginCache(this);
1002        if(cache != null)
1003        {
1004            loadCache(cache);
1005            classLoader.activate();
1006        }
1007        else
1008        {
1009            try
1010            {
1011                cache = generateCache();
1012                if(cache != null)
1013                {
1014                    setPluginCache(this,cache);
1015                    classLoader.activate();
1016                }
1017            }
1018            catch(IOException JavaDoc io)
1019            {
1020                Log.log(Log.ERROR,this,"Cannot load"
1021                    + " plugin " + path);
1022                Log.log(Log.ERROR,this,io);
1023
1024                String JavaDoc[] args = { io.toString() };
1025                jEdit.pluginError(path,"plugin-error.load-error",args);
1026
1027                uninit(false);
1028            }
1029        }
1030    } //}}}
1031

1032    //{{{ uninit() method
1033
void uninit(boolean exit)
1034    {
1035        deactivatePlugin(exit);
1036
1037        if(!exit)
1038        {
1039            for (String JavaDoc path : weRequireThese)
1040            {
1041                PluginJAR jar = jEdit.getPluginJAR(path);
1042                if(jar != null)
1043                    jar.theseRequireMe.remove(this.path);
1044            }
1045
1046            for (String JavaDoc path : weUseThese)
1047            {
1048                PluginJAR jar = jEdit.getPluginJAR(path);
1049                if(jar != null)
1050                    jar.theseUseMe.remove(this.path);
1051            }
1052
1053            classLoader.deactivate();
1054            BeanShell.resetClassManager();
1055
1056            if(actions != null)
1057                jEdit.removeActionSet(actions);
1058            if(browserActions != null)
1059                VFSBrowser.getActionContext().removeActionSet(browserActions);
1060
1061            DockableWindowFactory.getInstance()
1062                .unloadDockableWindows(this);
1063            ServiceManager.unloadServices(this);
1064
1065            jEdit.removePluginProps(properties);
1066
1067            try
1068            {
1069                if(zipFile != null)
1070                {
1071                    zipFile.close();
1072                    zipFile = null;
1073                }
1074            }
1075            catch(IOException JavaDoc io)
1076            {
1077                Log.log(Log.ERROR,this,io);
1078            }
1079        }
1080    } //}}}
1081

1082    //{{{ getClasses() method
1083
String JavaDoc[] getClasses()
1084    {
1085        return classes;
1086    } //}}}
1087

1088    //}}}
1089

1090    //{{{ Private members
1091

1092    //{{{ actionsPresentButNotCoreClass() method
1093
private void actionsPresentButNotCoreClass()
1094    {
1095        Log.log(Log.WARNING,this,getPath() + " has an actions.xml but no plugin core class");
1096        actions.setLabel("MISSING PLUGIN CORE CLASS");
1097    } //}}}
1098

1099    //{{{ loadCache() method
1100
private void loadCache(PluginCacheEntry cache)
1101    {
1102        classes = cache.classes;
1103
1104        /* this should be before dockables are initialized */
1105        if(cache.cachedProperties != null)
1106        {
1107            properties = cache.cachedProperties;
1108            jEdit.addPluginProps(cache.cachedProperties);
1109        }
1110
1111        if(cache.actionsURI != null
1112            && cache.cachedActionNames != null)
1113        {
1114            actions = new ActionSet(this,
1115                cache.cachedActionNames,
1116                cache.cachedActionToggleFlags,
1117                cache.actionsURI);
1118        }
1119
1120        if(cache.browserActionsURI != null
1121            && cache.cachedBrowserActionNames != null)
1122        {
1123            browserActions = new ActionSet(this,
1124                cache.cachedBrowserActionNames,
1125                cache.cachedBrowserActionToggleFlags,
1126                cache.browserActionsURI);
1127            VFSBrowser.getActionContext().addActionSet(browserActions);
1128        }
1129
1130        if(cache.dockablesURI != null
1131            && cache.cachedDockableNames != null
1132            && cache.cachedDockableActionFlags != null)
1133        {
1134            dockablesURI = cache.dockablesURI;
1135            DockableWindowFactory.getInstance()
1136                .cacheDockableWindows(this,
1137                cache.cachedDockableNames,
1138                cache.cachedDockableActionFlags);
1139        }
1140
1141        if(actions.size() != 0)
1142            jEdit.addActionSet(actions);
1143
1144        if(cache.servicesURI != null
1145            && cache.cachedServices != null)
1146        {
1147            servicesURI = cache.servicesURI;
1148            for(int i = 0; i < cache.cachedServices.length;
1149                i++)
1150            {
1151                ServiceManager.Descriptor d
1152                    = cache.cachedServices[i];
1153                ServiceManager.registerService(d);
1154            }
1155        }
1156
1157        if(cache.pluginClass != null)
1158        {
1159            // Check if a plugin with the same name
1160
// is already loaded
1161
if(jEdit.getPlugin(cache.pluginClass) != null)
1162            {
1163                jEdit.pluginError(path, "plugin-error.already-loaded",
1164                    null);
1165                uninit(false);
1166            }
1167            else
1168            {
1169                String JavaDoc label = jEdit.getProperty(
1170                    "plugin." + cache.pluginClass
1171                    + ".name");
1172                actions.setLabel(jEdit.getProperty(
1173                    "action-set.plugin",
1174                    new String JavaDoc[] { label }));
1175                plugin = new EditPlugin.Deferred(this,
1176                    cache.pluginClass);
1177            }
1178        }
1179        else
1180        {
1181            if(actions.size() != 0)
1182                actionsPresentButNotCoreClass();
1183        }
1184    } //}}}
1185

1186    //{{{ generateCache() method
1187
private PluginCacheEntry generateCache() throws IOException JavaDoc
1188    {
1189        properties = new Properties JavaDoc();
1190
1191        List JavaDoc<String JavaDoc> classes = new LinkedList JavaDoc<String JavaDoc>();
1192
1193        ZipFile JavaDoc zipFile = getZipFile();
1194
1195        List JavaDoc<String JavaDoc> plugins = new LinkedList JavaDoc<String JavaDoc>();
1196
1197        PluginCacheEntry cache = new PluginCacheEntry();
1198        cache.modTime = file.lastModified();
1199        cache.cachedProperties = new Properties JavaDoc();
1200
1201        Enumeration JavaDoc<? extends ZipEntry JavaDoc> entries = zipFile.entries();
1202        while(entries.hasMoreElements())
1203        {
1204            ZipEntry JavaDoc entry = entries.nextElement();
1205            String JavaDoc name = entry.getName();
1206            String JavaDoc lname = name.toLowerCase();
1207            if(lname.equals("actions.xml"))
1208            {
1209                cache.actionsURI = classLoader.getResource(name);
1210            }
1211            else if(lname.equals("browser.actions.xml"))
1212            {
1213                cache.browserActionsURI = classLoader.getResource(name);
1214            }
1215            else if(lname.equals("dockables.xml"))
1216            {
1217                dockablesURI = classLoader.getResource(name);
1218                cache.dockablesURI = dockablesURI;
1219            }
1220            else if(lname.equals("services.xml"))
1221            {
1222                servicesURI = classLoader.getResource(name);
1223                cache.servicesURI = servicesURI;
1224            }
1225            else if(lname.endsWith(".props"))
1226            {
1227                InputStream JavaDoc in = classLoader.getResourceAsStream(name);
1228                properties.load(in);
1229                in.close();
1230            }
1231            else if(name.endsWith(".class"))
1232            {
1233                String JavaDoc className = MiscUtilities
1234                    .fileToClass(name);
1235                if(className.endsWith("Plugin"))
1236                {
1237                    plugins.add(className);
1238                }
1239                classes.add(className);
1240            }
1241        }
1242
1243        cache.cachedProperties = properties;
1244        jEdit.addPluginProps(properties);
1245
1246        this.classes = cache.classes =
1247            classes.toArray(
1248            new String JavaDoc[classes.size()]);
1249
1250        String JavaDoc label = null;
1251
1252        for (String JavaDoc className : plugins)
1253        {
1254            String JavaDoc _label = jEdit.getProperty("plugin."
1255                + className + ".name");
1256            String JavaDoc version = jEdit.getProperty("plugin."
1257                + className + ".version");
1258            if(_label == null || version == null)
1259            {
1260                Log.log(Log.WARNING,this,"Ignoring: "
1261                    + className);
1262            }
1263            else
1264            {
1265                cache.pluginClass = className;
1266
1267                // Check if a plugin with the same name
1268
// is already loaded
1269
if(jEdit.getPlugin(className) != null)
1270                {
1271                    jEdit.pluginError(path, "plugin-error.already-loaded",
1272                        null);
1273                    return null;
1274                }
1275                plugin = new EditPlugin.Deferred(this,
1276                     className);
1277                label = _label;
1278
1279                break;
1280            }
1281        }
1282
1283        if(cache.actionsURI != null)
1284        {
1285            actions = new ActionSet(this,null,null,
1286                cache.actionsURI);
1287            actions.load();
1288            cache.cachedActionNames =
1289                actions.getCacheableActionNames();
1290            cache.cachedActionToggleFlags =
1291                new boolean[cache.cachedActionNames.length];
1292            for(int i = 0; i < cache.cachedActionNames.length; i++)
1293            {
1294                 cache.cachedActionToggleFlags[i] =
1295                     jEdit.getBooleanProperty(
1296                         cache.cachedActionNames[i] + ".toggle");
1297            }
1298        }
1299
1300        if(cache.browserActionsURI != null)
1301        {
1302            browserActions =
1303                new ActionSet(this,null,null, cache.browserActionsURI);
1304            browserActions.load();
1305            VFSBrowser.getActionContext().addActionSet(browserActions);
1306            cache.cachedBrowserActionNames =
1307                browserActions.getCacheableActionNames();
1308            cache.cachedBrowserActionToggleFlags = new boolean[
1309                cache.cachedBrowserActionNames.length];
1310            for(int i = 0;
1311                i < cache.cachedBrowserActionNames.length; i++)
1312            {
1313                 cache.cachedBrowserActionToggleFlags[i]
1314                    = jEdit.getBooleanProperty(
1315                        cache.cachedBrowserActionNames[i] + ".toggle");
1316            }
1317        }
1318
1319        if(dockablesURI != null)
1320        {
1321            DockableWindowFactory.getInstance()
1322                .loadDockableWindows(this, dockablesURI,cache);
1323        }
1324
1325        if(actions.size() != 0)
1326        {
1327            if(label != null)
1328            {
1329                actions.setLabel(jEdit.getProperty(
1330                    "action-set.plugin", new String JavaDoc[] { label }));
1331            }
1332            else
1333                actionsPresentButNotCoreClass();
1334
1335            jEdit.addActionSet(actions);
1336        }
1337
1338        if(servicesURI != null)
1339        {
1340            ServiceManager.loadServices(this,servicesURI,cache);
1341        }
1342
1343        return cache;
1344    } //}}}
1345

1346    //{{{ startPlugin() method
1347
private void startPlugin()
1348    {
1349        try
1350        {
1351            plugin.start();
1352        }
1353        catch(Throwable JavaDoc t)
1354        {
1355            breakPlugin();
1356
1357            Log.log(Log.ERROR,PluginJAR.this,
1358                "Error while starting plugin " + plugin.getClassName());
1359            Log.log(Log.ERROR,PluginJAR.this,t);
1360            String JavaDoc[] args = { t.toString() };
1361            jEdit.pluginError(path, "plugin-error.start-error",args);
1362        }
1363
1364        if(plugin instanceof EBPlugin)
1365        {
1366            if(jEdit.getProperty("plugin." + plugin.getClassName()
1367                + ".activate") == null)
1368            {
1369                // old plugins expected jEdit 4.1-style
1370
// behavior, where a PropertiesChanged
1371
// was sent after plugins were started
1372
((EBComponent)plugin).handleMessage(
1373                    new org.gjt.sp.jedit.msg.PropertiesChanged(null));
1374            }
1375            EditBus.addToBus((EBPlugin)plugin);
1376        }
1377
1378        // buffers retain a reference to the fold handler in
1379
// question... and the easiest way to handle fold
1380
// handler loading is this...
1381
Buffer buffer = jEdit.getFirstBuffer();
1382        while(buffer != null)
1383        {
1384            FoldHandler handler =
1385                FoldHandler.getFoldHandler(
1386                buffer.getStringProperty("folding"));
1387            // == null before loaded
1388
if(buffer.getFoldHandler() != null
1389                && handler != null
1390                && handler != buffer.getFoldHandler())
1391            {
1392                buffer.setFoldHandler(handler);
1393            }
1394            buffer = buffer.getNext();
1395        }
1396    } //}}}
1397

1398    //{{{ startPluginLater() method
1399
private void startPluginLater()
1400    {
1401        SwingUtilities.invokeLater(new Runnable JavaDoc()
1402        {
1403            public void run()
1404            {
1405                if(!activated)
1406                    return;
1407
1408                startPlugin();
1409            }
1410        });
1411    } //}}}
1412

1413    //{{{ breakPlugin() method
1414
private void breakPlugin()
1415    {
1416        plugin = new EditPlugin.Broken(this,plugin.getClassName());
1417
1418        // remove action sets, dockables, etc so that user doesn't
1419
// see the broken plugin
1420
uninit(false);
1421        // but we want properties to hang around
1422
jEdit.addPluginProps(properties);
1423    } //}}}
1424

1425    //}}}
1426

1427    //{{{ PluginCacheEntry class
1428
/**
1429     * Used by the <code>DockableWindowManager</code> and
1430     * <code>ServiceManager</code> to handle caching.
1431     * @since jEdit 4.2pre1
1432     */

1433    public static class PluginCacheEntry
1434    {
1435        public static final int MAGIC = 0xB7A2E420;
1436
1437        //{{{ Instance variables
1438
public PluginJAR plugin;
1439        public long modTime;
1440
1441        public String JavaDoc[] classes;
1442        public URL JavaDoc actionsURI;
1443        public String JavaDoc[] cachedActionNames;
1444        public boolean[] cachedActionToggleFlags;
1445        public URL JavaDoc browserActionsURI;
1446        public String JavaDoc[] cachedBrowserActionNames;
1447        public boolean[] cachedBrowserActionToggleFlags;
1448        public URL JavaDoc dockablesURI;
1449        public String JavaDoc[] cachedDockableNames;
1450        public boolean[] cachedDockableActionFlags;
1451        public URL JavaDoc servicesURI;
1452        ServiceManager.Descriptor[] cachedServices;
1453
1454        public Properties JavaDoc cachedProperties;
1455        public String JavaDoc pluginClass;
1456        //}}}
1457

1458        /* read() and write() must be kept perfectly in sync...
1459         * its a very simple file format. doing it this way is
1460         * faster than serializing since serialization calls
1461         * reflection, etc. */

1462
1463        //{{{ read() method
1464
public boolean read(DataInputStream JavaDoc din) throws IOException JavaDoc
1465        {
1466            int cacheMagic = din.readInt();
1467            if(cacheMagic != MAGIC)
1468                return false;
1469
1470            String JavaDoc cacheBuild = readString(din);
1471            if(!cacheBuild.equals(jEdit.getBuild()))
1472                return false;
1473
1474            long cacheModTime = din.readLong();
1475            if(cacheModTime != modTime)
1476                return false;
1477
1478            actionsURI = readURI(din);
1479            cachedActionNames = readStringArray(din);
1480            cachedActionToggleFlags = readBooleanArray(din);
1481
1482            browserActionsURI = readURI(din);
1483            cachedBrowserActionNames = readStringArray(din);
1484            cachedBrowserActionToggleFlags = readBooleanArray(din);
1485
1486            dockablesURI = readURI(din);
1487            cachedDockableNames = readStringArray(din);
1488            cachedDockableActionFlags = readBooleanArray(din);
1489
1490            servicesURI = readURI(din);
1491            int len = din.readInt();
1492            if(len == 0)
1493                cachedServices = null;
1494            else
1495            {
1496                cachedServices = new ServiceManager.Descriptor[len];
1497                for(int i = 0; i < len; i++)
1498                {
1499                    ServiceManager.Descriptor d = new
1500                        ServiceManager.Descriptor(
1501                        readString(din),
1502                        readString(din),
1503                        null,
1504                        plugin);
1505                    cachedServices[i] = d;
1506                }
1507            }
1508
1509            classes = readStringArray(din);
1510
1511            cachedProperties = readMap(din);
1512
1513            pluginClass = readString(din);
1514
1515            return true;
1516        } //}}}
1517

1518        //{{{ write() method
1519
public void write(DataOutputStream JavaDoc dout) throws IOException JavaDoc
1520        {
1521            dout.writeInt(MAGIC);
1522            writeString(dout,jEdit.getBuild());
1523
1524            dout.writeLong(modTime);
1525
1526            writeString(dout,actionsURI);
1527            writeStringArray(dout,cachedActionNames);
1528            writeBooleanArray(dout,cachedActionToggleFlags);
1529
1530            writeString(dout,browserActionsURI);
1531            writeStringArray(dout,cachedBrowserActionNames);
1532            writeBooleanArray(dout,cachedBrowserActionToggleFlags);
1533
1534            writeString(dout,dockablesURI);
1535            writeStringArray(dout,cachedDockableNames);
1536            writeBooleanArray(dout,cachedDockableActionFlags);
1537
1538            writeString(dout,servicesURI);
1539            if(cachedServices == null)
1540                dout.writeInt(0);
1541            else
1542            {
1543                dout.writeInt(cachedServices.length);
1544                for(int i = 0; i < cachedServices.length; i++)
1545                {
1546                    writeString(dout,cachedServices[i].clazz);
1547                    writeString(dout,cachedServices[i].name);
1548                }
1549            }
1550
1551            writeStringArray(dout,classes);
1552
1553            writeMap(dout,cachedProperties);
1554
1555            writeString(dout,pluginClass);
1556        } //}}}
1557

1558        //{{{ Private members
1559

1560        //{{{ readString() method
1561
private static String JavaDoc readString(DataInputStream JavaDoc din)
1562            throws IOException JavaDoc
1563        {
1564            int len = din.readInt();
1565            if(len == 0)
1566                return null;
1567            char[] str = new char[len];
1568            for(int i = 0; i < len; i++)
1569                str[i] = din.readChar();
1570            return new String JavaDoc(str);
1571        } //}}}
1572

1573        //{{{ readURI() method
1574
private static URL JavaDoc readURI(DataInputStream JavaDoc din)
1575            throws IOException JavaDoc
1576        {
1577            String JavaDoc str = readString(din);
1578            if(str == null)
1579                return null;
1580            else
1581                return new URL JavaDoc(str);
1582        } //}}}
1583

1584        //{{{ readStringArray() method
1585
private static String JavaDoc[] readStringArray(DataInputStream JavaDoc din)
1586            throws IOException JavaDoc
1587        {
1588            int len = din.readInt();
1589            if(len == 0)
1590                return null;
1591            String JavaDoc[] str = new String JavaDoc[len];
1592            for(int i = 0; i < len; i++)
1593            {
1594                str[i] = readString(din);
1595            }
1596            return str;
1597        } //}}}
1598

1599        //{{{ readBooleanArray() method
1600
private static boolean[] readBooleanArray(DataInputStream JavaDoc din)
1601            throws IOException JavaDoc
1602        {
1603            int len = din.readInt();
1604            if(len == 0)
1605                return null;
1606            boolean[] bools = new boolean[len];
1607            for(int i = 0; i < len; i++)
1608            {
1609                bools[i] = din.readBoolean();
1610            }
1611            return bools;
1612        } //}}}
1613

1614        //{{{ readMap() method
1615
private static Properties JavaDoc readMap(DataInputStream JavaDoc din)
1616            throws IOException JavaDoc
1617        {
1618            Properties JavaDoc returnValue = new Properties JavaDoc();
1619            int count = din.readInt();
1620            for(int i = 0; i < count; i++)
1621            {
1622                String JavaDoc key = readString(din);
1623                String JavaDoc value = readString(din);
1624                if(value == null)
1625                    value = "";
1626                returnValue.put(key,value);
1627            }
1628            return returnValue;
1629        } //}}}
1630

1631        //{{{ writeString() method
1632
private static void writeString(DataOutputStream JavaDoc dout,
1633            Object JavaDoc obj) throws IOException JavaDoc
1634        {
1635            if(obj == null)
1636            {
1637                dout.writeInt(0);
1638            }
1639            else
1640            {
1641                String JavaDoc str = obj.toString();
1642                dout.writeInt(str.length());
1643                dout.writeChars(str);
1644            }
1645        } //}}}
1646

1647        //{{{ writeStringArray() method
1648
private static void writeStringArray(DataOutputStream JavaDoc dout,
1649            String JavaDoc[] str) throws IOException JavaDoc
1650        {
1651            if(str == null)
1652            {
1653                dout.writeInt(0);
1654            }
1655            else
1656            {
1657                dout.writeInt(str.length);
1658                for(int i = 0; i < str.length; i++)
1659                {
1660                    writeString(dout,str[i]);
1661                }
1662            }
1663        } //}}}
1664

1665        //{{{ writeBooleanArray() method
1666
private static void writeBooleanArray(DataOutputStream JavaDoc dout,
1667            boolean[] bools) throws IOException JavaDoc
1668        {
1669            if(bools == null)
1670            {
1671                dout.writeInt(0);
1672            }
1673            else
1674            {
1675                dout.writeInt(bools.length);
1676                for(int i = 0; i < bools.length; i++)
1677                {
1678                    dout.writeBoolean(bools[i]);
1679                }
1680            }
1681        } //}}}
1682

1683        //{{{ writeMap() method
1684
private static void writeMap(DataOutputStream JavaDoc dout, Map JavaDoc map)
1685            throws IOException JavaDoc
1686        {
1687            dout.writeInt(map.size());
1688            Set JavaDoc<Map.Entry JavaDoc<Object JavaDoc, Object JavaDoc>> set = map.entrySet();
1689            for (Map.Entry JavaDoc<Object JavaDoc, Object JavaDoc> entry : set)
1690            {
1691                writeString(dout,entry.getKey());
1692                writeString(dout,entry.getValue());
1693            }
1694        } //}}}
1695

1696        //}}}
1697
} //}}}
1698
}
1699
Popular Tags