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

Last change on this file since 6685 was 6685, checked in by Nicklas Nordborg, 8 years ago

Fixes #1907: Make it possible to login with external authentication for the root user

No special treatment for the root user when logging in.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Id
File size: 97.6 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 6685 2015-01-20 08:18:41Z 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.png</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     
340      <tip>
341        <title>Start out in disabled state</title>
342       
343        <para>
344          The <sgmltag class="starttag">about</sgmltag> tag can be used to specify
345          that an extension should start out in disabled state. This can be useful
346          if there are multiple variants of an extension or if some extensions
347          are considered "advanced mode" and only should be enabled after some
348          serious thinking. To use this feature, simply set <code>&lt;about disabled="1"&gt;</code>
349          in the XML file.
350        </para>
351      </tip>
352    </para>
353   
354    <para>
355      The <sgmltag class="starttag">action-factory</sgmltag> tag is required and
356      so is the <sgmltag class="starttag">factory-class</sgmltag> subtag. It tells
357      the extension system which factory to use for creating actions. The
358      <classname docapi="net.sf.basedb.clients.web.extensions.menu">FixedMenuItemFactory</classname>
359      is a very simple factory that is shipped with BASE. This factory always creates the same
360      menu item, no matter what. Another factory for menu items is the
361      <classname docapi="net.sf.basedb.clients.web.extensions.menu">PermissionMenuItemFactory</classname>
362      which can create menu items that depends on the logged in user's permissions. It is
363      for example, possible to hide or disable the menu item if the user doesn't have enough
364      permissions. If none of the supplied factories suits you it is possible to
365      supply your own implementation. More about this later.
366    </para>
367   
368    <para>
369      The <sgmltag class="starttag">parameters</sgmltag> subtag is used to
370      provide initialisation parameters to the factory. Different factories
371      supports different parameters and you will have to check the javadoc documentation
372      for each factory to get information about which parameters that are supported.
373    </para>
374   
375    <tip>
376      <para>
377        In case the factory is poorly documented you can always assume that public
378        methods the start with <code>set</code> and take a single <classname>String</classname>
379        as an argument can be used as a parameter. The parameter tag to use should
380        be the same as the method name, minus the <code>set</code> prefix and with
381        the first letter in lowercase. For example, the method
382        <methodname>setIcon(String icon)</methodname> corresponds to the
383        <sgmltag class="starttag">icon</sgmltag> parameter.
384      </para>
385    </tip>
386   
387    <note>
388      <title>Content security policy and inline javascript</title>
389      <para>
390        In the above example <sgmltag class="starttag">onClick</sgmltag> is
391        a parameter that contains a javascript statement. In general, we recommend
392        that inline javascript is avoided due to security vulernabilities.
393        If you install the above extension, your BASE server probably display
394        a warning message about violating the <emphasis>Content security policy</emphasis>.
395        If so, you need to change the configuration to be less restricted. See
396        <xref linkend="appendix.web.xml.csp-filter" /> for more information.
397      </para>
398     
399      <para>
400        The real code examples uses a different design with pure HTML that is
401        generated dynamically and a fixed javascript file that attaches event
402        handlers when the page has been loaded and should be compatible with the
403        stricter security policy.
404      </para>
405    </note>
406   
407    <sect2 id="extensions_developer.extend_multiple">
408      <title>Extending multiple extension points with a single extension</title>
409     
410      <para>
411        A single extension can extend multiple extension points as long as their
412        action classes are compatible. This is for, for example, the case when
413        you want to add a button to more than one toolbar.       
414        To do this use the <sgmltag class="starttag">extends</sgmltag>
415        tag with multiple <sgmltag class="starttag">ref</sgmltag> tags.
416        You can skip the <sgmltag class="attribute">extends</sgmltag> 
417        attribute in the main tag.
418      </para>
419    <programlisting language="xml">
420<![CDATA[
421<extension
422   id="net.sf.basedb.clients.web.menu.extensions.history-edit"
423   >
424   <extends>
425      <ref index="2">net.sf.basedb.clients.web.tabcontrol.edit.sample</ref>
426      <ref index="2">net.sf.basedb.clients.web.tabcontrol.edit.extract</ref>
427   </extends>
428   ...
429</extension>
430]]>
431</programlisting>
432     
433      <para>
434        This is a feature of the XML format only. Behind the scenes two extensions will
435        be created (one for each extension point). The extensions will share the same
436        action and renderer factory instances. Since the id for an extension must be unique
437        a new id will be generated by combining the original id with the parts of the id's from
438        the extension points.
439      </para>
440     
441    </sect2>
442  </sect1>
443
444
445  <sect1 id="extensions_developer.factories">
446    <?dbhtml filename="factories.html" ?>
447    <title>Custom action factories</title>
448
449    <para>
450      Some times the factories shipped with BASE are not enough, and you
451      may want to provide your own factory implementation. In this case you will
452      have to create a class that implements the
453      <interfacename docapi="net.sf.basedb.util.extensions">ActionFactory</interfacename>
454      interface. Here is a very simple example that does the same as the
455      previous "Hello world" example.
456    </para>
457   
458    <programlisting language="java">
459<![CDATA[
460package net.sf.basedb.examples.extensions;
461
462import net.sf.basedb.clients.web.extensions.JspContext;
463import net.sf.basedb.clients.web.extensions.menu.MenuItemAction;
464import net.sf.basedb.clients.web.extensions.menu.MenuItemBean;
465import net.sf.basedb.util.extensions.ActionFactory;
466import net.sf.basedb.util.extensions.InvokationContext;
467
468/**
469   First example of an action factory where eveything is hardcoded.
470   @author nicklas
471*/
472public class HelloWorldFactory
473   implements ActionFactory<MenuItemAction>
474{
475
476   private MenuItemAction[] helloWorld;
477
478   // A public, no-argument constructor is required
479   public HelloWorldFactory()
480   {
481      helloWorld = new MenuItemAction[1];
482   }
483   
484   // Return true enable the extension, false to disable it
485   public boolean prepareContext(
486      InvokationContext<? super MenuItemAction> context)
487   {
488      return true;
489   }
490
491   // An extension may create one or more actions
492   public MenuItemAction[] getActions(
493      InvokationContext<? super MenuItemAction> context)
494   {
495      // This cast is always safe with the web client
496      JspContext jspContext = (JspContext)context.getClientContext();
497      if (helloWorld[0] == null)
498      {
499         MenuItemBean bean = new MenuItemBean();
500         bean.setTitle("Hello factory world!");
501         bean.setIcon(jspContext.getRoot() + "/images/info.gif");
502         // NOTE! onclick is deprected! A real implementation
503         // should bind events using to the menu using javascript
504         bean.setOnClick("alert('Hello factory world!')");
505         helloWorld[0] = bean;
506      }
507      return helloWorld;
508   }
509}
510]]>
511</programlisting>
512
513    <para>
514      And here is the XML configuration file that goes with it.
515    </para>
516
517    <programlisting language="xml">
518<![CDATA[
519<?xml version="1.0" encoding="UTF-8" ?>
520<extensions xmlns="http://base.thep.lu.se/extensions.xsd">
521   <extension
522      id="net.sf.basedb.clients.web.menu.extensions.helloworldfactory"
523      extends="net.sf.basedb.clients.web.menu.extensions"
524      >
525      <index>2</index>
526      <about>
527         <name>Hello factory world</name>
528         <description>
529            A "Hello world" variant with a custom action factory.
530            Everything is hard-coded into the factory.
531         </description>
532      </about>
533      <action-factory>
534         <factory-class>
535            net.sf.basedb.examples.extensions.HelloWorldFactory
536         </factory-class>
537      </action-factory>
538   </extension>
539</extensions>
540]]>
541</programlisting>
542   
543    <para>
544      To install this extension you need to put the compiled
545      <filename>HelloWorldFactory.class</filename> and the XML
546      file inside a JAR file. The XML file must be located at
547      <filename>META-INF/extensions.xml</filename> and the class
548      file at <filename>net/sf/basedb/examples/extensions/HelloWorldFactory.class</filename>.
549    </para>
550   
551    <para>
552      The above example is a bit artificial and we have not gained anything.
553      Instead, we have lost the ability to easily change the menu since everything is
554      now hardcoded into the factory. To change, for example the title, requires that
555      we recompile the java code. It would be more useful if we could make the factory
556      configurable with parameters. The next example will make the icon
557      and message configurable, and also include the name
558      of the currently logged in user. For example: "Greetings &lt;name of
559      logged in user&gt;!". We'll also get rid of the onclick event handler
560      and use proper event binding using javascript.
561    </para>
562   
563    <programlisting language="java">
564<![CDATA[
565package net.sf.basedb.examples.extensions;
566
567import net.sf.basedb.clients.web.extensions.AbstractJspActionFactory;
568import net.sf.basedb.clients.web.extensions.menu.MenuItemAction;
569import net.sf.basedb.clients.web.extensions.menu.MenuItemBean;
570import net.sf.basedb.core.DbControl;
571import net.sf.basedb.core.SessionControl;
572import net.sf.basedb.core.User;
573import net.sf.basedb.util.extensions.ClientContext;
574import net.sf.basedb.util.extensions.InvokationContext;
575import net.sf.basedb.util.extensions.xml.PathSetter;
576import net.sf.basedb.util.extensions.xml.VariableSetter;
577
578/**
579   Example menu item factory that creates a "Hello world" menu item
580   where the "Hello" part can be changed by the "prefix" setting in the
581   XML file, and the "world" part is dynamically replaced with the name
582   of the logged in user.
583   
584   @author nicklas
585*/
586public class HelloUserFactory
587   extends AbstractJspActionFactory<MenuItemAction>
588{
589   // The ID attribute of the <div> tag in the final HTML
590   private String id;
591 
592   // To store the URL to the icon
593   private String icon;
594   
595   // The default prefix is Hello
596   private String prefix = "Hello";
597   
598   // A public, no-argument constructor is required
599   public HelloUserFactory()
600   {}
601   
602   /**
603      Creates a menu item that displays: {prefix} {name of user}!
604   */
605   public MenuItemAction[] getActions(
606      InvokationContext<? super MenuItemAction> context)
607   {
608      String userName = getUserName(context.getClientContext());
609      MenuItemBean helloUser = new MenuItemBean();
610      helloUser.setId(id);
611      helloUser.setTitle(prefix + " " + userName + "!");
612      helloUser.setIcon(icon);
613      // Use 'dynamic' attributes for extra info that needs to be included
614      // in the HTML
615      setParameter("data-user-name", userName);
616      setParameter("data-prefix", prefix);
617      helloUser.setDynamicActionAttributesSource(this);
618      return new MenuItemAction[] { helloUser };
619   }
620
621   /**
622      Get the name of the logged in user.
623   */
624   private String getUserName(ClientContext context)
625   {
626      SessionControl sc = context.getSessionControl();
627      DbControl dc = context.getDbControl();
628      User current = User.getById(dc, sc.getLoggedInUserId());
629      return current.getName();
630   }
631   
632    /**
633      Set the ID to use for the <div> tag. This is needed
634      so that we can attach a 'click' handler to the menu item
635      with JavaScript.
636   */
637   public void setId(String id)
638   {
639      this.id = id;
640   }
641   
642   /**
643      Sets the icon to use. Path conversion is enabled.
644   */
645   @VariableSetter
646   @PathSetter
647   public void setIcon(String icon)
648   {
649      this.icon = icon;
650   }
651   
652   /**
653      Sets the prefix to use. If not set, the
654      default value is "Hello".
655   */
656   public void setPrefix(String prefix)
657   {
658      this.prefix = prefix == null ? "Hello" : prefix;
659   }
660}
661]]>
662</programlisting>
663   
664    <para>
665      The are several new parts in this factory. The first is the <methodname>getUserName()</methodname>
666      method which is called from <methodname>getActions()</methodname>. Note
667      that the <methodname>getActions()</methodname> method always create
668      a new <classname docapi="net.sf.basedb.clients.web.extensions.menu">MenuItemBean</classname>.
669      It can no longer be cached since the title and javascript code depends on
670      which user is logged in.
671    </para>
672   
673    <para>
674      The second new part is the <methodname>setId()</methodname>,
675      <methodname>setIcon()</methodname> and
676      <methodname>setPrefix()</methodname> methods.
677      The extensions system uses java reflection to find the existance of
678      the methods if <sgmltag class="starttag">id</sgmltag>,
679      <sgmltag class="starttag">icon</sgmltag> and/or
680      <sgmltag class="starttag">prefix</sgmltag> tags are present
681      in the <sgmltag class="starttag">parameters</sgmltag> tag for a factory,
682      the methods are automatically called with the value inside the tag
683      as it's argument.
684    </para>
685   
686    <para>
687      The <classname docapi="net.sf.basedb.util.extensions.xml">VariableSetter</classname> 
688      and <classname docapi="net.sf.basedb.util.extensions.xml">PathSetter</classname> 
689      annotations on the <methodname>setIcon()</methodname> are used to enable
690      "smart" convertions of the value. Note that in the
691      XML file you only have to specify <filename>/images/info.png</filename>
692      as the URL to the icon, but in the hardcoded factory you have to
693      do: <code>jspContext.getRoot() + "/images/info.png"</code>. In this case,
694      it is the <classname>PathSetter</classname> which automatically adds the
695      the JSP root directory to all URL:s starting with /. The
696      <classname>VariableSetter</classname> can do the same thing but you would have to use
697      <code>$ROOT$</code> instead. Eg. <code>$ROOT$/images/info.png</code>. The
698      <classname>PathSetter</classname> only looks at the first characteer,
699      while the <classname>VariableSetter</classname> looks in the entire string.
700    </para>
701   
702    <para>
703      The third new part is that the call to <methodname>MenuItemBean.setOnClick()</methodname>
704      has been removed. To replace the inline scripting functionality we need
705      the <methodname>MenuItemBean.setId()</methodname> call, the
706      <methodname>setParameter()</methodname> calls and the
707      <methodname>MenuItemBean.setDynamicActionAttributesSource()</methodname>
708      call. The dynamic attributes are a simple way to output data to
709      the HTML that is later needed by scripts. In this case, the generated
710      HTML may look something like this:
711    </para>
712   
713    <programlisting language="html">
714<![CDATA[
715<div id="greetings-user" data-user-name="..." data-prefix="Greetings" ... >
716...
717</div>
718]]>
719</programlisting>
720   
721    <para>
722      Here is an example of an extension configuration that can be used
723      with the new factory. Notice that the <sgmltag class="starttag">about</sgmltag>
724      tag now include <code>safe-scripts="1"</code> attribute. This is a way
725      for the devloper to tell the extensions installation wizard that the extensions
726      doesn't use any unsafe code and no warning will be displayed when installing the
727      extensions.
728    </para>
729   
730    <programlisting language="xml">
731<![CDATA[
732<extensions xmlns="http://base.thep.lu.se/extensions.xsd">
733   <extension
734      id="net.sf.basedb.clients.web.menu.extensions.hellouser"
735      extends="net.sf.basedb.clients.web.menu.extensions"
736      >
737      <index>3</index>
738      <about safe-scripts="1">
739         <name>Greetings user</name>
740         <description>
741            A "Hello world" variant with a custom action factory
742            that displays "Greetings {name of user}" instead. We also
743            make the icon configurable.
744         </description>
745      </about>
746      <action-factory>
747         <factory-class>
748            net.sf.basedb.examples.extensions.HelloUserFactory
749         </factory-class>
750         <parameters>
751          <id>greetings-user</id>
752            <prefix>Greetings</prefix>
753            <icon>/images/take_ownership.png</icon>
754            <script>~/scripts/menu-items.js</script>
755         </parameters>
756      </action-factory>
757   </extension>
758</extensions>
759]]>
760</programlisting>
761   
762    <para>
763    And the <filename>menu-items.js</filename> JavaScript file:
764    </para>
765    <programlisting language="javascript">
766<![CDATA[
767var HelloWorldMenu = function()
768{
769   var menu = {};
770
771   /**
772      Executed once when the page is loaded. Typically
773      used to bind events to fixed control elements.
774   */
775   menu.initMenuItems = function()
776   {
777      // Bind event handlers the menu items.
778      // First parameter is the ID of the menu item
779      // Second parameter is the event to react to (=click)
780      // Last parameter is the function to execute
781      Events.addEventHandler('greetings-user', 'click', menu.greetingsUser);
782   }
783
784   // Get the dynamic attributes defined in extensions.xml
785   // and generate an alert message
786   menu.greetingsUser = function(event)
787   {
788      var userName = Data.get(event.currentTarget, 'user-name');
789      var prefix = Data.get(event.currentTarget, 'prefix');
790      alert(prefix + ' ' + userName + '!');
791   }
792
793   return menu;
794}();
795
796//Register the page initializer method with the BASE core
797Doc.onLoad(HelloWorldMenu.initMenuItems);
798]]>
799</programlisting>
800   
801    <note>
802      <title>Be aware of multi-threading issues</title>
803      <para>
804        When you are creating custom action and renderer factories be
805        aware that multiple threads may use a single factory instance
806        at the same time. Action and renderer objects only needs to
807        be thread-safe if the factories re-use the same objects.
808      </para>
809    </note>
810   
811  </sect1>
812
813  <sect1 id="extensions_developer.resources">
814    <?dbhtml filename="resources.html" ?>
815    <title>Custom images, JSP files, and other resources</title>
816
817    <para>
818      Some times your extension may need other resources. It can for
819      for example be an icon, a javascript file, a JSP file or something
820      else. Fortunately this is very easy. You need to put the extension
821      in a JAR file. As usual the extension definition XML file should be
822      at <filename>META-INF/extensions.xml</filename>. Everything you put in
823      the JAR file inside the <filename>resources/</filename> directory
824      will automatically be extracted by the extension system to a directory
825      on the web server. Here is another "Hello world" example which uses a
826      custom JSP file to display the message. There is also a custom icon.
827    </para>
828   
829    <programlisting language="xml">
830<![CDATA[
831<extensions xmlns="http://base.thep.lu.se/extensions.xsd">
832   <extension
833      id="net.sf.basedb.clients.web.menu.extensions.hellojspworld"
834      extends="net.sf.basedb.clients.web.menu.extensions"
835      >
836      <index>4</index>
837      <about safe-scripts="1" safe-resources="1">
838         <name>Hello JSP world</name>
839         <description>
840            This example uses a custom JSP file to display the
841            "Hello world" message instead of a javascript popup.
842         </description>
843      </about>
844      <action-factory>
845         <factory-class>
846            net.sf.basedb.clients.web.extensions.menu.FixedMenuItemFactory
847         </factory-class>
848         <parameters>
849            <title>Hello JSP world!</title>
850            <tooltip>Opens a JSP file with the message</tooltip>
851            <data-url>$HOME$/hello_world.jsp?ID=$SESSION-ID$</data-url>
852            <data-popup>HelloJspWorld, 400, 300</data-popup>
853            <icon>~/images/world.png</icon>
854         </parameters>
855      </action-factory>
856   </extension>
857</extensions>
858]]>
859</programlisting>
860   
861    <para>
862      The JAR file should have have the following contents:
863    </para>
864   
865    <programlisting>
866META-INF/extensions.XML
867resources/hello_world.jsp
868resources/images/world.png
869</programlisting>
870   
871    <para>
872      When this extension is installed the <filename>hello_world.jsp</filename>
873      and <filename>world.png</filename> files are automatically extracted
874      to the web servers file system. Each extension is given a unique
875      <code>HOME</code> directory to make sure that extensions doesn't interfere
876      with each other. The URL to the home directory is made available in the
877      <varname>$HOME$</varname> variable. All factory settings that have
878      been annotated with the <interfacename 
879      docapi="net.sf.basedb.util.extensions.xml">VariableSetter</interfacename>
880      will have their values scanned for <code>$HOME$</code> which is replaced
881      with the real URL. It is also possible to use the <varname>$ROOT$</varname>
882      variable to get the root URL for the BASE web application. Never use
883      <code>/base/...</code> since users may install BASE into another
884      path.
885    </para>
886   
887    <para>
888      The tilde (~) in the <sgmltag class="starttag">icon</sgmltag> tag value
889      is also replaced with the <code>HOME</code> path. Note that this kind of
890      replacement is only done on factory settings that have been annotated
891      with the <classname docapi="net.sf.basedb.util.extensions.xml">PathSetter</classname>
892      annotation and is only done on the first character.
893    </para>
894   
895    <para>
896      The <code>safe-resources="1"</code> attribute in the <sgmltag class="starttag">about</sgmltag>
897      tag is used to tell BASE that all resource files doesn't use inline scripts or event handlers.
898      This is the default setting and don't have to be included. On the other hand,
899      if <code>safe-resources="0"</code> is specified BASE uses a less restrictive content
900      security policy for that extension that allows the use of inline scripts. This setting
901      is not recommended but can be useful during a transition phase while the extensions code
902      is being updated.
903    </para>
904   
905    <note>
906      <para>
907      Unfortunately, the custom JSP file can't use classes that
908      are located in the extension's JAR file. The reason is that the
909      JAR file is not known to Tomcat and Tomcat will not look in the
910      <filename>plugins.dir</filename> folder to
911      try to find classes. There are currently two possible workarounds:
912      </para>
913     
914      <itemizedlist>
915      <listitem>
916        <para>
917        Place classes needed by JSP files in a separate JAR file that
918        is installed into the <filename>WEB-INF/lib</filename> folder.
919        The drawback is that this requires a restart of Tomcat.
920        </para>
921      </listitem>
922     
923      <listitem>
924        <para>
925        Use an X-JSP file instead. This is an experimental feature. See
926        <xref linkend="extensions_developer.resources.xjsp" /> for more
927        information.
928        </para>
929      </listitem>
930      </itemizedlist>
931    </note>
932   
933    <sect2 id="extensions_developer.resources.scripts">
934      <title>Javascript and stylesheets</title>
935     
936      <para>
937        It is possible for an extension to use a custom javascript or stylesheet.
938        However, this doesn't happen automatically and may not be enabled
939        for all extension points. If an extension needs this functionality
940        the action factory or renderer factory must call
941        <methodname>JspContext.addScript()</methodname> or
942        <methodname>JspContext.addStylesheet()</methodname> from the
943        <methodname>prepareContext()</methodname> method.
944      </para>
945     
946      <para>
947        The <classname 
948        docapi="net.sf.basedb.clients.web.extensions">AbstractJspActionFactory</classname>
949        and <classname 
950        docapi="net.sf.basedb.clients.web.extensions">AbstractJspRendererFactory</classname>
951        factory can do this. All factories shipped with BASE extends one of those
952        classes and we recommend that custom-made factories also does this.
953      </para>
954     
955      <para>
956        Factories that are extending one of those two classes can use
957        <sgmltag class="starttag">script</sgmltag> and
958        <sgmltag class="starttag">stylesheet</sgmltag> tags in the
959        <sgmltag class="starttag">parameters</sgmltag> section for an
960        extensions. Each tag may be used more than one time. The
961        values are subject to path and variable substitution.
962      </para>
963     
964      <programlisting language="xml">
965<![CDATA[
966<action-factory>
967   <factory-class>
968      ... some factory class ...
969   </factory-class>
970   <parameters>
971      <script>~/scripts/custom.js</script>
972      <stylesheet>~/css/custom.css</stylesheet>
973      ... other parameters ...
974   </parameters>
975</action-factory>
976]]>
977</programlisting>
978     
979      <para>
980        If scripts and stylesheets has been added to the JSP context
981        the extension system will, <emphasis>in most cases</emphasis>,
982        include the proper HTML to link in the requested scripts and/or
983        stylesheet.
984      </para>
985     
986      <note>
987        <title>Use UTF-8 character encoding</title>
988        <para>
989          The script and stylesheet files should use use UTF-8 character encoding.
990          Otherwise they may not work as expected in BASE.
991        </para>
992      </note>
993     
994      <note>
995        <title>All extension points doesn't support custom scripts/stylesheets</title>
996        <para>
997          In some cases the rendering of the HTML page has gone to far
998          to make is possible to include custom scripts and stylesheets.
999          This is for example the case with the extensions menu. Always
1000          check the documentation for the extension point if scripts
1001          and stylesheets are supported or not.
1002        </para>
1003      </note>
1004    </sect2>
1005   
1006    <sect2 id="extensions_developer.resources.xjsp">
1007      <title>X-JSP files</title>
1008     
1009      <para>
1010        The drawback with a custom JSP file is that it is not possible to
1011        use classes from the extension's JAR file in the JSP code. The reason
1012        is that the JAR file is not known to Tomcat and Tomcat will not look
1013        in the <filename>plugins.dir</filename> folder to try to find
1014        classes.
1015      </para>
1016     
1017      <para>
1018        One workaround is to place classes that are needed by the JSP files
1019        in a separate JAR file that is placed in <filename>WEB-INF/lib</filename>.
1020        The drawback with this is that it requires a restart of Tomcat. It is
1021        also a second step that has to be performed manually by the person
1022        installing the extension and is maybe forgotten when doing an update.
1023      </para>
1024     
1025      <para>
1026        Another workaround is to use an X-JSP file. This is simply a regular
1027        JSP file that has a <code>.xjsp</code> extension instead of <code>.jsp</code>.
1028        The <code>.xjsp</code> extension will trigger the use of a different
1029        compiler that knows how to include the extension's JAR file in the class
1030        path.
1031      </para>
1032     
1033      <note>
1034        <title>X-JSP is experimental</title>
1035        <para>
1036          The X-JSP compiler depends on functionality that is internal to
1037          Tomcat. The JSP compiler is not part of any open specification
1038          and the implementation details may change at any time. This means
1039          that the X-JSP compiler may or may not work with future versions
1040          of Tomcat. We have currently tested it with Tomcat 7.0.30 only.
1041          It will most likely not work with other servlet containers.
1042        </para>
1043       
1044        <para>
1045          Adding support for X-JSP requires that a JAR file with the
1046          X-JSP compiler is installed into Tomcat's internal <filename>/lib</filename>
1047          directory. It is an optional step and not all BASE installations
1048          may have the compiler installed. See <xref linkend="plugins.installation.xjspcompiler" />.
1049        </para>
1050      </note>
1051     
1052    </sect2>
1053  </sect1>
1054 
1055  <sect1 id="extensions_developer.renderer">
1056    <?dbhtml filename="renderer.html" ?>
1057    <title>Custom renderers and renderer factories</title>
1058
1059    <para>
1060      It is always the responsibility of the extension point to
1061      render an action. The need for custom renderers is typically
1062      very small, at least if you want your extensions to blend into
1063      the look and feel of the BASE web client. Most customizations can
1064      be probably be handled by stylesheets and images. That said,
1065      you may still have a reason for using a custom renderer.
1066    </para>
1067   
1068    <para>
1069      Renderer factories are not very different from action factories.
1070      They are specified in the same way in the XML file and uses the
1071      same method for initialisation, including support for path
1072      conversion, etc. The difference is that you use a
1073      <sgmltag class="starttag">renderer-factory</sgmltag> tag
1074      instead of an <sgmltag class="starttag">action-factory</sgmltag>
1075      tag.
1076    </para>
1077
1078    <programlisting language="xml">
1079<![CDATA[
1080<renderer-factory>
1081   <factory-class>
1082      ... some factory class ...
1083   </factory-class>
1084   <parameters>
1085      ... some parameters ...
1086   </parameters>
1087</renderer-factory>
1088]]>
1089</programlisting>
1090
1091    <para>
1092      A <interfacename docapi="net.sf.basedb.util.extensions"
1093      >RendererFactory</interfacename> also has a <methodname>prepareContext()</methodname>
1094      method that can be used to tell the web client about any scripts or stylesheets
1095      the extension needs. If your renderer factory extends the <classname 
1096        docapi="net.sf.basedb.clients.web.extensions">AbstractJspRendererFactory</classname>
1097      class you will not have to worry about this since you can configure
1098      scripts and stylesheets in the XML file.
1099    </para>
1100   
1101    <para>
1102      A render factory must also implement the <methodname>getRenderer()</methodname> 
1103      which should return a <interfacename docapi="net.sf.basedb.util.extensions"
1104      >Renderer</interfacename> instance. The extension system will then call
1105      the <methodname>Renderer.render()</methodname> method to render an action.
1106      This method may be called multiple times if the extension created more than
1107      one action.
1108    </para>
1109   
1110    <para>
1111      The renderers responsibility is to generate the HTML
1112      that is going to be sent to the web client. To do this it needs
1113      access to the <classname 
1114      docapi="net.sf.basedb.clients.web.extensions">JspContext</classname> 
1115      object that was passed to the renderer factory. Here is a simple
1116      outline of both a renderer factory and renderer.
1117    </para>
1118   
1119    <programlisting language="java">
1120<![CDATA[
1121// File: MyRendererFactory.java
1122public class MyRendererFactory
1123   extends AbstractJspRendererFactory<MyAction>
1124{
1125
1126   public MyRendererFactory()
1127   {}
1128
1129   @Override
1130   public MyRenderer getRenderer(InvokationContext context)
1131   {
1132      return new MyRenderer((JspContext)context.getClientContext());
1133   }
1134}
1135
1136// File: MyRenderer.java
1137public class MyRenderer
1138   implements Renderer<MyAction>
1139{
1140
1141   private final JspContext context;
1142   public MyRenderer(JspContext context)
1143   {
1144      this.context = context;
1145   }
1146
1147   /**
1148      Generates HTML (unless invisible):
1149      <a class="[clazz]" style="[style]" href="[href]">[title]</a>
1150   */
1151   public void render(MyAction action)
1152   {
1153      if (!action.isVisible()) return;
1154      Writer out = context.getOut();
1155      try
1156      {
1157         out.write("<a");
1158         if (action.getClazz() != null)
1159         {
1160            out.write(" class=\"" + action.getClazz() + "\"");
1161         }
1162         if (action.getStyle() != null)
1163         {
1164            out.write(" style=\"" + action.getStyle() + "\"");
1165         }
1166         if (action.getHref() != null)
1167         {
1168            out.write(" href=\"" + action.getHref() + "\"");
1169         }
1170         out.write(">");
1171         out.write(HTML.encodeTags(action.getTitle()));
1172         out.write("</a>\n");
1173      }
1174      catch (IOException ex)
1175      {
1176         throw new RuntimeException(ex);
1177      }
1178   }
1179}
1180]]>
1181</programlisting>
1182  </sect1>
1183 
1184  <sect1 id="extensions_developer.extension_points">
1185    <?dbhtml filename="extensionpoints.html" ?>
1186    <title>Extension points</title>
1187   
1188    <para>
1189      The BASE web client ships with a number of predefined extension
1190      points. Adding more extension points to the existing web client
1191      requires some minor modifications to the regular JSP files. But this
1192      is not what this chapter is about. This chapter is about defining new
1193      extension points as part of an extension. It is nothing magical about
1194      this and the process is the same as for the regular extension points in
1195      the web client.
1196    </para>
1197   
1198    <para>
1199      The first thing you need to do is to start writing the
1200      XML definition of the extension point. Here is an example
1201      from the web client:
1202    </para>
1203   
1204    <programlisting language="xml">
1205<![CDATA[
1206<extensions
1207   xmlns="http://base.thep.lu.se/extensions.xsd"
1208   >
1209   <extension-point
1210      id="net.sf.basedb.clients.web.menu.extensions"
1211      >
1212      <action-class>net.sf.basedb.clients.web.extensions.menu.MenuItemAction</action-class>
1213      <name>Menu: extensions</name>
1214      <description>
1215         Extension point for adding extensions to the 'Extensions' menu.
1216         Extensions should provide MenuItemAction instances. The rendering
1217         is internal and extensions can't use their own rendering factories.
1218         The context will only include information about the currently logged
1219         in user, not information about the current page that is displayed.
1220         The reason for this is that the rendered menu is cached as a string
1221         in the user session. The menu is not updated on every page request.
1222         As of BASE 3.3, this extension point also support custom scripts and
1223         stylesheets.
1224      </description>
1225   </extension-point>
1226</extensions>
1227]]>
1228</programlisting>
1229   
1230    <para>
1231      The <sgmltag class="starttag">extensions</sgmltag> tag is the root tag and
1232      is needed to set up the namespace and schema validation.
1233    </para>
1234   
1235    <para>
1236      The <sgmltag class="starttag">extension-point</sgmltag> defines a new
1237      extension point. It must have an <sgmltag>id</sgmltag> attribute that
1238      is unique among all installed extension points. We recommend using
1239      the same naming conventions as for java packages. See <ulink 
1240      url="http://www.oracle.com/technetwork/java/codeconventions-135099.html">Java naming
1241      conventions from Oracle</ulink>.
1242    </para>
1243   
1244    <note>
1245      <title>Document the extension point!</title>
1246      <para>
1247        The <sgmltag class="starttag">name</sgmltag> and
1248        <sgmltag class="starttag">description</sgmltag> tags are optional,
1249        but we strongly recommend that values are provided.
1250        The description tag should be used to document the extension
1251        point. Pay special attention to the support (or lack of
1252        support) for custom scripts, stylesheets and renderers.
1253      </para>
1254    </note>
1255   
1256    <para>
1257      The <sgmltag class="starttag">action-class</sgmltag> defines the
1258      interface or class that extensions must provide to the extension
1259      point. This must be a class or interface that is a subclass
1260      of the <interfacename 
1261      docapi="net.sf.basedb.util.extensions">Action</interfacename>
1262      interface. We generally recommend that interfaces are used since
1263      this gives more implementation flexibility for action factories, but
1264      a regular class may work just as well.
1265    </para>
1266     
1267    <para>
1268      The action class is used to carry information about the action,
1269      such as a title, which icon to use, a tooltip text, etc. The action class may
1270      be as simple or complex as you like.
1271    </para>
1272     
1273    <note>
1274      <title>Web client extension points</title>
1275      <para>
1276        This is a note for the core developers. Extension points that
1277        are part of the web client should always define the action as
1278        an interface. We recommend that <code>getId()</code>, <code>getClazz()</code>
1279        and <code>getStyle()</code> attributes are always included if this makes
1280        sense. It is usually also a good idea to include <code>isVisible()</code>
1281        and <code>isEnabled()</code> attributes.
1282      </para>
1283    </note>
1284     
1285    <para>
1286      Now, if you are a good citizen you should also provide at least
1287      one implementation of an action factory that can create the
1288      objects of the desired type of action. The factory should
1289      of course be configurable from the XML file.
1290    </para>
1291   
1292    <para>
1293      If you are lazy or if you want to immediately start testing the JSP code
1294      for the extension point, it may be possible to use one of the debugger action
1295      factories in the <package>net.sf.basedb.util.extensions.debug</package>
1296      pacakge.
1297    </para>
1298   
1299    <itemizedlist>
1300    <listitem>
1301      <para>
1302      <classname 
1303      docapi="net.sf.basedb.util.extensions.debug">ProxyActionFactory</classname>:
1304      This action factory can only be used if your action class is an interface
1305      and all important methods starts with <code>get</code> or <code>is</code>.
1306      The proxy action factory uses Java reflection to create a dynamic
1307      proxy class in runtime. It will map all <code>getX()</code> and <code>isY()</code> 
1308      methods to retreive the values from the corresponding parameter in the XML file.
1309      For example, <methodname>getIcon()</methodname> will retrieve the value
1310      of the <sgmltag class="starttag">icon</sgmltag> tag and
1311      <methodname>isVisible()</methodname> from the <sgmltag 
1312      class="starttag">visible</sgmltag>. The factory is smart enough to convert
1313      the string to the correct return value for <type>int</type>, <type>long</type>,
1314      <type>float</type>, <type>double</type> and <type>boolean</type> data types and
1315      their corresponding object wrapper types, if this is needed.
1316      </para>
1317    </listitem>
1318   
1319    <listitem>
1320      <para>
1321      <classname 
1322      docapi="net.sf.basedb.util.extensions.debug">BeanActionFactory</classname>:
1323      This action factory can be used if you have created a bean-like
1324      class that implements the desired action class. The factory will
1325      create an instance of the class specified by the
1326      <sgmltag class="starttag">beanClass</sgmltag> parameter. The factory
1327      will then use Java reflection to find <code>set</code> method
1328      for the other parameters. If there is a parameter <sgmltag class="starttag">icon</sgmltag>
1329      the factory first looks for a <methodname>setIcon(String)</methodname>
1330      method. If it can't find that it will see if there is a <methodname>getIcon()</methodname>
1331      method which has a return type, T. If so, a second attempt is made to find
1332      a <methodname>setIcon(T)</methodname> method. The factory is smart enough
1333      to convert the string value from the XML file to the correct return value
1334       for <type>int</type>, <type>long</type>, <type>float</type>,
1335      <type>double</type> and <type>boolean</type> data types and their
1336      corresponding object wrapper types, if this is needed.
1337      </para>
1338    </listitem>
1339   
1340    </itemizedlist>
1341
1342
1343    <para>
1344      It is finally time to write the JSP code that actually uses the
1345      extension point. It is usually not very complicated. Here is
1346      an exemple which lists snippets from a JSP file:
1347    </para>
1348
1349    <programlisting>
1350<![CDATA[
1351// 1. We recommend using the extensions taglib (and the BASE core taglib)
1352<%@ taglib prefix="ext" uri="/WEB-INF/extensions.tld" %>
1353<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
1354
1355// 2. Prepare the extension point
1356SessionControl sc = Base.getExistingSessionControl(pageContext, true);
1357JspContext jspContext = ExtensionsControl.createContext(sc, pageContext);
1358ExtensionsInvoker invoker = ExtensionsControl.useExtensions(jspContext,
1359   "my.domain.name.extensionspoint");
1360
1361// 3. Output scripts and stylesheets
1362<base:page title="My new extension point">
1363   <base:head>
1364      <ext:scripts context="<%=jspContext%>" />
1365      <ext:stylesheets context="<%=jspContext%>" />
1366   </base:head>
1367   <base:body>
1368   ....
1369
1370// 4a. Using a taglib for rendering with the default renderer
1371<ext:render extensions="<%=invoker%>" context="<%=jspContext%>" />
1372
1373// 4b. Or, use the iterator and a more hard-coded approach
1374<%
1375Iterator it = invoker.iterate();
1376while (it.hasNext())
1377{
1378   MyAction action = (MyAction)it.next();
1379   String html = action.getTitle() +
1380    ....
1381   out.write(html);
1382}
1383%>
1384]]>
1385</programlisting>
1386
1387    <sect2 id="extensions_developer.error_handler">
1388      <title>Error handlers</title>
1389     
1390      <para>
1391        An extension points may define a custom error handler. If not, the
1392        default error handler is used which simply writes a message to the
1393        log file. If you want to use a different error handler, create
1394        a <sgmltag class="starttag">error-handler-factory</sgmltag> tag
1395        inside the extension point definition. The <sgmltag 
1396        class="starttag">factory-class</sgmltag> is a required subtag and
1397        must specify a class with a public no-argument constructor that
1398        implements the
1399        <interfacename docapi="net.sf.basedb.util.extensions">ErrorHandlerFactory</interfacename>
1400        interface. The <sgmltag class="starttag">parameters</sgmltag> subtag is
1401        optional and can be used to specify initialization parameters for the
1402        factory just as for action and renderer factories.
1403      </para>
1404
1405      <programlisting language="xml">
1406<![CDATA[
1407<extensions
1408   xmlns="http://base.thep.lu.se/extensions.xsd"
1409   >
1410   <extension-point
1411      id="net.sf.basedb.clients.web.menu.extensions"
1412      >
1413      <action-class>net.sf.basedb.clients.web.extensions.menu.MenuItemAction</action-class>
1414      <name>Menu: extensions</name>
1415      <error-handler-factory>
1416         <factory-class>
1417            ... some factory class ...
1418         </factory-class>
1419         <parameters>
1420            ... initialization parameters ...
1421         </parameters>
1422      </error-handler-factory>
1423   </extension-point>
1424</extensions>
1425]]>
1426</programlisting>
1427    </sect2>
1428  </sect1>
1429 
1430  <sect1 id="extensions_developer.servlets">
1431    <?dbhtml filename="servlets.html" ?>
1432    <title>Custom servlets</title>
1433    <para>
1434      It is possible for an extension to include servlets without having
1435      to register those servlets in Tomcat's <filename>WEB-INF/web.xml</filename>
1436      file. The extension needs to be in a JAR file as usual. The servlet class
1437      should be located in the JAR file following regular Java conventions.
1438      Eg. The class <classname>my.domain.ServletClass</classname> should
1439      be located at <filename>my/domain/ServletClass.class</filename>. You
1440      also need to create a second XML file that contains the servlet
1441      definitions at <filename>META-INF/servlets.xml</filename>. The format for
1442      defining servlets in this file is very similar to how servlets are
1443      defined in the <filename>web.xml</filename> file. Here is an example:
1444    </para>
1445   
1446    <programlisting language="xml">
1447<![CDATA[
1448<?xml version="1.0" encoding="UTF-8" ?>
1449<servlets xmlns="http://base.thep.lu.se/servlets.xsd">
1450   <servlet>
1451      <servlet-name>HelloWorld</servlet-name>
1452      <servlet-class>net.sf.basedb.examples.extensions.HelloWorldServlet</servlet-class>
1453      <init-param>
1454         <param-name>template</param-name>
1455         <param-value>Hello {user}! Welcome to the Servlet world!</param-value>
1456      </init-param>
1457   </servlet>
1458</servlets>
1459]]>
1460</programlisting>
1461
1462    <para>
1463      The <sgmltag class="starttag">servlets</sgmltag> tag is the root tag and is
1464      needed to set up the namespace and schema validation. This may contain
1465      any number of <sgmltag class="starttag">servlet</sgmltag> tags, each one
1466      defining a single servlet.
1467    </para>
1468   
1469    <para>
1470      The <sgmltag class="starttag">servlet-name</sgmltag> tag contains the name
1471      of the servlet. This is a required tag and must be unique among the servlets
1472      defined by this extension. Other extensions may use the same name without any
1473      problems.
1474    </para>
1475   
1476    <para>
1477      The <sgmltag class="starttag">servlet-class</sgmltag> tag contains the name
1478      of implementing class. This is required and the class must implement
1479      the <interfacename>Servlet</interfacename> interface and have a public,
1480      no-argument constructor. We recommend that servlet implementations instead
1481      extends the <classname>HttpServlet</classname> class. This will make the
1482      servlet programming easier.
1483    </para>
1484   
1485    <para>
1486      A servlet may have any number <sgmltag class="starttag">init-param</sgmltag>
1487      tags, containing initialisation parameters for the servlet. Here is the
1488      code for the servlet references in the above example.
1489    </para>
1490
1491    <programlisting language="java">
1492<![CDATA[
1493public class HelloWorldServlet
1494   extends HttpServlet
1495{
1496   private String template;
1497   public HelloWorldServlet()
1498   {}
1499
1500   @Override
1501   public void init()
1502      throws ServletException
1503   {
1504      ServletConfig cfg = getServletConfig();
1505      template = cfg.getInitParameter("template");
1506      if (template == null) template = "Hello {user}.";
1507   }
1508
1509   @Override
1510   protected void doGet(HttpServletRequest request, HttpServletResponse response)
1511      throws ServletException, IOException
1512   {
1513      final SessionControl sc = Base.getExistingSessionControl(request, true);
1514      final DbControl dc = sc.newDbControl();
1515      try
1516      {
1517         User current = User.getById(dc, sc.getLoggedInUserId());
1518         PrintWriter out = response.getWriter();
1519         out.print(template.replace("{user}", current.getName()));
1520      }
1521      finally
1522      {
1523         if (dc != null) dc.close();
1524      }
1525   }
1526   @Override
1527   protected void doPost(HttpServletRequest req, HttpServletResponse resp)
1528      throws ServletException, IOException
1529   {
1530      doGet(req, resp);
1531   }
1532}
1533]]>
1534</programlisting>
1535
1536    <para>
1537      Invoking the servlet is done with a URL that is constructed like:
1538      <filename>$HOME$/[servlet-name].servlet</filename>, where <code>$HOME$</code>
1539      is the home directory of the extension. An alternate URL
1540      that doesn't require the <filename>.servlet</filename> extension is available:
1541      <filename>$SERVLET_HOME$/[servlet-name]</filename>, where <code>$SERVLET_HOME$</code>
1542      is the home directory of servlets for the extension. Note that this
1543      directory is on a different sub-path than the <code>$HOME$</code> directory.
1544    </para>
1545    <para>
1546      Extra path information is supported
1547      if it is inserted between the servlet name and the <filename>.servlet</filename>
1548      extension: <filename>$HOME$/[servlet-name][/extra/path/info].servlet</filename>,
1549      <filename>$SERVLET_HOME$/[servlet-name][/extra/path/info]</filename>
1550     
1551    </para>
1552    <para>
1553      Query parameters are supported as normal:
1554      <filename>$HOME$/[servlet-name].servlet?param1=value&amp;param2=value</filename>,
1555      <filename>$SERVLET_HOME$/[servlet-name]?param1=value&amp;param2=value</filename>
1556    </para>
1557   
1558
1559    <programlisting language="xml">
1560<![CDATA[
1561<extension
1562   id="net.sf.basedb.clients.web.menu.extensions.helloservletworld"
1563   extends="net.sf.basedb.clients.web.menu.extensions"
1564   >
1565   <index>5</index>
1566   <about>
1567      <name>Hello Servlet world</name>
1568      <description>
1569         This example uses a custom Servlet page to display the
1570         "Hello world" message instead of a javascript popup.
1571      </description>
1572   </about>
1573   <action-factory>
1574      <factory-class>
1575         net.sf.basedb.clients.web.extensions.menu.FixedMenuItemFactory
1576      </factory-class>
1577      <parameters>
1578         <title>Hello Servlet world!</title>
1579         <tooltip>Opens a Servlet generated page with the message</tooltip>
1580         <data-url>$HOME$/HelloWorld.servlet?ID=$SESSION-ID$</data-url>
1581         <data-popup>HelloServletWorld, 400, 300</data-popup>
1582         <icon>~/images/servlet.png</icon>
1583      </parameters>
1584   </action-factory>
1585</extension>
1586]]>
1587</programlisting>
1588   
1589    <note>
1590      <para>
1591        To keep things as simple as possible, a new instance of the servlet
1592        class is created for each request. If the servlet needs complex or
1593        expensive initialisation, that should be externalised to other
1594        classes that the servlet can use.
1595      </para>
1596    </note>
1597   
1598  </sect1>
1599 
1600  <sect1 id="extensions_developer.base_extension_points">
1601    <?dbhtml filename="builtin.html" ?>
1602    <title>Extension points defined by BASE</title>
1603   
1604    <para>
1605      In this section, we will give an overview of the extension points defined
1606      by BASE. Most extension points are used in the web client to add
1607      buttons and menu items, but there are a few for the core API as well.
1608    </para>
1609   
1610    <sect2 id="extensions_developer.menuitems">
1611      <title>Menu: extensions</title>
1612     
1613      <para>
1614        Menu items can be added to the top-level
1615        <menuchoice><guimenu>Extensions</guimenu></menuchoice>
1616        menu. Actions should implement the interface: <interfacename 
1617        docapi="net.sf.basedb.clients.web.extensions.menu">MenuItemAction</interfacename>
1618      </para>
1619     
1620      <para>
1621        The <methodname>MenuItemAction.getMenuType()</methodname> provides support
1622        for <constant>MENUITEM</constant>, <constant>SUBMENU</constant> and
1623        <constant>SEPARATOR</constant> menus. Which of the other properties that
1624        are needed depend on the menu type. Read the javadoc for more information.
1625        The rendering is internal (eg. extensions can't provide their own renderers).
1626      </para>
1627     
1628      <para>
1629        BASE ships with two action factories:
1630        <classname docapi="net.sf.basedb.clients.web.extensions.menu">FixedMenuItemFactory</classname> and
1631        <classname docapi="net.sf.basedb.clients.web.extensions.menu">PermissionMenuItemFactory</classname>.
1632       
1633        The fixed factory provides a menu that is the same for all users.
1634        The permission factory can disable or hide a menu depending on the
1635        logged in user's role-based permissions. The title, icon, etc. can have
1636        different values depending on if the menu item is disabled or enabled.
1637      </para>
1638     
1639      <note>
1640        <title>onclick is deprecated</title>
1641        <para>
1642          The onclick attribute has been deprecated since BASE 3.3. Use a custom script instead to
1643          bind the click event with the menu item or <sgmltag class="starttag">data-url</sgmltag>
1644          if the menu simply navigates to another page. <sgmltag class="starttag">data-popup</sgmltag> 
1645          can be used to open the page in a popup window and should contain three comma-separated
1646          values: name-of-window, width-of-window, height-of-window
1647        </para>
1648      </note>
1649    </sect2>
1650   
1651    <sect2 id="extensions_developer.toolbars">
1652      <title>Toolbars</title>
1653      <para>
1654        Most toolbars on all list and single-item view pages can
1655        be extended with extra buttons. Actions should implement
1656        the interface: <interfacename 
1657          docapi="net.sf.basedb.clients.web.extensions.toolbar">ButtonAction</interfacename>.
1658        Button actions are very simple and only need to provide things like
1659        a title, tooltip, icon, etc. This extension point has
1660        support for custom javascript, stylesheets and renderers. The
1661        default renderer is <classname 
1662        docapi="net.sf.basedb.clients.web.extensions.toolbar">ToolbarButtonRendererFactory</classname>.
1663      </para>
1664
1665      <para>
1666        BASE ships with two action factories:
1667        <classname docapi="net.sf.basedb.clients.web.extensions.toolbar">FixedButtonFactory</classname> and
1668        <classname docapi="net.sf.basedb.clients.web.extensions.toolbar">PermissionButtonFactory</classname>.
1669       
1670        The fixed factory provides a toolbar button that is the same for all users.
1671        The permission factory can disable or hide a buton depending on the
1672        logged in user's role-based permissions. The title, icon, etc. can have
1673        different values depending on if the menu item is disabled or enabled.
1674      </para>
1675     
1676      <note>
1677        <title>onclick is deprecated</title>
1678        <para>
1679          The onclick attribute has been deprecated since BASE 3.3. Use a custom script instead to
1680          bind the click event with the button. Download the example code to see it in action.
1681        </para>
1682      </note>
1683     
1684    </sect2>
1685
1686    <sect2 id="extensions_developer.edit_dialogs">
1687      <title>Edit dialogs</title>
1688     
1689      <para>
1690        Most item edit dialogs can be extended with additional tabs.
1691        Actions should implement the interface: <interfacename 
1692          docapi="net.sf.basedb.clients.web.extensions.tabcontrol">TabAction</interfacename>.
1693        The actions are, in principle, simple and only need to
1694        provide a title and content (HTML). The action may also provide
1695        javascripts for validation, etc. This extension point has support
1696        for custom stylesheets and javascript. Rendering is fixed and can't
1697        be overridden.
1698      </para>
1699     
1700      <para>
1701        BASE ships with two action factories:
1702        <classname docapi="net.sf.basedb.clients.web.extensions.tabcontrol">FixedTabFactory</classname> and
1703        <classname docapi="net.sf.basedb.clients.web.extensions.tabcontrol">IncludeContentTabFactory</classname>.
1704       
1705        The fixed factory provides a tab with fixed content that is the same for all users
1706        and all items. This factory is not very useful in a real scenario.
1707        The other factory provides content by including the output from another resource,
1708        eg. a JSP page, a servlet, etc. The current context is stored in a request-scoped
1709        attribute under the key given by <code>JspContext.ATTRIBUTE_KEY</code>.
1710        A JSP or servlet should use this to hook into the current flow. Here is a code example:
1711      </para>
1712     
1713      <programlisting language="java">
1714<![CDATA[
1715// Get the JspContext that was created on the main edit page
1716final JspContext jspContext = (JspContext)request.getAttribute(JspContext.ATTRIBUTE_KEY);
1717
1718// The current item is found in the context. NOTE! Can be null if a new item
1719final BasicItem item = (BasicItem)jspContext.getCurrentItem();
1720
1721// Get the DbControl and SessionControl used to handle the request (do not close!)
1722final DbControl dc = jspContext.getDbControl();
1723final SessionControl sc = dc.getSessionControl();
1724]]>
1725</programlisting>
1726
1727      <para>
1728        The extra tab need to be paired with an extension that is invoked when
1729        the edit form is saved. Each edit-dialog extension point has a corresponding
1730        on-save extension point. Actions should implement the interface: <interfacename 
1731          docapi="net.sf.basedb.clients.web.extensions.edit">OnSaveAction</interfacename>.
1732       
1733        This interface define three callback methods that BASE will call when
1734        saving an item. The <methodname>OnSaveAction.onSave()</methodname>
1735        method is called first, but not until all regular properties have been
1736        updated. If the transaction is committed the <methodname>OnSaveAction.onCommit()</methodname>
1737        method is also called, otherwise the <methodname>OnSaveAction.onRollback()</methodname>
1738        is called. The <methodname>onSave()</methodname> method can throw an exception that
1739        will be displayed to the user. The other callback method should not throw exceptions
1740        at all, since that may result in undefined behaviour and can be confusing for the user.
1741      </para>
1742    </sect2>
1743   
1744    <sect2 id="extensions_developer.bioassayset_tools">
1745      <title>Bioassay set: Tools</title>
1746      <para>
1747        The bioassay set listing for an experiment has a <guilabel>Tools</guilabel>
1748        column which can be extended by extensions. This extension point is similar
1749        to the toolbar extension points and actions should implement
1750        the interface: <interfacename 
1751          docapi="net.sf.basedb.clients.web.extensions.toolbar">ButtonAction</interfacename>.
1752      </para>
1753     
1754      <para>
1755        Note that the list can contain
1756        <classname docapi="net.sf.basedb.core">BioAssaySet</classname>,
1757        <classname docapi="net.sf.basedb.core">Transformation</classname> and
1758        <classname docapi="net.sf.basedb.core">ExtraValue</classname> items.
1759        The factory implementation need to be aware of this if it uses
1760        the <methodname>JspContext.getItem()</methodname> method to examine the
1761        current item.
1762      </para>
1763    </sect2>
1764
1765    <sect2 id="extensions_developer.bioassayset_plots">
1766      <title>Bioassay set: Overview plots</title>
1767      <para>
1768        The bioassay set page has a tab <guilabel>Overview plots</guilabel>.
1769        The contents of this tab is supposed to be some kind of images
1770        that have been generated from the data in the current bioassay set.
1771        What kind of plots that can be generated typically depends on the
1772        kind of data you have. BASE ships with an extension
1773        (<classname docapi="net.sf.basedb.clients.web.extensions">MAPlotFactory</classname>)
1774        that creates MA plots and Correction factor plots for 2-channel bioassays.
1775        Actions should implement the interface:
1776        <interfacename docapi="net.sf.basedb.clients.web.extensions.plot">OverviewPlotAction</interfacename>.
1777        A single action generates a sub-tab in the <guilabel>Overview plots</guilabel> tab.
1778        The sub-tab may contain one or more images. Each image is defined by a
1779        <interfacename docapi="net.sf.basedb.clients.web.extensions.plot">PlotGenerator</interfacename>
1780        which sets the size of the image and provides an URL to a servlet that generates
1781        the actual image. It is recommended that the servlet cache images since the
1782        data in a bioassay set never changes. The BASE core API provides a
1783        system-managed file cache that is suitable for this. Call
1784        <methodname>Application.getStaticCache()</methodname> to get a
1785        <classname docapi="net.sf.basedb.util">StaticCache</classname> instance.
1786        See the source code for the core
1787        <classname docapi="net.sf.basedb.clients.web.servlet">PlotServlet</classname>
1788        for details of how to use the cache.
1789      </para>
1790     
1791    </sect2>
1792
1793    <sect2 id="extensions_developer.services">
1794      <title>Services</title>
1795      <para>
1796        A service is a piece of code that is loaded when the BASE web
1797        server starts up. The service is then running as long as the BASE web
1798        server is running. It is possible to manually stop and start services.
1799        This extension point is different from most others in that it doesn't
1800        affects the visible interface. Since services are loaded at startup time,
1801        this also means that the context passed to <interfacename>ActionFactory</interfacename> 
1802        methods will have a special <classname>ClientContext</classname> associated with it.
1803        There is no current item, and no user is logged in. However, the <classname>SessionControl</classname>
1804        returned from <methodname>ClientContext.getSessionControl()</methodname> gives
1805        permission to imporsonate another making it possible for the extension
1806        to access the BASE database almost without limitation. There is no meaning for
1807        extensions to specify a <interfacename>RendererFactory</interfacename>. Service
1808        actions should implement the interface:
1809        <interfacename docapi="net.sf.basedb.clients.web.extensions.service">ServiceControllerAction</interfacename>.
1810       
1811        The interface provides <methodname>start()</methodname> and
1812        <methodname>stop()</methodname> methods for controlling the service.
1813        BASE doesn't ship with any service, but there is an FTP service
1814        available at the BASE plug-ins site: <ulink 
1815        url="http://baseplugins.thep.lu.se/wiki/net.sf.basedb.ftp">
1816        http://baseplugins.thep.lu.se/wiki/net.sf.basedb.ftp</ulink>
1817      </para>
1818     
1819    </sect2>
1820
1821    <sect2 id="extensions_developer.connection_manager">
1822      <title>Connection managers</title>
1823      <para>
1824        This extension point adds support for using external files
1825        in BASE. This is a core extension point and is available
1826        independently of the web client. Actions should implement
1827        the interface:
1828        <interfacename docapi="net.sf.basedb.util.uri">ConnectionManagerFactory</interfacename>.
1829      </para>
1830     
1831      <para>
1832        The <methodname>getDisplayName()</methodname> and <methodname>getDescription()</methodname>
1833        methods are used in the gui when a user manually selects which connection
1834        manager to use. The <methodname>supports(URI)</methodname> is used when auto-selecting
1835        a connection manager based on the URI of the resource.
1836      </para>
1837     
1838      <para>
1839        BASE ships with factory that supports HTTP and HTTPS file
1840        references: <classname 
1841        docapi="net.sf.basedb.util.uri.http">HttpConnectionManagerFactory</classname>.
1842       
1843        The BASE plug-ins site has an connection manager that support
1844        the Hadoop distributed file system (HDFS): <ulink 
1845        url="http://baseplugins.thep.lu.se/wiki/net.sf.basedb.hdfs">
1846        http://baseplugins.thep.lu.se/wiki/net.sf.basedb.hdfs</ulink>
1847      </para>
1848     
1849    </sect2>
1850
1851    <sect2 id="extensions_developer.fileset_validator">
1852      <title>Fileset validators</title>
1853     
1854      <itemizedlist>
1855        <title>See also</title>
1856        <listitem><para><xref linkend="core_api.data_in_files" /></para></listitem>
1857        <listitem><para><xref linkend="data_api.platforms" /></para></listitem>
1858      </itemizedlist>
1859 
1860      <para>
1861        In those cases where files are used to store data instead
1862        of importing it to the database, BASE can use extensions to
1863        check that the supplied files are valid and also to extract
1864        metadata from the files. For example, the
1865        <classname docapi="net.sf.basedb.util.affymetrix">CelValidationAction</classname>
1866        is used to check if a file is a valid Affymetrix CEL file and
1867        to extract data headers and the number of spots from it.
1868      </para>
1869     
1870      <para>
1871        Validation and metadata extraction actions should implement
1872        the <interfacename docapi="net.sf.basedb.util.fileset">ValidationAction</interfacename>
1873        interface. This is a core extension point and is available
1874        independently of the web client.
1875      </para>
1876     
1877      <para>
1878        This extension point is a bit more complex than most other extension
1879        points. To begin with, the factory class will be called with the
1880        owner of the file set as the current item. Eg. the
1881        <code>ClientContext.getCurrentItem()</code> should return a
1882        <interfacename docapi="net.sf.basedb.core">FileStoreEnabled</interfacename>
1883        item. It is recommended that the factory performs a pre-filtering
1884        of the items to avoid calling the actual validation code on unsupported
1885        files. For example, the <classname docapi="net.sf.basedb.util.affymetrix">CelValidationFactory</classname>
1886        will check that the item is a <classname docapi="net.sf.basedb.core">RawBioAssay</classname>
1887        item using the Affymetrix platform.
1888      </para>
1889     
1890      <para>
1891        Each file in the file set is then passed to the
1892        <methodname>ValidationAction.acceptFile(FileSetMember)</methodname>
1893        which may accept or reject the file. If the file is accepted it may
1894        be accepted for immediate validation or later validation. The latter option
1895        is useful in more complex scenarios were files need to be validated as a group.
1896        If the file is accepted the <methodname>ValidationAction.validateAndExtractMetadata()</methodname>
1897        is called, which is were the real work should happen.
1898      </para>
1899     
1900      <para>
1901        The extensions for this extension point is also called when a file is replaced
1902        or removed from the file set. The calling sequence to set up the validation is
1903        more or less the same as described above, but the last step is to
1904        call <methodname>ValidationAction.resetMetadata()</methodname> instead
1905        of <methodname>ValidationAction.validateAndExtractMetadata()</methodname>.
1906      </para>
1907
1908      <tip>
1909        <title>
1910          Use the <classname docapi="net.sf.basedb.util.fileset">SingleFileValidationAction</classname>
1911          class.
1912        </title>
1913        <para>
1914          Most validators that work on a single file at a time may find the
1915          <classname>SingleFileValidationAction</classname> class useful. Is should
1916          simplify the task of making sure that only the desired file type is
1917          validated. See the source code of the <classname 
1918          docapi="net.sf.basedb.util.affymetrix">CelValidationAction</classname>
1919          class for an example.
1920        </para>
1921      </tip>
1922     
1923    </sect2>
1924 
1925    <sect2 id="extensions_developer.logging">
1926      <title>Logging managers</title>
1927     
1928      <para>
1929        This extension point makes it possible to detect changes that are made to
1930        item and generate log entries in real time. The core will send notifications
1931        for all item creations, updates and deletions to all registered logging
1932        managers. It is up to each implementation to decide if an event should be
1933        logged, where to log it and how much information that should be stored.
1934        The BASE core provides a logging implementation that save some information
1935        to the database which can also be viewed through the web interface.
1936      </para>
1937     
1938      <para>
1939        The logging mechanism works on the data layer level and hooks into
1940        callbacks provided by Hibernate. <interfacename 
1941        docapi="net.sf.basedb.core.log">EntityLogger</interfacename>:s are used to
1942        extract relevant information from Hibernate and create log entries.
1943        While it is possible to have a generic logger it is usually better
1944        to have different implementations depending on the type of entity that
1945        was changed. For example, a change in a child item should, for usability
1946        reasons, be logged as a change in the parent item. Entity loggers
1947        are created by a <interfacename 
1948        docapi="net.sf.basedb.core.log">LogManagerFactory</interfacename>. All changes
1949        made in a single transaction are usually collected by a <interfacename 
1950        docapi="net.sf.basedb.core.log">LogManager</interfacename> which is also
1951        created by the factory.
1952      </para>
1953     
1954      <sect3 id="extensions_developer.logging.factory">
1955        <title>The LogManagerFactory interface</title>
1956       
1957        <para>
1958          Each registered action factory shoulds create a <interfacename 
1959          docapi="net.sf.basedb.core.log">LogManagerFactory</interfacename> 
1960          that is used throughout a single transaction. If the factory is
1961          thread-safe, the same instance can be re-used for multiple requests
1962          at the same time. Here is a list of
1963          the methods the factory must implement:
1964        </para>
1965       
1966        <variablelist>
1967          <varlistentry>
1968            <term>
1969              <methodsynopsis language="java">
1970                <modifier>public</modifier>
1971                <type>LogManager</type>
1972                <methodname>getLogManager</methodname>
1973                <methodparam>
1974                  <type>LogControl</type>
1975                  <parameter>logControl</parameter>
1976                </methodparam>
1977              </methodsynopsis>
1978            </term>
1979            <listitem>
1980              <para>
1981              Creates a log manager for a single transaction. Since a transaction
1982              is not thread-safe the log manager implementation doesn't have to
1983              be either. The factory has the possibility to create new log managers
1984              for each transaction.
1985              </para>
1986            </listitem>
1987          </varlistentry>
1988         
1989          <varlistentry>
1990            <term>
1991              <methodsynopsis language="java">
1992                <modifier>public</modifier>
1993                <type>boolean</type>
1994                <methodname>isLoggable</methodname>
1995                <methodparam>
1996                  <type>Object</type>
1997                  <parameter>entity</parameter>
1998                </methodparam>
1999              </methodsynopsis>
2000            </term>
2001            <listitem>
2002              <para>
2003              Checks if changes to the given entity should be
2004              logged or not. For performance reasons, it usually makes sense to
2005              not log everything. For example, the database logger implementation
2006              only logs changes if the entity implements the <interfacename 
2007              docapi="net.sf.basedb.core.data">LoggableData</interfacename>
2008              interface. The return value of this method should be consistent
2009              with <methodname>getEntityLogger()</methodname>.
2010              </para>
2011            </listitem>
2012          </varlistentry>
2013
2014          <varlistentry>
2015            <term>
2016              <methodsynopsis language="java">
2017                <modifier>public</modifier>
2018                <type>EntityLogger</type>
2019                <methodname>getEntityLogger</methodname>
2020                <methodparam>
2021                  <type>LogManager</type>
2022                  <parameter>logManager</parameter>
2023                </methodparam>
2024                <methodparam>
2025                  <type>Object</type>
2026                  <parameter>entity</parameter>
2027                </methodparam>
2028              </methodsynopsis>
2029            </term>
2030            <listitem>
2031              <para>
2032              Create or get an entity logger that knows how to log
2033              changes to the given entity. If the entity should not be
2034              logged, <constant>null</constant> can be returned. This method
2035              is called for each modified item in the transaction.
2036              </para>
2037            </listitem>
2038          </varlistentry>
2039        </variablelist>
2040       
2041      </sect3>
2042     
2043      <sect3 id="extensions_developer.logging.manager">
2044        <title>The LogManager interface</title>
2045       
2046        <para>
2047          A new log manager is created for each transaction. The log manager
2048          is responsible for collecting all changes made in the transaction
2049          and store those changes in the appropriate place. The interface doesn't define
2050          any methods for this collection, since each implementation may have
2051          very different needs.
2052        </para>
2053       
2054        <variablelist>
2055          <varlistentry>
2056            <term>
2057              <methodsynopsis language="java">
2058                <modifier>public</modifier>
2059                <type>LogControl</type>
2060                <methodname>getLogControl</methodname>
2061              </methodsynopsis>
2062            </term>
2063            <listitem>
2064              <para>
2065              Get the log control object that was supplied by the BASE core
2066              when the transaction was started. The log controller contains
2067              methods for accessing information about the transaction, such
2068              as the logged in user, executing plug-in, etc. It can also
2069              be used to execute queries against the database to get
2070              even more information.
2071              </para>
2072             
2073              <warning>
2074                <para>
2075                  Be careful about the queries that are executed by the log
2076                  controller. Since all logging code is executed at flush
2077                  time in callbacks from Hibernate we are not allowed to
2078                  use the regular session. Instead, all queries are sent
2079                  through the stateless session. The stateless session has no
2080                  caching functionality which means that Hibernate will use
2081                  extra queries to load associations. Our recommendation is
2082                  to avoid quires that return full entities, use scalar
2083                  queries instead to just load the values that are needed.
2084                </para>
2085              </warning>
2086            </listitem>
2087          </varlistentry>
2088          <varlistentry>
2089            <term>
2090              <methodsynopsis language="java">
2091                <modifier>public</modifier>
2092                <void/>
2093                <methodname>afterCommit</methodname>
2094              </methodsynopsis>
2095            </term>
2096            <term>
2097              <methodsynopsis language="java">
2098                <modifier>public</modifier>
2099                <void/>
2100                <methodname>afterRollback</methodname>
2101              </methodsynopsis>
2102            </term>
2103            <listitem>
2104              Called after a successful commit or after a rollback. Note
2105              that the connection to the database has been closed at this
2106              time and it is not possible to save any more information to
2107              it at this time.
2108            </listitem>
2109          </varlistentry>
2110        </variablelist>
2111      </sect3>
2112
2113      <sect3 id="extensions_developer.logging.entitylogger">
2114        <title>The EntityLogger interface</title>
2115       
2116        <para>
2117          An entity logger is responsible for extracting the changes
2118          made to an entity and converting it to something that is useful
2119          as a log entry. In most cases, this is not very complicated, but
2120          in some cases, a change in one entity should actually be logged
2121          as a change in a different entity. For example, changes to
2122          annotations are handled by the <classname 
2123          docapi="net.sf.basedb.core.log.db">AnnotationLogger</classname> which
2124          which log it as a change on the parent item.
2125        </para>
2126       
2127        <variablelist>
2128          <varlistentry>
2129            <term>
2130              <methodsynopsis language="java">
2131                <modifier>public</modifier>
2132                <void/>
2133                <methodname>logChanges</methodname>
2134                <methodparam>
2135                  <type>LogManager</type>
2136                  <parameter>logManager</parameter>
2137                </methodparam>
2138                <methodparam>
2139                  <type>EntityDetails</type>
2140                  <parameter>details</parameter>
2141                </methodparam>
2142              </methodsynopsis>
2143            </term>
2144            <listitem>
2145              <para>
2146              This method is called whenever a change has been detected
2147              in an entity. The <varname>details</varname> variable contains
2148              information about the entity and, to a certain degree,
2149              what changes that has been made.
2150              </para>
2151            </listitem>
2152          </varlistentry>
2153        </variablelist>
2154      </sect3>
2155     
2156    </sect2>
2157 
2158 
2159    <sect2 id="extensions_developer.overview_loader">
2160      <title>Item overview loaders</title>
2161     
2162      <para>
2163        The item overview functionality allow extensions to load more items in the tree
2164        structure. The extension point is a core extension point that is available
2165        independently of the web client. Actions should implement the
2166        <interfacename docapi="net.sf.basedb.util.overview.extensions">ChildNodeLoaderAction</interfacename>
2167        interface. We recommend that the actions also extend the
2168        <classname docapi="net.sf.basedb.util.overview.loader">BasicItemNodeLoader</classname>
2169        since this will make it easier to handle situations with missing items, permission
2170        problems and validation. Since each registered extension is checked for each item
2171        in the overview we recommend that the action factory makes a first filtering step
2172        before an action is created. This should be relatively simple since the current
2173        item in the <classname>ClientContext</classname> is the parent node. For example:
2174      </para>
2175     
2176      <programlisting language="java">
2177<![CDATA[
2178// From the ActionFactory interface
2179public boolean prepareContext(InvokationContext<? super ChildNodeLoaderAction> context)
2180{
2181   Node parentNode = (Node)context.getClientContext().getCurrentItem();
2182   if (parentNode != null)
2183   {
2184      if (parentNode.getItem() instanceof Ownable)
2185      {
2186         return true;
2187      }
2188   }
2189   return false;
2190}
2191]]>
2192</programlisting>
2193     
2194    </sect2>
2195   
2196    <sect2 id="extensions_developer.overview_validator">
2197      <title>Item overview validation</title>
2198     
2199      <para>
2200        The item overview functionality allow extensions to add validation code
2201        to any item in the tree. There are two co-existing extension points, one
2202        for the actual validation code and one for the validation rule defintions.
2203        Both extension points are core extension points that is available
2204        independently of the web client. Validation actions should implement the
2205        <interfacename docapi="net.sf.basedb.util.overview.extensions">NodeValidatorAction</interfacename>
2206        interface, which is simple the same as <interfacename docapi="net.sf.basedb.util.overview.validator">NodeValidator</interfacename>
2207        We recommend that the actions extend the
2208        <classname docapi="net.sf.basedb.util.overview.validator">NameableNodeValidator</classname>
2209        or <classname docapi="net.sf.basedb.util.overview.validator">BasicNodeValidator</classname>
2210        since this will make it easier to handle situations with missing items and permission
2211        problems. Since each registered extension is checked for each item
2212        in the overview we recommend that the action factory makes a first filtering step
2213        before an action is created. This should be relatively simple since the current
2214        item in the <classname>ClientContext</classname> is type of that should be validated.
2215        For example:
2216      </para>
2217     
2218      <programlisting language="java">
2219<![CDATA[
2220// From the ActionFactory interface
2221public boolean prepareContext(InvokationContext<? super NodeValidatorAction> context)
2222{
2223   return context.getClientContext().getCurrentItem() == Item.USER;
2224}
2225]]>
2226</programlisting>
2227
2228      <para>
2229        Rule definition actions should implement the <interfacename 
2230        docapi="net.sf.basedb.util.overview.extensions">ValidationRuleAction</interfacename>.
2231        This is simply a container with some information about the validation rule, such as
2232        a title, description and a default severity level. The
2233        <classname docapi="net.sf.basedb.util.overview">Validator</classname> class
2234        that ships with BASE already implements this interface. The <classname 
2235        docapi="net.sf.basedb.util.overview.extensions">ReflectValidationRuleActionFactory</classname>
2236        can be used to return an existing <code>public static final</code> rule definition as an
2237        action:
2238      </para>
2239     
2240      <programlisting language="xml">
2241<![CDATA[
2242<extension
2243   id="validationrule.invalid-url"
2244   extends="net.sf.basedb.util.overview.validationrule">
2245   <index>4</index>
2246   <about>
2247      <name>Invalid URL</name>
2248      <description>Checks if an URL has a valid syntax.</description>
2249   </about>
2250   <action-factory>
2251      <factory-class>
2252         net.sf.basedb.util.overview.extensions.ReflectValidationRuleActionFactory
2253      </factory-class>
2254      <parameters>
2255         <field>net.sf.basedb.examples.extensions.overview.OwnerValidator.INVALID_URL</field>
2256      </parameters>
2257   </action-factory>
2258</extension>
2259]]>
2260</programlisting>
2261     
2262    </sect2>
2263   
2264    <sect2 id="extensions_developer.overview_information">
2265      <title>Item overview information</title>
2266     
2267      <para>
2268        The item overview functionality allow extensions to display additional information
2269        about the currently selected node in the right pane in the web interface.
2270        Each <interfacename docapi="net.sf.basedb.clients.web.extensions.section">SectionAction</interfacename> 
2271        object that is created by extensions will result in an additional section in the
2272        GUI. Note that all extension factories are called for all nodes. The
2273        <methodname>ActionFactory.prepareContext()</methodname> should be used to enable/disable
2274        the extension depending on the node that is selected. BASE ships with the
2275        <classname docapi="net.sf.basedb.clients.web.extensions.section">IncludeContentSectionFactory</classname>
2276        factory implementation which allows a resourse (eg. another JSP script) to generate
2277        the content of the section. The current context is stored in a request-scoped
2278        attribute under the key given by <code>JspContext.ATTRIBUTE_KEY</code>.
2279        A JSP or servlet should use this to hook into the current flow. Here is a code example:
2280      </para>
2281     
2282      <programlisting language="java">
2283<![CDATA[
2284// Get the JspContext that was created on the main edit page
2285final JspContext jspContext = (JspContext)request.getAttribute(JspContext.ATTRIBUTE_KEY);
2286
2287// The currently selected node is found in the context.
2288final Node node = (Node)jspContext.getCurrentItem();
2289
2290// Get the DbControl and SessionControl used to handle the request (do not close!)
2291final DbControl dc = jspContext.getDbControl();
2292final SessionControl sc = dc.getSessionControl();
2293]]>
2294</programlisting>
2295       
2296    </sect2>
2297   
2298   
2299    <sect2 id="extensions_developer.list_column">
2300      <title>Table list columns</title>
2301     
2302      <para>
2303        This extension point makes it possible to add more columns to most major list pages
2304        in the web interface. Actions should implement the <interfacename 
2305        docapi="net.sf.basedb.clients.web.extensions.list">ListColumnAction</interfacename> interface.
2306        This interface contains several methods which can be grouped into three main types:
2307      </para>
2308
2309      <itemizedlist>
2310        <listitem>
2311          <para>
2312            Metadata methods, for example, the id and title of the column and if the column
2313            can be sorted, filtered, etc.
2314          </para>
2315        </listitem>
2316       
2317        <listitem>
2318          <para>
2319            Rendering information, for example, CSS class and style information that is
2320            used for the column header.
2321          </para>
2322        </listitem>
2323       
2324        <listitem>
2325          <para>
2326            Worker methods, that retrieve the value from the current item and format
2327            it for proper display. Different methods are used for the web display
2328            and for exporting to a file.
2329          </para>
2330        </listitem>
2331      </itemizedlist>
2332     
2333      <para>
2334        The <classname docapi="net.sf.basedb.clients.web.extensions.list">AbstractListColumnBean</classname>
2335        class provides a bean-like implementation for all methods except the <methodname>getValue()</methodname>
2336        method. Extending from this class makes it easy to your own implementations. BASE ships with the
2337        <classname docapi="net.sf.basedb.clients.web.extensions.list">PropertyPathActionFactory</classname>
2338        factory that can be used without coding if the added column can be expressed as a property path that
2339        can be handled by the <classname docapi="net.sf.basedb.core">Metadata</classname> class.
2340        As usual, see the <ulink url="http://baseplugins.thep.lu.se/wiki/net.sf.basedb.examplecode">example code</ulink> 
2341        for some examples.
2342      </para>
2343     
2344    </sect2>
2345   
2346    <sect2 id="extensions_developer.login-manager">
2347      <title>Login manager</title>
2348      <para>
2349        This extension point makes it possible to authenticate users by some other means than
2350        the regular internal username+password authentication. Authentication managers should
2351        implement the <classname docapi="net.sf.basedb.core.authentication">AuthenticationManager</classname>
2352        action interface. This interface is simple and contain only one parameter-less method
2353        <methodname>authenticate()</methodname>. There are three outcomes:
2354      </para>
2355     
2356      <itemizedlist>
2357        <listitem>
2358          <para>A <classname docapi="net.sf.basedb.core.authentication">AuthenticatedUser</classname>
2359          is returned with information about a user that has passed authentication.
2360          </para>
2361        </listitem>
2362       
2363        <listitem>
2364          <para>A <constant>null</constant> value is returned to indicate that the manager could
2365          not determine if the login credentials are valid or not. The BASE core may try another
2366          authentication manager or use internal authentication.
2367          </para>
2368        </listitem>
2369       
2370        <listitem>
2371          <para>An exception is thrown to indicate that the manager has determined that
2372          the login credentials are invalid.
2373          </para>
2374        </listitem>
2375       
2376      </itemizedlist>
2377     
2378      <para>
2379        Since the action interface doesn't contain any parameters that contain information about the
2380        login request, the implementation need to get this from the <classname 
2381        docapi="net.sf.basedb.util.extensions">ClientContext</classname> that is passed to the
2382        action factory. The <methodname>getCurrentItem()</methodname> item is a <classname 
2383        docapi="net.sf.basedb.core.authentication">LoginRequest</classname> containing the login and
2384        password the user entered on the login page. The <classname>ClientContext</classname>
2385        ojbect can be cast to <classname docapi="net.sf.basedb.core">AuthenticationContext</classname>
2386        which provide some extra services to the authentication manager.
2387      </para>
2388     
2389      <sect3 id="extensions_developer.login-manager.internal-vs-external">
2390        <title>Internal vs. external authentation</title>
2391     
2392        <para>
2393          All login requests are always sent to registered authentication
2394          managers first. Internal authentication is only used if no authentication
2395          manager could validate the user. Even with external authentication it is possible to
2396          let BASE cache the logins/passwords. This makes it possible to login to
2397          BASE if the external authentication server is down.
2398        </para>
2399       
2400        <note>
2401          <para>
2402          An external authentication server can only be used to grant or deny
2403          a user access to BASE. It cannot be used to give a user permissions,
2404          or put a user into groups or different roles inside BASE.
2405          </para>
2406        </note>
2407
2408        <para>
2409          The authentication process goes something like this:
2410         
2411          <itemizedlist>
2412          <listitem>
2413            <para>
2414              An external authentication manager determines that the login request
2415              is valid and the user is already known to BASE.
2416              If the extra information (name, email, phone, etc.) is supplied
2417              and the <property>auth.synchronize</property> setting
2418              is <constant>TRUE</constant> the extra information is copied to
2419              the BASE server.
2420            </para>
2421          </listitem>
2422         
2423          <listitem>
2424            <para>
2425              An external authentication manager determines that the login request
2426              is valid, but the user is not known to BASE. This happens
2427              the first time a user logs in. BASE will create
2428              a new user account. If the authentication manager provides extra information, it
2429              is copied to the BASE server (even if <property>auth.synchronize</property> 
2430              is not set). The new user account will get the default quota
2431              and be added to the all roles and groups which has been
2432              marked as <emphasis>default</emphasis>.
2433            </para>
2434          </listitem>
2435
2436          <listitem>
2437            <para>
2438              If password caching is enabled, the password is copied to BASE.
2439              If an expiration timeout has been set, an expiration date
2440              will be calculated and set on the user account. The expiration
2441              date is only checked when the external authentication server is
2442              down.
2443            </para>
2444          </listitem>
2445
2446          <listitem>
2447            <para>
2448              The external authentication manager says that the login is invalid or
2449              the password is incorrect. The user will not be logged in.
2450            </para>
2451          </listitem>
2452         
2453          <listitem>
2454            <para>
2455              The authentication manager says that something else is wrong.
2456              If password caching is enabled, internal authentication will be
2457              used. Otherwise the user will not be logged in.
2458            </para>
2459          </listitem>
2460          </itemizedlist>
2461         
2462        </para>
2463      </sect3>
2464     
2465      <sect3 id="pextensions_developer.login-manager.settings">
2466        <title>Configuration settings</title>
2467     
2468        <para>
2469          The configuration settings for the authentication system are located
2470          in the <filename>base.config</filename> file.
2471          Here is an overview of the settings. For more information read
2472          <xref linkend="appendix.base.config.authentication" />.
2473        </para>
2474       
2475        <variablelist>
2476        <varlistentry>
2477          <term><property>auth.synchronize</property></term>
2478          <listitem>
2479            <para>
2480            If extra user information is synchronized at login time or not.
2481            This setting is ignored if the driver does not support extra information.
2482            </para>
2483          </listitem>
2484        </varlistentry>
2485       
2486        <varlistentry>
2487          <term><property>auth.cachepasswords</property></term>
2488          <listitem>
2489            <para>
2490              If passwords should be cached by BASE or not. If the passwords are
2491              cached a user may login to BASE even if the external authentication
2492              server is down.
2493            </para>
2494          </listitem>
2495        </varlistentry>
2496       
2497        <varlistentry>
2498          <term><property>auth.daystocache</property></term>
2499          <listitem>
2500            <para>
2501              How many days to cache the passwords if caching has been enabled.
2502              A value of 0 caches the passwords for ever.     
2503            </para>
2504          </listitem>
2505        </varlistentry>
2506        </variablelist>
2507      </sect3>
2508     
2509    </sect2>
2510   
2511    <sect2 id="extensions_developer.login-form">
2512      <title>Login form</title>
2513     
2514      <para>
2515        This extension point is typically used in combination with a login manager to provide a
2516        customized login form. Extensions should implement the <interfacename 
2517        docapi="net.sf.basedb.clients.web.extensions.login">LoginFormAction</interfacename>
2518        action which is used to specify prompts, tooltips, help texts and styling information
2519        for the login and password fields. The extension point supports custom scripts and stylesheets.
2520      </para>
2521     
2522      <note>
2523        <title>Only the first registered extension is used</title>
2524        <para>
2525          Since there is only one login form, only the first registered extension is used even
2526          if there are more extensions for this extension point.
2527        </para>
2528      </note>
2529     
2530    </sect2>
2531   
2532    <sect2 id="extensions_developer.skins">
2533      <title>Skins</title>
2534     
2535      <para>
2536        This extension point can be used to change the visual appearance of BASE. Contrary
2537        to other extension points, providing actions are optional. The skinning is
2538        done by having the action factory set style sheet and script files on the <classname 
2539        docapi="net.sf.basedb.clients.web.extensions">JspContext</classname> instance.
2540        Typically the style sheet override or set some properties defined by the BASE
2541        core stylesheets.
2542      </para>
2543     
2544      <para>
2545        Actions may be provided and should then implement the <interfacename 
2546        docapi="net.sf.basedb.clients.web.extensions.skin">SkinAction</interfacename>
2547        interface. Actions are needed if the skin extension wants to modify the
2548        fav-icon or include some data in a hidden <sgmltag class="starttag">div</sgmltag>
2549        tag. For this to work, the action must also implement the <interfacename 
2550        docapi="net.sf.basedb.clients.web.extensions">DynamicActionAttributes</interfacename>
2551        interface, since only the dynamic attribute values are included in the web page.
2552      </para>
2553     
2554      <para>
2555        BASE provides a simple action factory implementation,
2556        <classname docapi="net.sf.basedb.clients.web.extensions.skin">FixedSkinActionFactory</classname>,
2557        that supports all of the above.
2558      </para>
2559     
2560    </sect2>
2561  </sect1>
2562 
2563</chapter>
Note: See TracBrowser for help on using the repository browser.