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

Last change on this file since 7548 was 7548, checked in by Nicklas Nordborg, 4 years ago

Fixes #2134: Deprecate secondary storage

Code and documentatation has been updated.

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