PageRenderTime 63ms CodeModel.GetById 53ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre5/doc/users-guide/host-design.xml

#
XML | 473 lines | 372 code | 53 blank | 48 comment | 0 complexity | 74fa48f7499dadaf2cd652982182ded6 MD5 | raw file
  1<!-- jEdit 4.0 Plugin Guide, (C) 2001 John Gellene            -->
  2
  3<!-- jEdit buffer-local properties:                           -->
  4<!-- :indentSize=1:tabSize=2:noTabs=true:maxLineLen=72:       -->
  5
  6<!-- This file contains a discussion of the host architecture -->
  7<!-- in the jEdit Plugin API                                  -->
  8<!-- $Id: host-design.xml 4003 2002-01-31 21:09:13Z jgellene $
  9-->
 10
 11<chapter id="host-design"><title>jEdit as a Plugin Host</title>
 12
 13<para>
 14	A good way to start learning what a plugin requires is to look at what
 15  the host application does with one. We start our discussion of
 16  plugins by outlining how jEdit loads and displays them. This section
 17  only provides a broad overview of the more important components that
 18  make up jEdit; specifics of the API will be documented in
 19  subsequent chapters.
 20</para>
 21
 22<sect1 id="host-design-load"><title>
 23<indexterm>
 24	<primary>Plugin API</primary>
 25	<secondary>loading at startup</secondary>
 26</indexterm>
 27Loading Plugins</title>
 28
 29<para>
 30  As part of its startup routine, jEdit's <function>main</function>
 31  method calls various methods to load and initialize plugins.
 32  This occurs after the application has done the following:
 33</para>
 34
 35  <itemizedlist>
 36    <listitem><para>
 37      parsed command line options;
 38    </para></listitem>
 39    <listitem><para>
 40      started the edit server (unless instructed not to
 41      by a command line option) and;
 42    </para></listitem>
 43    <listitem><para>
 44      loaded application properties, any user-supplied properties, and the
 45      application's set of actions that will be available from jEdit's menu
 46      bar (as well as the toolbar and keyboard shortcuts);
 47    </para></listitem>
 48  </itemizedlist>
 49
 50<para>
 51  Plugin loading occurs before jEdit creates any windows or loads any files
 52  for editing. It also occurs before jEdit runs any startup scripts.
 53</para>
 54
 55<sect2 id="host-design-loader"><title>
 56<indexterm>
 57	<primary>JAR class loader</primary>
 58</indexterm>
 59The JARClassLoader</title>
 60
 61<para>
 62  Plugins are loaded from files with the <filename>.jar</filename>
 63  filename extension located in the <filename>jars</filename>
 64  subdirectories of the jEdit installation and user settings directories
 65  (see <xref linkend="settings-directory" />).
 66</para>
 67
 68<para>
 69  For each JAR archive file it finds, jEdit creates an instance of the
 70  <classname>JARClassLoader</classname> class. This is a jEdit-specific
 71  class
 72  that implements the Java platform's abstract class
 73  <classname>ClassLoader</classname>. The constructor for the
 74  <classname>JARClassLoader</classname> object does the following:
 75    <itemizedlist>
 76      <listitem><para>
 77        Adds any class file with a name ending with
 78        <filename>Plugin.class</filename> to an internal collection of
 79        plugin class names maintained by the
 80        <classname>JARClassLoader</classname>. See <xref
 81        linkend="plugin-classes" />.
 82      </para></listitem>
 83      <listitem><para>
 84        Loads any properties defined in files ending with
 85        the extension <filename>.props</filename> that are contained
 86        in the archive. See <xref linkend="api-resource-properties" />.
 87      </para></listitem>
 88      <listitem><para>
 89        Loads as stored BeanShell code the routine for creating a
 90        docking or floating window containing the visible components of
 91        each plugin contained in the archive. This code is contained in an
 92        XML file named <filename>dockables.xml</filename> and located at the top
 93        level of the archive file. <!-- See <xref linkend="api-resources-activation" />. -->
 94        This file is required if the plugin provides for a docking or
 95        floating window.
 96      </para></listitem>
 97      <listitem><para>
 98        Loads any data on the plugin's actions from a file named
 99        <filename>actions.xml</filename> (if it exists) located at the
100        top level of the archive file. See <xref
101        linkend="api-resources-action" />.
102      </para></listitem>
103      <listitem><para>
104       Adds to a collection maintained by jEdit a new object of
105       type <classname>EditPlugin.JAR</classname>. This is a data structure
106       holding the name of the jar archive file, a reference to the
107       <classname>JARClassLoader</classname> and a collection,
108       initially empty, of plugins found in the archive file.
109      </para></listitem>
110    </itemizedlist>
111</para>
112
113<para>
114  Once all plugin JAR files have been examined for the above resources,
115  jEdit initializes all class files whose names end in
116  <filename>Plugin.class</filename>, as identified in the first pass
117  through the JAR archive.  We will call these classes
118<indexterm>
119	<primary>Plugin API</primary>
120	<secondary>plugin core class</secondary>
121</indexterm>
122<firstterm>plugin core classes</firstterm>. Plugin core classes provide
123  the principal point of contact between jEdit and the plugin, and
124  must extend jEdit's abstract <classname>EditPlugin</classname> class.
125  Use of a class name ending in <classname>Plugin</classname> is also
126  required.
127</para>
128
129<para>
130<indexterm>
131	<primary>Plugins</primary>
132	<secondary>dependencies</secondary>
133</indexterm>
134  For each plugin core class, the loader first checks the plugin's
135  properties to see if it is subject to any dependencies. For example, a
136  plugin may require that the version of the Java runtime environment or
137  of jEdit itself be equal to or above some threshold version. A plugin
138  can also require the presence of another plugin. If any dependency is
139  not satisified, the loader marks the plugin as <quote>broken</quote> and
140  logs an error message.
141</para>
142
143<para>
144  If all dependencies are satisfied, a new instance
145  of the plugin core class is created and added to the collection
146  maintained by the appropriate <classname>EditPlugin.JAR</classname>
147  object. By
148  accessing that object, jEdit can keep track of plugins it has
149  successfully loaded, and call methods or perform routines on them.
150</para>
151
152<sidebar><title>
153<indexterm>
154	<primary>Plugin API</primary>
155	<secondary>using class libraries</secondary>
156</indexterm>
157Additional class libraries for plugins</title>
158
159<para>
160  JAR files with no plugin core classes are also loaded by jEdit; no special
161  initialization is performed on them, and the classes they contain are
162  made available to other plugins.  For example, many plugins that rely on
163  third-party class libraries ship them as separate JAR archives.
164</para>
165
166<para>
167  A plugin that bundles extra JAR archives must define a property that
168  lists these JAR files in order for the plugin manager to be able to
169  remove the plugin completely. See <xref
170  linkend="api-resource-properties" />.
171</para>
172
173</sidebar>
174
175</sect2>
176
177<sect2 id="host-design-plugin-start"><title>Starting the Plugin</title>
178
179<para>
180  After creating and storing the plugin core object, jEdit calls the
181  <function>start()</function> method of the plugin core class.
182  Because this method is defined as an empty <quote>no-op</quote> in the
183  <classname>EditPlugin</classname> abstract class, a plugin need not
184  provide its own implementation if the plugin does not require its
185  own initialization. If the only initialization required is to register
186  the plugin core object with the EditBus, it is better to do that
187  simply by deriving the class from <classname>EBPlugin</classname>
188  instead of <classname>EditPlugin</classname>.
189</para>
190
191<!--
192<para>
193  The
194  <function>start()</function> method can perform initialization of the
195  object's data
196  members. It can also register itself with
197  jEdit's <firstterm>EditBus</firstterm> object, which manages messaging
198  between plugins and the host application. We will discuss the
199  EditBus in more detail in <xref linkend="host-display-manager" />
200  and <xref linkend="api-message" />.
201</para>
202-->
203
204<para>
205  At this point, we can identify the following practical requirements
206  for a plugin:
207</para>
208
209<itemizedlist>
210  <listitem><para>
211    it must be packaged as a JAR archive;
212  </para></listitem>
213  <listitem><para>
214    the JAR archive must contain an XML data file named
215    <filename>dockables.xml</filename> containing code on how the plugin will
216    create a docking or floating window when it is activated;
217  </para></listitem>
218  <listitem><para>
219    if the plugin requires initialization when jEdit starts up,
220    the JAR archive must contain at least one plugin core
221    class whose name ends in <filename>Plugin</filename> and which
222    extends the <classname>EditPlugin</classname> abstract class;
223  </para></listitem>
224  <listitem><para>
225    the JAR archive may contain data concerning actions for display
226    in jEdit's menu bar and elsewhere in a file entitled
227    <filename>actions.xml</filename>; and
228  </para></listitem>
229  <listitem><para>
230    the archive must contain
231    at least one properties file having a <filename>.props</filename>
232    extension. Certain properties giving information
233    about the plugin must be defined.
234  </para></listitem>
235</itemizedlist>
236
237<para>
238  We will provide more detail on these requirements later.
239</para>
240
241</sect2>
242
243</sect1>
244
245<sect1 id="host-design-display"><title>The User Interface of a Plugin</title>
246
247<para>
248  <!-- To display a user interface, plugins can either directly extend Java's
249  <classname>JFrame</classname>, <classname>JDialog</classname>, or
250  <classname>JWindow</classname> classes, or use jEdit's dockable window
251  API. Plugin windows are typically defined in classes that are
252  part of the plugin package but separate from the plugin core
253  class. -->
254  To display a user interface, plugins provide a top-level component
255  derived (directly or indirectly) from the Swing
256  <classname>JComponent</classname> class.  This component will be
257  embedded in a docking of floating window created by the Plugin API. It
258  is typically defined in a class that is part of the plugin package but
259  separate from the plugin core class (if one exists).
260</para>
261
262<sect2 id="host-display-view"><title>
263<indexterm>
264	<primary>View</primary>
265	<secondary>use in Plugin API</secondary>
266</indexterm>
267<indexterm>
268	<primary>Plugin API</primary>
269	<secondary>use of View object</secondary>
270</indexterm>
271The Role of the View Object</title>
272
273<para>
274  A <classname>View</classname> is jEdit's top-level frame window that
275  contains one or more (if the view is split) text areas, a menu bar,
276  a toolbar and other window
277  decorations, as well as docked plugin components. The
278  <classname>View</classname> class
279  performs two important operations that deal
280  with plugins: creating plugin menu items, and managing dockable
281  windows.
282</para>
283
284<para>
285<indexterm>
286	<primary>Plugin API</primary>
287	<secondary>menu creation</secondary>
288</indexterm>
289
290  When a view is being created, its initialization routine
291  iterates through the collection of loaded plugins and calls
292  the <function>createMenuItems()</function> method of
293  each plugin core class. In the parent class,
294  <classname>EditPlugin</classname>, this method is an empty
295  <quote>no-op</quote>.  In order to add items to jEdit's menu bar
296  under the <guilabel>Plugins</guilabel> heading, the plugin core class
297  supplies its own version of <function>createMenuItems()</function>.
298  As we will explain in the next chapter,
299  the typical plugin, instead of creating Java
300  <classname>JMenu</classname> and <classname>JMenuItem</classname>
301  objects directly, relies on a method in a utility class to
302  create menu entries.
303</para>
304
305<para>
306  The <classname>View</classname> also creates and initializes a
307  <classname>DockableWindowManager</classname> object. This object is
308  responsible for creating, closing and managing dockable windows.
309</para>
310
311<para>
312  The <classname>View</classname> class contains a number of methods
313  that can be called from plugins; see <xref linkend="class-view" /> for
314  details.
315</para>
316
317</sect2>
318
319<sect2 id="host-display-manager">
320<title>
321<indexterm>
322	<primary>Plugin API</primary>
323	<secondary>DockableWindowManager class</secondary>
324</indexterm>
325<indexterm>
326	<primary>DockableWindowManager</primary>
327	<secondary>use in Plugin API</secondary>
328</indexterm>
329The DockableWindowManager and the EditBus</title>
330
331<para>
332  The <classname>DockableWindowManager</classname> keeps track of docked
333  and floating windows. When the <classname>View</classname> object
334  initializes its <classname>DockableWindowManager</classname>, the
335  manager iterates through the list of registered dockable windows and
336  examines options supplied by the user in the <guilabel>Global
337  Options</guilabel> dialog box. It displays any windows that the user
338  designated as <quote>auto open</quote>. The
339  <classname>DockableWindowManager</classname> object is also invoked
340  whenever the user requests a dockable window is opened or closed.
341</para>
342
343<para>
344  The <classname>DockableWindowManager</classname> creates and displays
345  plugin windows by routing messages through the application's
346  <classname>EditBus</classname> object that we mentioned earlier. The
347  EditBus mantains a list of objects that have requested to receive
348  messages. When a message is sent using this class, all registered
349  components receive it in turn.
350</para>
351
352<para>
353  Plugins register with the EditBus to receive messages reflecting
354  changes in the application's state, including changes in buffers,
355  views and editing pane, changes in the set of propoerties maintained
356  by the application, and the closing of the application.  A full list
357  of message classes used by the EditBus are summarized beginning with
358  <xref linkend="class-EBMessage"/>.
359</para>
360
361<para>
362<indexterm>
363	<primary>Plugin API</primary>
364	<secondary>EBComponent class</secondary>
365</indexterm>
366  Classes for objects that subscribe to the EditBus must implement the
367  <classname>EBComponent</classname> interface, which defines the single
368  method <function>handleMessage()</function>. A
369  <classname>View</classname>, for example, can receive and handle EditBus
370  messages because it also implements <classname>EBComponent</classname>.
371</para>
372
373<para>
374  Any class in a plugin can receive messages by providing an
375  implementation of the <classname>EBComponent</classname>
376  interface.  A <quote>plugin core class</quote> that implements the
377  <classname>EBPlugin</classname> interface (and whose name ends with
378  <quote>Plugin</quote> for identification purposes) will automtically be
379  added to the EditBus during jEdit's startup routine.  Any other
380  class - for example, a docking window component that needs to receive
381  notification of buffer changes - must perform its own registration by calling
382  <function>EditBus.addToBus(this)</function> during its initialization.
383  If this class if derived from <classname>JComponent</classname>, a
384  convenient place to register would be in an implementation of the
385  <classname>JComponent</classname> method
386  <function>addNotify()</function>.
387</para>
388
389</sect2>
390
391<sect2 id="host-display-message">
392<title>
393<indexterm>
394	<primary>Plugin API</primary>
395	<secondary>creating dockable windows</secondary>
396</indexterm>
397Dockable Window Creation</title>
398
399<para>
400  To activate a plugin window, the
401  <classname>DockableWindowManager</classname> finds and executes the
402  BeanShell code extracted from the plugin's
403  <filename>dockables.xml</filename> file during application startup. This
404  code will typically consist of a call to the constructor of the docking
405  window component that passes two parameters: the
406  <classname>View</classname> associated with the docking window
407  component, and a<classname>String</classname> representing the compnent's
408  docking or floating position. The return value of the constructor call
409  is stored
410</para>
411
412<para>
413  As a final step in plugin activation, the manager creates another window
414  object that will contain the object returned by this constructor call.
415  This object
416  implements the <classname>DockableWindowContainer</classname> interface;
417  depending on the settings for the plugin selected by the user, it will
418  either be a tabbed window pane in one of the docked windows attached
419  to the <classname>View</classname> object, or a separate, floating frame
420  window. Plugins need not be aware of the implementation details of the
421  container.
422</para>
423
424<para>
425  Eventually the <classname>DockableWindowManager</classname> destroys
426  the plugin window,
427  whether docking or floating, in response to user action or as
428  part of the destruction of the corresponding <classname>View</classname>
429  object.
430</para>
431
432<para>
433  The <classname>DockableWindowManager</classname> and
434  <classname>EditBus</classname> classes contain a number of methods
435  that can be called from plugins; see <xref linkend="class-view" /> for
436  details.
437</para>
438
439<!--
440<para>
441  This summary shows that a plugin wishing to use the dockable window
442  API has the following additional requirements:
443</para>
444
445<itemizedlist>
446  <listitem><para>
447    the plugin class must extend <classname>EBPlugin</classname>
448    instead of <classname>EditPlugin</classname> in order to
449    receive the <classname>CreateDockableWindow</classname> message;
450  </para></listitem>
451  <listitem><para>
452    it must register its dockable windows in its
453    <function>start()</function> method; and
454  </para></listitem>
455  <listitem><para>
456    it must create and arrange any dockable windows it provides
457    in response to the appropriate
458    <classname>CreateDockableWindow</classname> message;
459  </para></listitem>
460</itemizedlist>
461-->
462
463<para>
464  With this broad outline of how jEdit behaves as a plugin host in the
465  background, we will next review the programming elements that make up
466  a plugin.
467</para>
468
469</sect2>
470
471</sect1>
472
473</chapter>