source: trunk/doc/src/docbook/developer/extensions.xml @ 5816

Last change on this file since 5816 was 5816, checked in by Nicklas Nordborg, 10 years ago

References #1590: Documentation cleanup

3 chapters in the Developer documentation should now be up-to-date:

  • Overview
  • Plug-in developer
  • Extensions developer
  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Id
File size: 67.3 KB
Line 
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE chapter PUBLIC
3    "-//Dawid Weiss//DTD DocBook V3.1-Based Extension for XML and graphics inclusion//EN"
4    "../../../../lib/docbook/preprocess/dweiss-docbook-extensions.dtd">
5<!--
6  $Id: extensions.xml 5816 2011-10-20 12:36:44Z nicklas $
7 
8  Copyright (C) 2008
9 
10  This file is part of BASE - BioArray Software Environment.
11  Available at http://base.thep.lu.se/
12 
13  BASE is free software; you can redistribute it and/or
14  modify it under the terms of the GNU General Public License
15  as published by the Free Software Foundation; either version 3
16  of the License, or (at your option) any later version.
17 
18  BASE is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  GNU General Public License for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with BASE. If not, see <http://www.gnu.org/licenses/>.
25-->
26
27<chapter id="extensions_developer">
28  <?dbhtml dir="extensions" filename="index.html" ?>
29  <title>Extensions developer</title>
30
31  <sect1 id="extensions_developer.overview">
32    <?dbhtml filename="overview.html" ?>
33    <title>Overview</title>
34    <para>
35      The BASE application includes an extensions mechanism that makes it possible
36      to dynamically add functions to the GUI without having to edit the JSP code.
37      It is, for example, possible to add menu items in the menu and toolbar buttons
38      in selected toolbars.
39    </para>
40   
41    <para>
42      Go to the
43        <menuchoice>
44          <guimenu>Administrate</guimenu>
45          <guimenuitem>Plug-ins &amp; extensions</guimenuitem>
46          <guimenuitem>Overview</guimenuitem>
47        </menuchoice>
48      menu to display a list of possible extension points and all installed
49      extensions. From this page, if you are logged in with enough permissions,
50      it is also possible to configure the extensions system, enable/disable
51      extensions, etc. Read more about this in <xref linkend="plugins" />.
52    </para>
53
54    <para>
55      Extensions can come in two forms, either as an XML file in the
56      <emphasis>BASE Extensions XML</emphasis> format or as a JAR file.
57      A JAR file is required when the extension needs to execute custom-made
58      code or use custom resources such as icons, css stylesheets, or
59      JSP files.
60    </para>
61
62    <itemizedlist>
63      <title>More reading</title>
64      <listitem>
65        <para>
66        <xref linkend="plugins" />.
67        </para>
68      </listitem>
69     
70      <listitem>
71        <para>
72        <xref linkend="core_api.extensions" />.
73        </para>
74      </listitem>
75    </itemizedlist>
76
77    <sect2 id="extensions_developer.examplecode">
78      <title>Download code examples</title>
79
80      <para>
81        The code examples in this chapter can be downloaded from the
82        BASE plug-ins site:
83        <ulink url="http://baseplugins.thep.lu.se/wiki/net.sf.basedb.examplecode"
84        >http://baseplugins.thep.lu.se/wiki/net.sf.basedb.examplecode</ulink>
85      </para>
86    </sect2>
87
88    <sect2 id="extensions_developer.terminology">
89      <title>Terminology</title>
90     
91      <variablelist>
92      <varlistentry>
93        <term>Extension point</term>
94        <listitem>
95          <para>
96          An extensions point is a place in the BASE core or web client interface
97          where it is possible to extend the functionality with custom extensions. An
98          extension point has an ID which must be unique among all existing
99          extension points. Extension points registered by the BASE web client all
100          starts with <code>net.sf.basedb.clients.web</code> prefix. The
101          extension point also defines an
102          <interfacename docapi="net.sf.basedb.util.extensions">Action</interfacename>
103          subclass that all extensions must implement.
104          </para>
105        </listitem>
106      </varlistentry>
107     
108      <varlistentry>
109        <term>Extension</term>
110        <listitem>
111          <para>
112          An extensions is a custom addition to the BASE web client
113          interface or core API. This can mean a new menu item in the menu or a
114          new button in a toolbar. An extension must provide an
115          <interfacename docapi="net.sf.basedb.util.extensions">ActionFactory</interfacename>
116          that knows how to create actions that fits the requirements
117          from the extension point the extension is extending.
118          </para>
119        </listitem>
120      </varlistentry>
121     
122      <varlistentry>
123        <term>Action</term>
124        <listitem>
125          <para>
126          An <interfacename docapi="net.sf.basedb.util.extensions">Action</interfacename>
127          is an interface definition which provides an extension point enough
128          information to make it possible to render the action as HTML.
129          An action typically has methods such as, <code>getTitle()</code>,
130          <code>getIcon()</code> and <code>getOnClick()</code>.
131          </para>
132        </listitem>
133      </varlistentry>
134     
135      <varlistentry>
136        <term>Action factory</term>
137        <listitem>
138          <para>
139          An <interfacename docapi="net.sf.basedb.util.extensions">ActionFactory</interfacename>
140          is an object that knows how to create actions of some specific type, for
141          example menu item actions. Action factories are part of an
142          extension definition and can usually be configured with parameters
143          from the XML file. BASE ships with several implementations of
144          action factories for all defined extension points. Still, if your
145          extension needs a different implementation you can easily create your
146          own factory.
147          </para>
148        </listitem>
149      </varlistentry>
150     
151      <varlistentry>
152        <term>Renderer</term>
153        <listitem>
154          <para>
155          A <interfacename docapi="net.sf.basedb.util.extensions">Renderer</interfacename>
156          is an object that knows how to convert the information in an action to
157          HTML. The use of renderers are optional. Some extension points use a
158          "hard-coded" approach that renders the actions directly on the JSP file.
159          Some extension points uses a locked renderer, while other extension
160          points provides a default renderer, but allows extensions to supply their
161          own if they want to. Renderers are mostly used by the web client extensions,
162          not so much by the core extensions.
163          </para>
164        </listitem>
165      </varlistentry>
166 
167      <varlistentry>
168        <term>Renderer factory</term>
169        <listitem>
170          <para>
171          A <interfacename docapi="net.sf.basedb.util.extensions">RendererFactory</interfacename>
172          is an object that knows how to create renderers. Renderer factories can
173          be part of both extension points and extensions. In most other aspects
174          renderer factories are very similar to action factories.
175          </para>
176        </listitem>
177      </varlistentry>
178
179      <varlistentry>
180        <term>Error handler factory</term>
181        <listitem>
182          <para>
183          An <interfacename docapi="net.sf.basedb.util.extensions">ErrorHandlerFactory</interfacename>
184          is an object that knows how to handle error that occur when executing extensions.
185          An error handler factory is defined as part of an extension point and handles all
186          errors related to the extensions of that extension point. In most other aspects
187          error handler factories are similar to renderer and action factories. If the
188          extension point doesn't define an error handler factory, the system will
189          select a default that only writes a message to the log file
190          <classname docapi="net.sf.basedb.util.extensions">LoggingErrorHandlerFactory</classname>
191          </para>
192        </listitem>
193      </varlistentry>
194     
195      <varlistentry>
196        <term>Client context</term>
197        <listitem>
198          <para>
199          A <classname docapi="net.sf.basedb.util.extensions">ClientContext</classname>
200          is an object which contains information about the current user session.
201          It is for example, possible to get information about the logged in
202          user, the currently active item, etc.
203          </para>
204         
205          <para>
206          In the BASE web client the context is always a
207          <classname docapi="net.sf.basedb.clients.web.extensions">JspContext</classname>.
208          Wherever a <classname>ClientContext</classname> object is provided as a
209          parameter it is always safe to cast it to a <classname>JspContext</classname> 
210          object. Extension points in the core usually use a
211          <classname>ClientContext</classname>.
212          </para>
213         
214          <para>
215          The context can also be used by an extension to request that a specific
216          javascript or stylesheet file should be included in the HTML code.
217          </para>
218        </listitem>
219      </varlistentry>
220     
221      </variablelist>
222     
223     
224    </sect2>
225  </sect1>
226 
227  <sect1 id="extensions_developer.helloworld">
228    <?dbhtml filename="helloworld.html" ?>
229    <title>Hello world as an extension</title>
230   
231    <para>
232      We will use the classical Hello world as the first simple example
233      of an extension. This extension will add a new menu item in the
234      menu which displays a popup with the text "Hello world!" when
235      selected. Copy the XML code below and save it to a file in
236      the <filename>plugins.dir</filename>
237      directory. The filename must end with <filename>.xml</filename>.
238      Install the extension by going through the installation wizard
239      at <menuchoice>
240          <guimenu>Administrate</guimenu>
241          <guimenuitem>Plug-ins &amp; extensions</guimenuitem>
242          <guimenuitem>Overview</guimenuitem>
243        </menuchoice>.
244    </para>
245   
246    <para>
247      When the extension has been installed you should have a new
248      menu item:
249      <menuchoice>
250        <guimenu>Extensions</guimenu>
251        <guimenuitem>Hello world!</guimenuitem>
252      </menuchoice>
253      which pops up a message in a Javascript window.
254    </para>
255   
256    <note>
257      <para>
258      You may have to logout and login again to see the new menu item.
259      </para>
260    </note>
261   
262    <programlisting language="xml">
263<![CDATA[
264<?xml version="1.0" encoding="UTF-8" ?>
265<extensions xmlns="http://base.thep.lu.se/extensions.xsd">
266   <extension
267      id="net.sf.basedb.clients.web.menu.extensions.helloworld"
268      extends="net.sf.basedb.clients.web.menu.extensions"
269      >
270      <index>1</index>
271      <about>
272         <name>Hello world</name>
273         <description>
274            The very first extensions example. Adds a "Hello world"
275            menu item that displays "Hello world" in a javascript
276            popup when selected.
277         </description>
278      </about>
279      <action-factory>
280         <factory-class> 
281            net.sf.basedb.clients.web.extensions.menu.FixedMenuItemFactory
282         </factory-class>
283         <parameters>
284            <title>Hello world!</title>
285            <tooltip>This is to test the extensions system</tooltip>
286            <onClick>alert('Hello world!')</onClick>
287            <icon>/images/info.gif</icon>
288         </parameters>
289      </action-factory>
290   </extension>
291</extensions>
292]]>
293</programlisting>
294   
295    <para>
296      The <sgmltag class="starttag">extensions</sgmltag> tag is the root
297      tag and is needed to set up the namespace and schema validation.
298    </para>
299   
300    <para>
301      The <sgmltag class="starttag">extension</sgmltag> defines a new
302      extension. It must have an <sgmltag>id</sgmltag> attribute that
303      is unique among all installed extensions and an <sgmltag>extends</sgmltag> 
304      attribute which id the ID of the extension point. For the <sgmltag>id</sgmltag>
305      attribute we recommend using the same naming conventions as for java
306      packages. See <ulink 
307      url="http://www.oracle.com/technetwork/java/codeconventions-135099.html">Java naming
308      conventions from Oracle</ulink>.
309    </para>
310   
311    <para>
312      The <sgmltag class="starttag">about</sgmltag> tag is optional and
313      can be used to provide meta information about the extension. We
314      recommend that all extensions are given at least a
315      <sgmltag class="starttag">name</sgmltag>. Other supported subtags are:
316     
317      <itemizedlist>
318        <listitem><sgmltag class="starttag">description</sgmltag></listitem>
319        <listitem><sgmltag class="starttag">version</sgmltag></listitem>
320        <listitem><sgmltag class="starttag">copyright</sgmltag></listitem>
321        <listitem><sgmltag class="starttag">contact</sgmltag></listitem>
322        <listitem><sgmltag class="starttag">email</sgmltag></listitem>
323        <listitem><sgmltag class="starttag">url</sgmltag></listitem>
324      </itemizedlist>
325     
326      <tip>
327        <title>Global about tag</title>
328       
329        <para>
330          <sgmltag class="starttag">about</sgmltag> tag can also be specified as a
331          first-level tag (eq. as a child to <sgmltag class="starttag">extensions</sgmltag>).
332          This can be useful when an XML file defines more than one extension
333          and you don't want to repeat the same information for every extension.
334          You can still override the information for specific extensions by including
335          new values in the extension's <sgmltag class="starttag">about</sgmltag>
336          tag.
337        </para>
338      </tip>
339    </para>
340   
341    <para>
342      The <sgmltag class="starttag">action-factory</sgmltag> tag is required and
343      so is the <sgmltag class="starttag">factory-class</sgmltag> subtag. It tells
344      the extension system which factory to use for creating actions. The
345      <classname docapi="net.sf.basedb.clients.web.extensions.menu">FixedMenuItemFactory</classname>
346      is a very simple factory that is shipped with BASE. This factory always creates the same
347      menu item, no matter what. Another factory for menu items is the
348      <classname docapi="net.sf.basedb.clients.web.extensions.menu">PermissionMenuItemFactory</classname>
349      which can create menu items that depends on the logged in user's permissions. It is
350      for example, possible to hide or disable the menu item if the user doesn't have enough
351      permissions. If none of the supplied factories suits you it is possible to
352      supply your own implementation. More about this later.
353    </para>
354   
355    <para>
356      The <sgmltag class="starttag">parameters</sgmltag> subtag is used to
357      provide initialisation parameters to the factory. Different factories
358      supports different parameters and you will have to check the javadoc documentation
359      for each factory to get information about which parameters that are supported.
360    </para>
361   
362    <tip>
363      <para>
364        In case the factory is poorly documented you can always assume that public
365        methods the start with <code>set</code> and take a single <classname>String</classname>
366        as an argument can be used as a parameter. The parameter tag to use should
367        be the same as the method name, minus the <code>set</code> prefix and with
368        the first letter in lowercase. For example, the method
369        <methodname>setIcon(String icon)</methodname> corresponds to the
370        <sgmltag class="starttag">icon</sgmltag> parameter.
371      </para>
372    </tip>
373   
374    <sect2 id="extensions_developer.extend_multiple">
375      <title>Extending multiple extension points with a single extension</title>
376     
377      <para>
378        A single extension can extend multiple extension points as long as their
379        action classes are compatible. This is for, for example, the case when
380        you want to add a button to more than one toolbar.       
381        To do this use the <sgmltag class="starttag">extends</sgmltag>
382        tag with multiple <sgmltag class="starttag">ref</sgmltag> tags.
383        You can skip the <sgmltag class="attribute">extends</sgmltag> 
384        attribute in the main tag.
385      </para>
386    <programlisting language="xml">
387<![CDATA[
388<extension
389   id="net.sf.basedb.clients.web.menu.extensions.history-edit"
390   >
391   <extends>
392      <ref index="2">net.sf.basedb.clients.web.tabcontrol.edit.sample</ref>
393      <ref index="2">net.sf.basedb.clients.web.tabcontrol.edit.extract</ref>
394   </extends>
395   ...
396</extension>
397]]>
398</programlisting>
399     
400      <para>
401        This is a feature of the XML format only. Behind the scenes two extensions will
402        be created (one for each extension point). The extensions will share the same
403        action and renderer factory instances. Since the id for an extension must be unique
404        a new id will be generated by combining the original id with the parts of the id's from
405        the extension points.
406      </para>
407     
408    </sect2>
409  </sect1>
410
411
412  <sect1 id="extensions_developer.factories">
413    <?dbhtml filename="factories.html" ?>
414    <title>Custom action factories</title>
415
416    <para>
417      Some times the factories shipped with BASE are not enough, and you
418      may want to provide your own factory implementation. In this case you will
419      have to create a class that implements the
420      <interfacename docapi="net.sf.basedb.util.extensions">ActionFactory</interfacename>
421      interface. Here is a very simple example that does the same as the
422      previous "Hello world" example.
423    </para>
424   
425    <programlisting language="java">
426<![CDATA[
427package net.sf.basedb.examples.extensions;
428
429import net.sf.basedb.clients.web.extensions.JspContext;
430import net.sf.basedb.clients.web.extensions.menu.MenuItemAction;
431import net.sf.basedb.clients.web.extensions.menu.MenuItemBean;
432import net.sf.basedb.util.extensions.ActionFactory;
433import net.sf.basedb.util.extensions.InvokationContext;
434
435/**
436   First example of an action factory where eveything is hardcoded.
437   @author nicklas
438*/
439public class HelloWorldFactory
440   implements ActionFactory<MenuItemAction>
441{
442
443   private MenuItemAction[] helloWorld;
444
445   // A public, no-argument constructor is required
446   public HelloWorldFactory()
447   {
448      helloWorld = new MenuItemAction[1];
449   }
450   
451   // Return true enable the extension, false to disable it
452   public boolean prepareContext(
453      InvokationContext<? super MenuItemAction> context)
454   {
455      return true;
456   }
457
458   // An extension may create one or more actions
459   public MenuItemAction[] getActions(
460      InvokationContext<? super MenuItemAction> context)
461   {
462      // This cast is always safe with the web client
463      JspContext jspContext = (JspContext)context.getClientContext();
464      if (helloWorld[0] == null)
465      {
466         MenuItemBean bean = new MenuItemBean();
467         bean.setTitle("Hello factory world!");
468         bean.setIcon(jspContext.getRoot() + "/images/info.gif");
469         bean.setOnClick("alert('Hello factory world!')");
470         helloWorld[0] = bean;
471      }
472      return helloWorld;
473   }
474}
475]]>
476</programlisting>
477
478    <para>
479      And here is the XML configuration file that goes with it.
480    </para>
481
482    <programlisting language="xml">
483<![CDATA[
484<?xml version="1.0" encoding="UTF-8" ?>
485<extensions xmlns="http://base.thep.lu.se/extensions.xsd">
486   <extension
487      id="net.sf.basedb.clients.web.menu.extensions.helloworldfactory"
488      extends="net.sf.basedb.clients.web.menu.extensions"
489      >
490      <index>2</index>
491      <about>
492         <name>Hello factory world</name>
493         <description>
494            A "Hello world" variant with a custom action factory.
495            Everything is hard-coded into the factory.
496         </description>
497      </about>
498      <action-factory>
499         <factory-class>
500            net.sf.basedb.examples.extensions.HelloWorldFactory
501         </factory-class>
502      </action-factory>
503   </extension>
504</extensions>
505]]>
506</programlisting>
507   
508    <para>
509      To install this extension you need to put the compiled
510      <filename>HelloWorldFactory.class</filename> and the XML
511      file inside a JAR file. The XML file must be located at
512      <filename>META-INF/extensions.xml</filename> and the class
513      file at <filename>net/sf/basedb/examples/extensions/HelloWorldFactory.class</filename>.
514    </para>
515   
516    <para>
517      The above example is a bit artificial and we have not gained anything.
518      Instead, we have lost the ability to easily change the menu since everything is
519      now hardcoded into the factory. To change, for example the title, requires that
520      we recompile the java code. It would be more useful if we could make the factory
521      configurable with parameters. The next example will make the icon
522      and message configurable, and also include the name
523      of the currently logged in user. For example: "Greetings &lt;name of
524      logged in user&gt;!".
525    </para>
526   
527    <programlisting language="java">
528<![CDATA[
529package net.sf.basedb.examples.extensions;
530
531import net.sf.basedb.clients.web.extensions.AbstractJspActionFactory;
532import net.sf.basedb.clients.web.extensions.menu.MenuItemAction;
533import net.sf.basedb.clients.web.extensions.menu.MenuItemBean;
534import net.sf.basedb.core.DbControl;
535import net.sf.basedb.core.SessionControl;
536import net.sf.basedb.core.User;
537import net.sf.basedb.util.extensions.ClientContext;
538import net.sf.basedb.util.extensions.InvokationContext;
539import net.sf.basedb.util.extensions.xml.PathSetter;
540import net.sf.basedb.util.extensions.xml.VariableSetter;
541
542/**
543   Example menu item factory that creates a "Hello world" menu item
544   where the "Hello" part can be changed by the "prefix" setting in the
545   XML file, and the "world" part is dynamically replaced with the name
546   of the logged in user.
547   
548   @author nicklas
549*/
550public class HelloUserFactory
551   extends AbstractJspActionFactory<MenuItemAction>
552{
553   // To store the URL to the icon
554   private String icon;
555   
556   // The default prefix is Hello
557   private String prefix = "Hello";
558   
559   // A public, no-argument constructor is required
560   public HelloUserFactory()
561   {}
562   
563   /**
564      Creates a menu item that displays: {prefix} {name of user}!
565   */
566   public MenuItemAction[] getActions(
567      InvokationContext<? super MenuItemAction> context)
568   {
569      String userName = getUserName(context.getClientContext());
570      MenuItemBean helloUser = new MenuItemBean();
571      helloUser.setTitle(prefix + " " + userName + "!");
572      helloUser.setIcon(icon);
573      helloUser.setOnClick("alert('" + prefix + " " + userName + "!')");
574      return new MenuItemAction[] { helloUser };
575   }
576
577   /**
578      Get the name of the logged in user.
579   */
580   private String getUserName(ClientContext context)
581   {
582      SessionControl sc = context.getSessionControl();
583      DbControl dc = context.getDbControl();
584      User current = User.getById(dc, sc.getLoggedInUserId());
585      return current.getName();
586   }
587   
588   /**
589      Sets the icon to use. Path conversion is enabled.
590   */
591   @VariableSetter
592   @PathSetter
593   public void setIcon(String icon)
594   {
595      this.icon = icon;
596   }
597   
598   /**
599      Sets the prefix to use. If not set, the
600      default value is "Hello".
601   */
602   public void setPrefix(String prefix)
603   {
604      this.prefix = prefix == null ? "Hello" : prefix;
605   }
606}
607]]>
608</programlisting>
609   
610    <para>
611      The are two new parts in this factory. The first is the <methodname>getUserName()</methodname>
612      method which is called from <methodname>getActions()</methodname>. Note
613      that the <methodname>getActions()</methodname> method always create
614      a new <classname docapi="net.sf.basedb.clients.web.extensions.menu">MenuItemBean</classname>.
615      It can no longer be cached since the title and javascript code depends on
616      which user is logged in.
617    </para>
618   
619    <para>
620      The second new part is the <methodname>setIcon()</methodname> and
621      <methodname>setPrefix()</methodname> methods.
622      The extensions system uses java reflection to find the existance of
623      the methods if <sgmltag class="starttag">icon</sgmltag> and/or
624      <sgmltag class="starttag">prefix</sgmltag> tags are present
625      in the <sgmltag class="starttag">parameters</sgmltag> tag for a factory,
626      the methods are automatically called with the value inside the tag
627      as it's argument.
628    </para>
629   
630    <para>
631      The <classname docapi="net.sf.basedb.util.extensions.xml">VariableSetter</classname> 
632      and <classname docapi="net.sf.basedb.util.extensions.xml">PathSetter</classname> 
633      annotations on the <methodname>setIcon()</methodname> are used to enable
634      "smart" convertions of the value. Note that in the
635      XML file you only have to specify <filename>/images/info.gif</filename>
636      as the URL to the icon, but in the hardcoded factory you have to
637      do: <code>jspContext.getRoot() + "/images/info.gif"</code>. In this case,
638      it is the <classname>PathSetter</classname> which automatically adds the
639      the JSP root directory to all URL:s starting with /. The
640      <classname>VariableSetter</classname> can do the same thing but you would have to use
641      <code>$ROOT$</code> instead. Eg. <code>$ROOT$/images/info.gif</code>. The
642      <classname>PathSetter</classname> only looks at the first characteer,
643      while the <classname>VariableSetter</classname> looks in the entire string.
644    </para>
645   
646    <para>
647      Here is an example of an extension configuration that can be used
648      with the new factory.
649    </para>
650   
651    <programlisting language="xml">
652<![CDATA[
653<extensions xmlns="http://base.thep.lu.se/extensions.xsd">
654   <extension
655      id="net.sf.basedb.clients.web.menu.extensions.hellouser"
656      extends="net.sf.basedb.clients.web.menu.extensions"
657      >
658      <index>3</index>
659      <about>
660         <name>Greetings user</name>
661         <description>
662            A "Hello world" variant with a custom action factory
663            that displays "Greetings {name of user}" instead. We also
664            make the icon configurable.
665         </description>
666      </about>
667      <action-factory>
668         <factory-class>
669            net.sf.basedb.examples.extensions.HelloUserFactory
670         </factory-class>
671         <parameters>
672            <prefix>Greetings</prefix>
673            <icon>/images/take_ownership.png</icon>
674         </parameters>
675      </action-factory>
676   </extension>
677</extensions>
678]]>
679</programlisting>
680   
681    <note>
682      <title>Be aware of multi-threading issues</title>
683      <para>
684        When you are creating custom action and renderer factories be
685        aware that multiple threads may use a single factory instance
686        at the same time. Action and renderer objects only needs to
687        be thread-safe if the factories re-use the same objects.
688      </para>
689    </note>
690   
691  </sect1>
692
693  <sect1 id="extensions_developer.resources">
694    <?dbhtml filename="resources.html" ?>
695    <title>Custom images, JSP files, and other resources</title>
696
697    <para>
698      Some times your extension may need other resources. It can for
699      for example be an icon, a javascript file, a JSP file or something
700      else. Fortunately this is very easy. You need to put the extension
701      in a JAR file. As usual the extension definition XML file should be
702      at <filename>META-INF/extensions.xml</filename>. Everything you put in
703      the JAR file inside the <filename>resources/</filename> directory
704      will automatically be extracted by the extension system to a directory
705      on the web server. Here is another "Hello world" example which uses a
706      custom JSP file to display the message. There is also a custom icon.
707    </para>
708   
709    <programlisting language="xml">
710<![CDATA[
711<extensions xmlns="http://base.thep.lu.se/extensions.xsd">
712   <extension
713      id="net.sf.basedb.clients.web.menu.extensions.hellojspworld"
714      extends="net.sf.basedb.clients.web.menu.extensions"
715      >
716      <index>4</index>
717      <about>
718         <name>Hello JSP world</name>
719         <description>
720            This example uses a custom JSP file to display the
721            "Hello world" message instead of a javascript popup.
722         </description>
723      </about>
724      <action-factory>
725         <factory-class>
726            net.sf.basedb.clients.web.extensions.menu.FixedMenuItemFactory
727         </factory-class>
728         <parameters>
729            <title>Hello JSP world!</title>
730            <tooltip>Opens a JSP file with the message</tooltip>
731            <onClick>
732               Main.openPopup('$HOME$/hello_world.jsp?ID=' + getSessionId(), 'HelloJspWorld', 400, 300)
733            </onClick>
734            <icon>~/images/world.png</icon>
735         </parameters>
736      </action-factory>
737   </extension>
738</extensions>
739]]>
740</programlisting>
741   
742    <para>
743      The JAR file should have have the following contents:
744    </para>
745   
746    <programlisting>
747META-INF/extensions.XML
748resources/hello_world.jsp
749resources/images/world.png
750</programlisting>
751   
752    <para>
753      When this extension is installed the <filename>hello_world.jsp</filename>
754      and <filename>world.png</filename> files are automatically extracted
755      to the web servers file system. Each extension is given a unique
756      <code>HOME</code> directory to make sure that extensions doesn't interfere
757      with each other. The URL to the home directory is made available in the
758      <varname>$HOME$</varname> variable. All factory settings that have
759      been annotated with the <interfacename 
760      docapi="net.sf.basedb.util.extensions.xml">VariableSetter</interfacename>
761      will have their values scanned for <code>$HOME$</code> which is replaced
762      with the real URL. It is also possible to use the <varname>$ROOT$</varname>
763      variable to get the root URL for the BASE web application. Never use
764      <code>/base/...</code> since users may install BASE into another
765      path.
766    </para>
767   
768    <para>
769      The tilde (~) in the <sgmltag class="starttag">icon</sgmltag> tag value
770      is also replaced with the <code>HOME</code> path. Note that this kind of
771      replacement is only done on factory settings that have been annotated
772      with the <classname docapi="net.sf.basedb.util.extensions.xml">PathSetter</classname>
773      annotation and is only done on the first character.
774    </para>
775   
776    <note>
777      <para>
778      Unfortunately, the custom JSP file can't use classes that
779      are located in the extension's JAR file. The reason is that the
780      JAR file is not known to Tomcat and Tomcat will not look in the
781      <filename>plugins.dir</filename> folder to
782      try to find classes. There are currently two possible workarounds:
783      </para>
784     
785      <itemizedlist>
786      <listitem>
787        <para>
788        Place classes needed by JSP files in a separate JAR file that
789        is installed into the <filename>WEB-INF/lib</filename> folder.
790        The drawback is that this requires a restart of Tomcat.
791        </para>
792      </listitem>
793     
794      <listitem>
795        <para>
796        Use an X-JSP file instead. This is an experimental feature. See
797        <xref linkend="extensions_developer.resources.xjsp" /> for more
798        information.
799        </para>
800      </listitem>
801      </itemizedlist>
802    </note>
803   
804    <sect2 id="extensions_developer.resources.scripts">
805      <title>Javascript and stylesheets</title>
806     
807      <para>
808        It is possible for an extension to use a custom javascript or stylesheet.
809        However, this doesn't happen automatically and may not be enabled
810        for all extension points. If an extension needs this functionality
811        the action factory or renderer factory must call
812        <methodname>JspContext.addScript()</methodname> or
813        <methodname>JspContext.addStylesheet()</methodname> from the
814        <methodname>prepareContext()</methodname> method.
815      </para>
816     
817      <para>
818        The <classname 
819        docapi="net.sf.basedb.clients.web.extensions">AbstractJspActionFactory</classname>
820        and <classname 
821        docapi="net.sf.basedb.clients.web.extensions">AbstractJspRendererFactory</classname>
822        factory can do this. All factories shipped with BASE extends one of those
823        classes and we recommend that custom-made factories also does this.
824      </para>
825     
826      <para>
827        Factories that are extending one of those two classes can use
828        <sgmltag class="starttag">script</sgmltag> and
829        <sgmltag class="starttag">stylesheet</sgmltag> tags in the
830        <sgmltag class="starttag">parameters</sgmltag> section for an
831        extensions. Each tag may be used more than one time. The
832        values are subject to path and variable substitution.
833      </para>
834     
835      <programlisting language="xml">
836<![CDATA[
837<action-factory>
838   <factory-class>
839      ... some factory class ...
840   </factory-class>
841   <parameters>
842      <script>~/scripts/custom.js</script>
843      <stylesheet>~/css/custom.css</stylesheet>
844      ... other parameters ...
845   </parameters>
846</action-factory>
847]]>
848</programlisting>
849     
850      <para>
851        If scripts and stylesheets has been added to the JSP context
852        the extension system will, <emphasis>in most cases</emphasis>,
853        include the proper HTML to link in the requested scripts and/or
854        stylesheet.
855      </para>
856     
857      <note>
858        <title>Use UTF-8 character encoding</title>
859        <para>
860          The script and stylesheet files should use use UTF-8 character encoding.
861          Otherwise they may not work as expected in BASE.
862        </para>
863      </note>
864     
865      <note>
866        <title>All extension points doesn't support custom scripts/stylesheets</title>
867        <para>
868          In some cases the rendering of the HTML page has gone to far
869          to make is possible to include custom scripts and stylesheets.
870          This is for example the case with the extensions menu. Always
871          check the documentation for the extension point if scripts
872          and stylesheets are supported or not.
873        </para>
874      </note>
875    </sect2>
876   
877    <sect2 id="extensions_developer.resources.xjsp">
878      <title>X-JSP files</title>
879     
880      <para>
881        The drawback with a custom JSP file is that it is not possible to
882        use classes from the extension's JAR file in the JSP code. The reason
883        is that the JAR file is not known to Tomcat and Tomcat will not look
884        in the <filename>plugins.dir</filename> folder to try to find
885        classes.
886      </para>
887     
888      <para>
889        One workaround is to place classes that are needed by the JSP files
890        in a separate JAR file that is placed in <filename>WEB-INF/lib</filename>.
891        The drawback with this is that it requires a restart of Tomcat. It is
892        also a second step that has to be performed manually by the person
893        installing the extension and is maybe forgotten when doing an update.
894      </para>
895     
896      <para>
897        Another workaround is to use an X-JSP file. This is simply a regular
898        JSP file that has a <code>.xjsp</code> extension instead of <code>.jsp</code>.
899        The <code>.xjsp</code> extension will trigger the use of a different
900        compiler that knows how to include the extension's JAR file in the class
901        path.
902      </para>
903     
904      <note>
905        <title>X-JSP is experimental</title>
906        <para>
907          The X-JSP compiler depends on functionality that is internal to
908          Tomcat. The JSP compiler is not part of any open specification
909          and the implementation details may change at any time. This means
910          that the X-JSP compiler may or may not work with future versions
911          of Tomcat. We have currently tested it with Tomcat 6.0.14 only.
912          It will most likely not work with other servlet containers.
913        </para>
914       
915        <para>
916          Adding support for X-JSP requires that a JAR file with the
917          X-JSP compiler is installed into Tomcat's internal <filename>/lib</filename>
918          directory. It is an optional step and not all BASE installations
919          may have the compiler installed. See <xref linkend="plugins.installation.xjspcompiler" />.
920        </para>
921      </note>
922     
923    </sect2>
924  </sect1>
925 
926  <sect1 id="extensions_developer.renderer">
927    <?dbhtml filename="renderer.html" ?>
928    <title>Custom renderers and renderer factories</title>
929
930    <para>
931      It is always the responsibility of the extension point to
932      render an action. The need for custom renderers is typically
933      very small, at least if you want your extensions to blend into
934      the look and feel of the BASE web client. Most customizations can
935      be probably be handled by stylesheets and images. That said,
936      you may still have a reason for using a custom renderer.
937    </para>
938   
939    <para>
940      Renderer factories are not very different from action factories.
941      They are specified in the same way in the XML file and uses the
942      same method for initialisation, including support for path
943      conversion, etc. The difference is that you use a
944      <sgmltag class="starttag">renderer-factory</sgmltag> tag
945      instead of an <sgmltag class="starttag">action-factory</sgmltag>
946      tag.
947    </para>
948
949    <programlisting language="xml">
950<![CDATA[
951<renderer-factory>
952   <factory-class>
953      ... some factory class ...
954   </factory-class>
955   <parameters>
956      ... some parameters ...
957   </parameters>
958</renderer-factory>
959]]>
960</programlisting>
961
962    <para>
963      A <interfacename docapi="net.sf.basedb.util.extensions"
964      >RendererFactory</interfacename> also has a <methodname>prepareContext()</methodname>
965      method that can be used to tell the web client about any scripts or stylesheets
966      the extension needs. If your renderer factory extends the <classname 
967        docapi="net.sf.basedb.clients.web.extensions">AbstractJspRendererFactory</classname>
968      class you will not have to worry about this since you can configure
969      scripts and stylesheets in the XML file.
970    </para>
971   
972    <para>
973      A render factory must also implement the <methodname>getRenderer()</methodname> 
974      which should return a <interfacename docapi="net.sf.basedb.util.extensions"
975      >Renderer</interfacename> instance. The extension system will then call
976      the <methodname>Renderer.render()</methodname> method to render an action.
977      This method may be called multiple times if the extension created more than
978      one action.
979    </para>
980   
981    <para>
982      The renderers responsibility is to generate the HTML
983      that is going to be sent to the web client. To do this it needs
984      access to the <classname 
985      docapi="net.sf.basedb.clients.web.extensions">JspContext</classname> 
986      object that was passed to the renderer factory. Here is a simple
987      outline of both a renderer factory and renderer.
988    </para>
989   
990    <programlisting language="java">
991<![CDATA[
992// File: MyRendererFactory.java
993public class MyRendererFactory
994   extends AbstractJspRendererFactory<MyAction>
995{
996
997   public MyRendererFactory()
998   {}
999
1000   @Override
1001   public MyRenderer getRenderer(InvokationContext context)
1002   {
1003      return new MyRenderer((JspContext)context.getClientContext());
1004   }
1005}
1006
1007// File: MyRenderer.java
1008public class MyRenderer
1009   implements Renderer<MyAction>
1010{
1011
1012   private final JspContext context;
1013   public MyRenderer(JspContext context)
1014   {
1015      this.context = context;
1016   }
1017
1018   /**
1019      Generates HTML (unless invisible):
1020      <a class="[clazz]" style="[style]" onclick="[onClick]">[title]</a>
1021   */
1022   public void render(MyAction action)
1023   {
1024      if (!action.isVisible()) return;
1025      Writer out = context.getOut();
1026      try
1027      {
1028         out.write("<a");
1029         if (action.getClazz() != null)
1030         {
1031            out.write(" class=\"" + action.getClazz() + "\"");
1032         }
1033         if (action.getStyle() != null)
1034         {
1035            out.write(" style=\"" + action.getStyle() + "\"");
1036         }
1037         if (action.getOnClick() != null)
1038         {
1039            out.write(" href=\"" + action.getOnClick() + "\"");
1040         }
1041         out.write(">");
1042         out.write(HTML.encodeTags(action.getTitle()));
1043         out.write("</a>\n");
1044      }
1045      catch (IOException ex)
1046      {
1047         throw new RuntimeException(ex);
1048      }
1049   }
1050}
1051]]>
1052</programlisting>
1053  </sect1>
1054 
1055  <sect1 id="extensions_developer.extension_points">
1056    <?dbhtml filename="extensionpoints.html" ?>
1057    <title>Extension points</title>
1058   
1059    <para>
1060      The BASE web client ships with a number of predefined extension
1061      points. Adding more extension points to the existing web client
1062      requires some minor modifications to the regular JSP files. But this
1063      is not what this chapter is about. This chapter is about defining new
1064      extension points as part of an extension. It is nothing magical about
1065      this and the process is the same as for the regular extension points in
1066      the web client.
1067    </para>
1068   
1069    <para>
1070      The first thing you need to do is to start writing the
1071      XML definition of the extension point. Here is an example
1072      from the web client:
1073    </para>
1074   
1075    <programlisting language="xml">
1076<![CDATA[
1077<extensions
1078   xmlns="http://base.thep.lu.se/extensions.xsd"
1079   >
1080   <extension-point
1081      id="net.sf.basedb.clients.web.menu.extensions"
1082      >
1083      <action-class>net.sf.basedb.clients.web.extensions.menu.MenuItemAction</action-class>
1084      <name>Menu: extensions</name>
1085      <description>
1086         Extension point for adding extensions to the 'Extensions' menu.
1087         Extensions should provide MenuItemAction instances. The rendering
1088         is internal and extensions can't use their own rendering factories.
1089         The context will only include information about the currently logged
1090         in user, not information about the current page that is displayed.
1091         The reason for this is that the rendered menu is cached as a string
1092         in the user session. The menu is not updated on every page request.
1093         This extension point doesn't support custom stylesheets or javascripts.
1094      </description>
1095   </extension-point>
1096</extensions>
1097]]>
1098</programlisting>
1099   
1100    <para>
1101      The <sgmltag class="starttag">extensions</sgmltag> tag is the root tag and
1102      is needed to set up the namespace and schema validation.
1103    </para>
1104   
1105    <para>
1106      The <sgmltag class="starttag">extension-point</sgmltag> defines a new
1107      extension point. It must have an <sgmltag>id</sgmltag> attribute that
1108      is unique among all installed extension points. We recommend using
1109      the same naming conventions as for java packages. See <ulink 
1110      url="http://www.oracle.com/technetwork/java/codeconventions-135099.html">Java naming
1111      conventions from Oracle</ulink>.
1112    </para>
1113   
1114    <note>
1115      <title>Document the extension point!</title>
1116      <para>
1117        The <sgmltag class="starttag">name</sgmltag> and
1118        <sgmltag class="starttag">description</sgmltag> tags are optional,
1119        but we strongly recommend that values are provided.
1120        The description tag should be used to document the extension
1121        point. Pay special attention to the support (or lack of
1122        support) for custom scripts, stylesheets and renderers.
1123      </para>
1124    </note>
1125   
1126    <para>
1127      The <sgmltag class="starttag">action-class</sgmltag> defines the
1128      interface or class that extensions must provide to the extension
1129      point. This must be a class or interface that is a subclass
1130      of the <interfacename 
1131      docapi="net.sf.basedb.util.extensions">Action</interfacename>
1132      interface. We generally recommend that interfaces are used since
1133      this gives more implementation flexibility for action factories, but
1134      a regular class may work just as well.
1135    </para>
1136     
1137    <para>
1138      The action class is used to carry information about the action,
1139      such as a title, which icon to use, a tooltip text, a javascript
1140      snippet that is invoked on click events, etc. The action class may
1141      be as simple or complex as you like.
1142    </para>
1143     
1144    <note>
1145      <title>Web client extension points</title>
1146      <para>
1147        This is a note for the core developers. Extension points that
1148        are part of the web client should always define the action as
1149        an interface. We recommend that <code>getId()</code>, <code>getClazz()</code>
1150        and <code>getStyle()</code> attributes are always included if this makes
1151        sense. It is usually also a good idea to include <code>isVisible()</code>
1152        and <code>isEnabled()</code> attributes.
1153      </para>
1154    </note>
1155     
1156    <para>
1157      Now, if you are a good citizen you should also provide at least
1158      one implementation of an action factory that can create the
1159      objects of the desired type of action. The factory should
1160      of course be configurable from the XML file.
1161    </para>
1162   
1163    <para>
1164      If you are lazy or if you want to immediately start testing the JSP code
1165      for the extension point, it may be possible to use one of the debugger action
1166      factories in the <package>net.sf.basedb.util.extensions.debug</package>
1167      pacakge.
1168    </para>
1169   
1170    <itemizedlist>
1171    <listitem>
1172      <para>
1173      <classname 
1174      docapi="net.sf.basedb.util.extensions.debug">ProxyActionFactory</classname>:
1175      This action factory can only be used if your action class is an interface
1176      and all important methods starts with <code>get</code> or <code>is</code>.
1177      The proxy action factory uses Java reflection to create a dynamic
1178      proxy class in runtime. It will map all <code>getX()</code> and <code>isY()</code> 
1179      methods to retreive the values from the corresponding parameter in the XML file.
1180      For example, <methodname>getIcon()</methodname> will retrieve the value
1181      of the <sgmltag class="starttag">icon</sgmltag> tag and
1182      <methodname>isVisible()</methodname> from the <sgmltag 
1183      class="starttag">visible</sgmltag>. The factory is smart enough to convert
1184      the string to the correct return value for <type>int</type>, <type>long</type>,
1185      <type>float</type>, <type>double</type> and <type>boolean</type> data types and
1186      their corresponding object wrapper types, if this is needed.
1187      </para>
1188    </listitem>
1189   
1190    <listitem>
1191      <para>
1192      <classname 
1193      docapi="net.sf.basedb.util.extensions.debug">BeanActionFactory</classname>:
1194      This action factory can be used if you have created a bean-like
1195      class that implements the desired action class. The factory will
1196      create an instance of the class specified by the
1197      <sgmltag class="starttag">beanClass</sgmltag> parameter. The factory
1198      will then use Java reflection to find <code>set</code> method
1199      for the other parameters. If there is a parameter <sgmltag class="starttag">icon</sgmltag>
1200      the factory first looks for a <methodname>setIcon(String)</methodname>
1201      method. If it can't find that it will see if there is a <methodname>getIcon()</methodname>
1202      method which has a return type, T. If so, a second attempt is made to find
1203      a <methodname>setIcon(T)</methodname> method. The factory is smart enough
1204      to convert the string value from the XML file to the correct return value
1205       for <type>int</type>, <type>long</type>, <type>float</type>,
1206      <type>double</type> and <type>boolean</type> data types and their
1207      corresponding object wrapper types, if this is needed.
1208      </para>
1209    </listitem>
1210   
1211    </itemizedlist>
1212
1213
1214    <para>
1215      It is finally time to write the JSP code that actually uses the
1216      extension point. It is usually not very complicated. Here is
1217      an exemple which lists snippets from a JSP file:
1218    </para>
1219
1220    <programlisting>
1221<![CDATA[
1222// 1. We recommend using the extensions taglib (and the BASE core taglib)
1223<%@ taglib prefix="ext" uri="/WEB-INF/extensions.tld" %>
1224<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
1225
1226// 2. Prepare the extension point
1227SessionControl sc = Base.getExistingSessionControl(pageContext, true);
1228JspContext jspContext = ExtensionsControl.createContext(sc, pageContext);
1229ExtensionsInvoker invoker = ExtensionsControl.useExtensions(jspContext,
1230   "my.domain.name.extensionspoint");
1231
1232// 3. Output scripts and stylesheets
1233<base:page title="My new extension point">
1234   <base:head>
1235      <ext:scripts context="<%=jspContext%>" />
1236      <ext:stylesheets context="<%=jspContext%>" />
1237   </base:head>
1238   <base:body>
1239   ....
1240
1241// 4a. Using a taglib for rendering with the default renderer
1242<ext:render extensions="<%=invoker%>" context="<%=jspContext%>" />
1243
1244// 4b. Or, use the iterator and a more hard-coded approach
1245<%
1246Iterator it = invoker.iterate();
1247while (it.hasNext())
1248{
1249   MyAction action = (MyAction)it.next();
1250   String html = action.getTitle() +
1251    ....
1252   out.write(html);
1253}
1254%>
1255]]>
1256</programlisting>
1257
1258    <sect2 id="extensions_developer.error_handler">
1259      <title>Error handlers</title>
1260     
1261      <para>
1262        An extension points may define a custom error handler. If not, the
1263        default error handler is used which simply writes a message to the
1264        log file. If you want to use a different error handler, create
1265        a <sgmltag class="starttag">error-handler-factory</sgmltag> tag
1266        inside the extension point definition. The <sgmltag 
1267        class="starttag">factory-class</sgmltag> is a required subtag and
1268        must specify a class with a public no-argument constructor that
1269        implements the
1270        <interfacename docapi="net.sf.basedb.util.extensions">ErrorHandlerFactory</interfacename>
1271        interface. The <sgmltag class="starttag">parameters</sgmltag> subtag is
1272        optional and can be used to specify initialization parameters for the
1273        factory just as for action and renderer factories.
1274      </para>
1275
1276      <programlisting language="xml">
1277<![CDATA[
1278<extensions
1279   xmlns="http://base.thep.lu.se/extensions.xsd"
1280   >
1281   <extension-point
1282      id="net.sf.basedb.clients.web.menu.extensions"
1283      >
1284      <action-class>net.sf.basedb.clients.web.extensions.menu.MenuItemAction</action-class>
1285      <name>Menu: extensions</name>
1286      <error-handler-factory>
1287         <factory-class>
1288            ... some factory class ...
1289         </factory-class>
1290         <parameters>
1291            ... initialization parameters ...
1292         </parameters>
1293      </error-handler-factory>
1294   </extension-point>
1295</extensions>
1296]]>
1297</programlisting>
1298    </sect2>
1299  </sect1>
1300 
1301  <sect1 id="extensions_developer.servlets">
1302    <?dbhtml filename="servlets.html" ?>
1303    <title>Custom servlets</title>
1304    <para>
1305      It is possible for an extension to include servlets without having
1306      to register those servlets in Tomcat's <filename>WEB-INF/web.xml</filename>
1307      file. The extension needs to be in a JAR file as usual. The servlet class
1308      should be located in the JAR file following regular Java conventions.
1309      Eg. The class <classname>my.domain.ServletClass</classname> should
1310      be located at <filename>my/domain/ServletClass.class</filename>. You
1311      also need to create a second XML file that contains the servlet
1312      definitions at <filename>META-INF/servlets.xml</filename>. The format for
1313      defining servlets in this file is very similar to how servlets are
1314      defined in the <filename>web.xml</filename> file. Here is an example:
1315    </para>
1316   
1317    <programlisting language="xml">
1318<![CDATA[
1319<?xml version="1.0" encoding="UTF-8" ?>
1320<servlets xmlns="http://base.thep.lu.se/servlets.xsd">
1321   <servlet>
1322      <servlet-name>HelloWorld</servlet-name>
1323      <servlet-class>net.sf.basedb.examples.extensions.HelloWorldServlet</servlet-class>
1324      <init-param>
1325         <param-name>template</param-name>
1326         <param-value>Hello {user}! Welcome to the Servlet world!</param-value>
1327      </init-param>
1328   </servlet>
1329</servlets>
1330]]>
1331</programlisting>
1332
1333    <para>
1334      The <sgmltag class="starttag">servlets</sgmltag> tag is the root tag and is
1335      needed to set up the namespace and schema validation. This may contain
1336      any number of <sgmltag class="starttag">servlet</sgmltag> tags, each one
1337      defining a single servlet.
1338    </para>
1339   
1340    <para>
1341      The <sgmltag class="starttag">servlet-name</sgmltag> tag contains the name
1342      of the servlet. This is a required tag and must be unique among the servlets
1343      defined by this extension. Other extensions may use the same name without any
1344      problems.
1345    </para>
1346   
1347    <para>
1348      The <sgmltag class="starttag">servlet-class</sgmltag> tag contains the name
1349      of implementing class. This is required and the class must implement
1350      the <interfacename>Servlet</interfacename> interface and have a public,
1351      no-argument constructor. We recommend that servlet implementations instead
1352      extends the <classname>HttpServlet</classname> class. This will make the
1353      servlet programming easier.
1354    </para>
1355   
1356    <para>
1357      A servlet may have any number <sgmltag class="starttag">init-param</sgmltag>
1358      tags, containing initialisation parameters for the servlet. Here is the
1359      code for the servlet references in the above example.
1360    </para>
1361
1362    <programlisting language="java">
1363<![CDATA[
1364public class HelloWorldServlet
1365   extends HttpServlet
1366{
1367   private String template;
1368   public HelloWorldServlet()
1369   {}
1370
1371   @Override
1372   public void init()
1373      throws ServletException
1374   {
1375      ServletConfig cfg = getServletConfig();
1376      template = cfg.getInitParameter("template");
1377      if (template == null) template = "Hello {user}.";
1378   }
1379
1380   @Override
1381   protected void doGet(HttpServletRequest request, HttpServletResponse response)
1382      throws ServletException, IOException
1383   {
1384      final SessionControl sc = Base.getExistingSessionControl(request, true);
1385      final DbControl dc = sc.newDbControl();
1386      try
1387      {
1388         User current = User.getById(dc, sc.getLoggedInUserId());
1389         PrintWriter out = response.getWriter();
1390         out.print(template.replace("{user}", current.getName()));
1391      }
1392      finally
1393      {
1394         if (dc != null) dc.close();
1395      }
1396   }
1397   @Override
1398   protected void doPost(HttpServletRequest req, HttpServletResponse resp)
1399      throws ServletException, IOException
1400   {
1401      doGet(req, resp);
1402   }
1403}
1404]]>
1405</programlisting>
1406
1407    <para>
1408      Invoking the servlet is done with a URL that is constructed like:
1409      <filename>$HOME$/[servlet-name].servlet</filename>, where <code>$HOME$</code>
1410      is the home directory of the extension. An alternate URL
1411      that doesn't require the <filename>.servlet</filename> extension is available:
1412      <filename>$SERVLET_HOME$/[servlet-name]</filename>, where <code>$SERVLET_HOME$</code>
1413      is the home directory of servlets for the extension. Note that this
1414      directory is on a different sub-path than the <code>$HOME$</code> directory.
1415    </para>
1416    <para>
1417      Extra path information is supported
1418      if it is inserted between the servlet name and the <filename>.servlet</filename>
1419      extension: <filename>$HOME$/[servlet-name][/extra/path/info].servlet</filename>,
1420      <filename>$SERVLET_HOME$/[servlet-name][/extra/path/info]</filename>
1421     
1422    </para>
1423    <para>
1424      Query parameters are supported as normal:
1425      <filename>$HOME$/[servlet-name].servlet?param1=value&amp;param2=value</filename>,
1426      <filename>$SERVLET_HOME$/[servlet-name]?param1=value&amp;param2=value</filename>
1427    </para>
1428   
1429
1430    <programlisting language="xml">
1431<![CDATA[
1432<extension
1433   id="net.sf.basedb.clients.web.menu.extensions.helloservletworld"
1434   extends="net.sf.basedb.clients.web.menu.extensions"
1435   >
1436   <index>5</index>
1437   <about>
1438      <name>Hello Servlet world</name>
1439      <description>
1440         This example uses a custom Servlet page to display the
1441         "Hello world" message instead of a javascript popup.
1442      </description>
1443   </about>
1444   <action-factory>
1445      <factory-class>
1446         net.sf.basedb.clients.web.extensions.menu.FixedMenuItemFactory
1447      </factory-class>
1448      <parameters>
1449         <title>Hello Servlet world!</title>
1450         <tooltip>Opens a Servlet generated page with the message</tooltip>
1451         <onClick>
1452           Main.openPopup('$HOME$/HelloWorld.servlet?ID=' + getSessionId(), 'HelloServletWorld', 400, 300)
1453         </onClick>
1454         <icon>~/images/servlet.png</icon>
1455      </parameters>
1456   </action-factory>
1457</extension>
1458]]>
1459</programlisting>
1460   
1461    <note>
1462      <para>
1463        To keep things as simple as possible, a new instance of the servlet
1464        class is created for each request. If the servlet needs complex or
1465        expensive initialisation, that should be externalised to other
1466        classes that the servlet can use.
1467      </para>
1468    </note>
1469   
1470  </sect1>
1471 
1472  <sect1 id="extensions_developer.base_extension_points">
1473    <?dbhtml filename="builtin.html" ?>
1474    <title>Extension points defined by BASE</title>
1475   
1476    <para>
1477      In this section, we will give an overview of the extension points defined
1478      by BASE. Most extension points are used in the web client to add
1479      buttons and menu items, but there are a few for the core API as well.
1480    </para>
1481   
1482    <sect2 id="extensions_developer.menuitems">
1483      <title>Menu: extensions</title>
1484     
1485      <para>
1486        Menu items can be added to the top-level
1487        <menuchoice><guimenu>Extensions</guimenu></menuchoice>
1488        menu. Actions should implement the interface: <interfacename 
1489        docapi="net.sf.basedb.clients.web.extensions.menu">MenuItemAction</interfacename>
1490      </para>
1491     
1492      <para>
1493        The <methodname>MenuItemAction.getMenuType()</methodname> provides support
1494        for <constant>MENUITEM</constant>, <constant>SUBMENU</constant> and
1495        <constant>SEPARATOR</constant> menus. Which of the other properties that
1496        are needed depend on the menu type. Read the javadoc for more information.
1497        This extension point doesn't support custom javascripts or stylesheets and
1498        the rendering is internal (eg. extensions can't provide their own renderers).
1499      </para>
1500     
1501      <para>
1502        BASE ships with two action factories:
1503        <classname docapi="net.sf.basedb.clients.web.extensions.menu">FixedMenuItemFactory</classname> and
1504        <classname docapi="net.sf.basedb.clients.web.extensions.menu">PermissionMenuItemFactory</classname>.
1505       
1506        The fixed factory provides a menu that is the same for all users.
1507        The permission factory can disable or hide a menu depending on the
1508        logged in user's role-based permissions. The title, icon, etc. can have
1509        different values depending on if the menu item is disabled or enabled.
1510      </para>
1511    </sect2>
1512   
1513    <sect2 id="extensions_developer.toolbars">
1514      <title>Toolbars</title>
1515      <para>
1516        Most toolbars on all list and single-item view pages can
1517        be extended with extra buttons. Actions should implement
1518        the interface: <interfacename 
1519          docapi="net.sf.basedb.clients.web.extensions.toolbar">ButtonAction</interfacename>.
1520        Button actions are very simple and only need to provide things like
1521        a title, tooltip, on-click script, etc. This extension point has
1522        support for custom javascript, stylesheets and renderers. The
1523        default renderer is <classname 
1524        docapi="net.sf.basedb.clients.web.extensions.toolbar">ToolbarButtonRendererFactory</classname>.
1525      </para>
1526
1527      <para>
1528        BASE ships with two action factories:
1529        <classname docapi="net.sf.basedb.clients.web.extensions.toolbar">FixedButtonFactory</classname> and
1530        <classname docapi="net.sf.basedb.clients.web.extensions.toolbar">PermissionButtonFactory</classname>.
1531       
1532        The fixed factory provides a toolbar button that is the same for all users.
1533        The permission factory can disable or hide a buton depending on the
1534        logged in user's role-based permissions. The title, icon, etc. can have
1535        different values depending on if the menu item is disabled or enabled.
1536      </para>
1537    </sect2>
1538
1539    <sect2 id="extensions_developer.edit_dialogs">
1540      <title>Edit dialogs</title>
1541     
1542      <para>
1543        Most item edit dialogs can be extended with additional tabs.
1544        Actions should implement the interface: <interfacename 
1545          docapi="net.sf.basedb.clients.web.extensions.tabcontrol">TabAction</interfacename>.
1546        The actions are, in principle, simple and only need to
1547        provide a title and content (HTML). The action may also provide
1548        javascripts for validation, etc. This extension point has support
1549        for custom stylesheets and javascript. Rendering is fixed and can't
1550        be overridden.
1551      </para>
1552     
1553      <para>
1554        BASE ships with two action factories:
1555        <classname docapi="net.sf.basedb.clients.web.extensions.tabcontrol">FixedTabFactory</classname> and
1556        <classname docapi="net.sf.basedb.clients.web.extensions.tabcontrol">IncludeContentTabFactory</classname>.
1557       
1558        The fixed factory provides a tab with fixed content that is the same for all users
1559        and all items. This factory is not very useful in a real scenario.
1560        The other factory provides content by including the output from another resource,
1561        eg. a JSP page, a servlet, etc. The current context is stored in a request-scoped
1562        attribute under the key given by <code>JspContext.ATTRIBUTE_KEY</code>.
1563        A JSP or servlet should use this to hook into the current flow. Here is a code example:
1564      </para>
1565     
1566      <programlisting language="java">
1567<![CDATA[
1568// Get the JspContext that was created on the main edit page
1569final JspContext jspContext = (JspContext)request.getAttribute(JspContext.ATTRIBUTE_KEY);
1570
1571// The current item is found in the context. NOTE! Can be null if a new item
1572final BasicItem item = (BasicItem)jspContext.getCurrentItem();
1573
1574// Get the DbControl and SessionControl used to handle the request (do not close!)
1575final DbControl dc = jspContext.getDbControl();
1576final SessionControl sc = dc.getSessionControl();
1577]]>
1578</programlisting>
1579
1580      <para>
1581        The extra tab need to be paired with an extension that is invoked when
1582        the edit form is saved. Each edit-dialog extension point has a corresponding
1583        on-save extension point. Actions should implement the interface: <interfacename 
1584          docapi="net.sf.basedb.clients.web.extensions.edit">OnSaveAction</interfacename>.
1585       
1586        This interface define three callback methods that BASE will call when
1587        saving an item. The <methodname>OnSaveAction.onSave()</methodname>
1588        method is called first, but not until all regular properties have been
1589        updated. If the transaction is committed the <methodname>OnSaveAction.onCommit()</methodname>
1590        method is also called, otherwise the <methodname>OnSaveAction.onRollback()</methodname>
1591        is called. The <methodname>onSave()</methodname> method can throw an exception that
1592        will be displayed to the user. The other callback method should not throw exceptions
1593        at all, since that may result in undefined behaviour and can be confusing for the user.
1594      </para>
1595    </sect2>
1596   
1597    <sect2 id="extensions_developer.bioassayset_tools">
1598      <title>Bioassay set: Tools</title>
1599      <para>
1600        The bioassay set listing for an experiment has a <guilabel>Tools</guilabel>
1601        column which can be extended by extensions. This extension point is similar
1602        to the toolbar extension points and actions should implement
1603        the interface: <interfacename 
1604          docapi="net.sf.basedb.clients.web.extensions.toolbar">ButtonAction</interfacename>.
1605      </para>
1606     
1607      <para>
1608        Note that the list can contain
1609        <classname docapi="net.sf.basedb.core">BioAssaySet</classname>,
1610        <classname docapi="net.sf.basedb.core">Transformation</classname> and
1611        <classname docapi="net.sf.basedb.core">ExtraValue</classname> items.
1612        The factory implementation need to be aware of this if it uses
1613        the <methodname>JspContext.getItem()</methodname> method to examine the
1614        current item.
1615      </para>
1616    </sect2>
1617
1618    <sect2 id="extensions_developer.bioassayset_plots">
1619      <title>Bioassay set: Overview plots</title>
1620      <para>
1621        The bioassay set page has a tab <guilabel>Overview plots</guilabel>.
1622        The contents of this tab is supposed to be some kind of images
1623        that have been generated from the data in the current bioassay set.
1624        What kind of plots that can be generated typically depends on the
1625        kind of data you have. BASE ships with an extension
1626        (<classname docapi="net.sf.basedb.clients.web.extensions">MAPlotFactory</classname>)
1627        that creates MA plots and Correction factor plots for 2-channel bioassays.
1628        Actions should implement the interface:
1629        <interfacename docapi="net.sf.basedb.clients.web.extensions.plot">OverviewPlotAction</interfacename>.
1630        A single action generates a sub-tab in the <guilabel>Overview plots</guilabel> tab.
1631        The sub-tab may contain one or more images. Each image is defined by a
1632        <interfacename docapi="net.sf.basedb.clients.web.extensions.plot">PlotGenerator</interfacename>
1633        which sets the size of the image and provides an URL to a servlet that generates
1634        the actual image. It is recommended that the servlet cache images since the
1635        data in a bioassay set never changes. The BASE core API provides a
1636        system-managed file cache that is suitable for this. Call
1637        <methodname>Application.getStaticCache()</methodname> to get a
1638        <classname docapi="net.sf.basedb.util">StaticCache</classname> instance.
1639        See the source code for the core
1640        <classname docapi="net.sf.basedb.clients.web.servlet">PlotServlet</classname>
1641        for details of how to use the cache.
1642      </para>
1643     
1644    </sect2>
1645
1646    <sect2 id="extensions_developer.services">
1647      <title>Services</title>
1648      <para>
1649        A service is a piece of code that is loaded when the BASE web
1650        server starts up. The service is then running as long as the BASE web
1651        server is running. It is possible to manually stop and start services.
1652        This extension point is different from most others in that it doesn't
1653        affects the visible interface. Since services are loaded at startup time,
1654        this also means that the context passed to ActionFactory methods will
1655        not have any <classname>ClientContext</classname> associated with it
1656        (eg. the <methodname>InvokationContext.getClientContext()</methodname>
1657        always return null). There is also no meaning for extensions to specify
1658        a <interfacename>RendererFactory</interfacename>. Service actions should
1659        implement the interface:
1660        <interfacename docapi="net.sf.basedb.clients.web.extensions.service">ServiceControllerAction</interfacename>.
1661       
1662        The interface provides <methodname>start()</methodname> and
1663        <methodname>stop()</methodname> methods for controlling the service.
1664        BASE doesn't ship with any service, but there is an FTP service
1665        available at the BASE plug-ins site: <ulink 
1666        url="http://baseplugins.thep.lu.se/wiki/net.sf.basedb.ftp">
1667        http://baseplugins.thep.lu.se/wiki/net.sf.basedb.ftp</ulink>
1668      </para>
1669     
1670    </sect2>
1671
1672    <sect2 id="extensions_developer.connection_manager">
1673      <title>Connection managers</title>
1674      <para>
1675        This extension point adds support for using external files
1676        in BASE. This is a core extension point and is available
1677        independently of the web client. Actions should implement
1678        the interface:
1679        <interfacename docapi="net.sf.basedb.util.uri">ConnectionManagerFactory</interfacename>.
1680      </para>
1681     
1682      <para>
1683        The <methodname>getDisplayName()</methodname> and <methodname>getDescription()</methodname>
1684        methods are used in the gui when a user manually selects which connection
1685        manager to use. The <methodname>supports(URI)</methodname> is used when auto-selecting
1686        a connection manager based on the URI of the resource.
1687      </para>
1688     
1689      <para>
1690        BASE ships with factory that supports HTTP and HTTPS file
1691        references: <classname 
1692        docapi="net.sf.basedb.util.uri.http">HttpConnectionManagerFactory</classname>.
1693       
1694        The BASE plug-ins site has an connection manager that support
1695        the Hadoop distributed file system (HDFS): <ulink 
1696        url="http://baseplugins.thep.lu.se/wiki/net.sf.basedb.hdfs">
1697        http://baseplugins.thep.lu.se/wiki/net.sf.basedb.hdfs</ulink>
1698      </para>
1699     
1700    </sect2>
1701
1702    <sect2 id="extensions_developer.fileset_validator">
1703      <title>Fileset validators</title>
1704     
1705      <itemizedlist>
1706        <title>See also</title>
1707        <listitem><para><xref linkend="core_api.data_in_files" /></para></listitem>
1708        <listitem><para><xref linkend="data_api.platforms" /></para></listitem>
1709      </itemizedlist>
1710 
1711      <para>
1712        In those cases where files are used to store data instead
1713        of importing it to the database, BASE can use extensions to
1714        check that the supplied files are valid and also to extract
1715        metadata from the files. For example, the
1716        <classname docapi="net.sf.basedb.util.affymetrix">CelValidationAction</classname>
1717        is used to check if a file is a valid Affymetrix CEL file and
1718        to extract data headers and the number of spots from it.
1719      </para>
1720     
1721      <para>
1722        Validation and metadata extraction actions should implement
1723        the <interfacename docapi="net.sf.basedb.util.fileset">ValidationAction</interfacename>
1724        interface. This is a core extension point and is available
1725        independently of the web client.
1726      </para>
1727     
1728      <para>
1729        This extension point is a bit more complex than most other extension
1730        points. To begin with, the factory class will be called with the
1731        owner of the file set as the current item. Eg. the
1732        <code>ClientContext.getCurrentItem()</code> should return a
1733        <interfacename docapi="net.sf.basedb.core">FileStoreEnabled</interfacename>
1734        item. It is recommended that the factory performs a pre-filtering
1735        of the items to avoid calling the actual validation code on unsupported
1736        files. For example, the <classname docapi="net.sf.basedb.util.affymetrix">CelValidationFactory</classname>
1737        will check that the item is a <classname docapi="net.sf.basedb.core">RawBioAssay</classname>
1738        item using the Affymetrix platform.
1739      </para>
1740     
1741      <para>
1742        Each file in the file set is then passed to the
1743        <methodname>ValidationAction.acceptFile(FileSetMember)</methodname>
1744        which may accept or reject the file. If the file is accepted it may
1745        be accepted for immediate validation or later validation. The latter option
1746        is useful in more complex scenarios were files need to be validated as a group.
1747        If the file is accepted the <methodname>ValidationAction.validateAndExtractMetadata()</methodname>
1748        is called, which is were the real work should happen.
1749      </para>
1750     
1751      <para>
1752        The extensions for this extension point is also called when a file is replaced
1753        or removed from the file set. The calling sequence to set up the validation is
1754        more or less the same as described above, but the last step is to
1755        call <methodname>ValidationAction.resetMetadata()</methodname> instead
1756        of <methodname>ValidationAction.validateAndExtractMetadata()</methodname>.
1757      </para>
1758
1759      <tip>
1760        <title>
1761          Use the <classname docapi="net.sf.basedb.util.fileset">SingleFileValidationAction</classname>
1762          class.
1763        </title>
1764        <para>
1765          Most validators that work on a single file at a time may find the
1766          <classname>SingleFileValidationAction</classname> class useful. Is should
1767          simplify the task of making sure that only the desired file type is
1768          validated. See the source code of the <classname 
1769          docapi="net.sf.basedb.util.affymetrix">CelValidationAction</classname>
1770          class for an example.
1771        </para>
1772      </tip>
1773     
1774    </sect2>
1775   
1776  </sect1>
1777 
1778</chapter>
Note: See TracBrowser for help on using the repository browser.