source: trunk/doc/src/docbook/developerdoc/plugin_developer.xml @ 3495

Last change on this file since 3495 was 3495, checked in by Nicklas Nordborg, 16 years ago

References #625. Major features are now in place. It's a bit tricky to update the isInContext
method on all plug-ins. I need more testing time to verify that all works before I close the
ticket.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 90.6 KB
Line 
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE chapter PUBLIC
3    "-//Dawid Weiss//DTD DocBook V3.1-Based Extension for XML and graphics inclusion//EN"
4    "../../../../lib/docbook/preprocess/dweiss-docbook-extensions.dtd">
5<!--
6  $Id: plugin_developer.xml 3495 2007-06-14 12:36:26Z nicklas $:
7 
8  Copyright (C) Authors contributing to this file.
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 2
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 this program; if not, write to the Free Software
25  Foundation, Inc., 59 Temple Place - Suite 330,
26  Boston, MA  02111-1307, USA.
27-->
28
29<chapter id="plugin_developer">
30  <?dbhtml dir="plugin_developer"?>
31  <title>Plug-in developer</title>
32  <sect1 id="plugin_developer.organize">
33    <title>How to organize your plug-in project</title>
34   
35    <sect2 id="plugin_developer.organize.ant">
36      <title>Using Ant</title>
37      <para>
38        Here is a simple example of how you might organize your project using ant
39        (<ulink url="http://ant.apache.org">http://ant.apache.org</ulink>) as the build
40        tool. This is just a recommendation that we have found to be working
41        well. You may choose to do it another way.
42      </para>
43
44      <sect3 id="plugin_developer.organize.ant.directories">
45        <title>Directory layout</title>
46        <para>
47       
48          Create a directory on your computer where you want
49          to store your plug-in project. This directory is the
50          <filename class="directory"><replaceable>pluginname</replaceable>/</filename>
51          directory in the listing below. You should also create some subdirectories:
52         
53          <literallayout>
54<filename class="directory"><replaceable>pluginname</replaceable>/</filename>
55<filename class="directory"><replaceable>pluginname</replaceable>/bin/</filename>
56<filename class="directory"><replaceable>pluginname</replaceable>/lib/</filename>
57<filename class="directory"><replaceable>pluginname</replaceable>/src/<replaceable>org/company</replaceable>/</filename>
58          </literallayout>
59          The
60          <filename class="directory">bin/</filename>
61          directory is empty to start with. It will contain the compiled code.
62          In the <filename class="directory">lib/</filename>
63          directory you should put <filename>BASE2Core.jar</filename>
64          and other library files your plug-in depends on. The
65          <filename class="directory">src/</filename>
66          directory contains your source code. In this directory you should create
67          subdirectories corresponding to the package name of your plug-in
68          class(es). See <ulink url="http://en.wikipedia.org/wiki/Java_package"
69          >http://en.wikipedia.org/wiki/Java_package</ulink> for information
70          about conventions for naming packages.
71        </para>
72      </sect3>
73   
74      <sect3 id="plugin_developer.organize.ant.buildfile">
75        <title>The build file</title>
76        <para>
77          In the root of your directory, create the build file:
78          <filename>build.xml</filename>
79          . Here is an example that will compile your plug-in and put it in a JAR file.
80        </para>
81        <example id="plugin_developer.organize.build.file">
82          <title>A simple build file</title>
83<programlisting>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
84&lt;project
85   name="MyPlugin"
86   default="build.plugin"
87   basedir="."
88   &gt;
89
90   &lt;!-- variables used --&gt;
91   &lt;property name="plugin.name" value="MyPlugin" /&gt;
92   &lt;property name="src" value="src" /&gt;
93   &lt;property name="bin" value="bin" /&gt;
94
95   &lt;!-- set up classpath for compiling --&gt;
96   &lt;path id="classpath"&gt;
97      &lt;fileset dir="lib"&gt;
98         &lt;include name="**/*.jar"/&gt;
99      &lt;/fileset&gt;
100   &lt;/path&gt;
101
102   
103   &lt;!-- main target --&gt;
104   &lt;target
105      name="build.plugin" 
106      description="Compiles the plug-in and put in jar"
107      &gt;
108      &lt;javac
109         encoding="ISO-8859-1"
110         srcdir="${src}"
111         destdir="${bin}"
112         classpathref="classpath"&gt;
113      &lt;/javac&gt;
114      &lt;jar
115         jarfile="${plugin.name}.jar"
116         basedir="bin"
117         manifest="MANIFEST.MF"
118         &gt;
119      &lt;/jar&gt;
120
121    &lt;/target&gt;
122&lt;/project&gt; </programlisting>
123        </example>
124        <para>
125          If your plug-in depends on other JAR files than the
126          <filename>BASE2Core.jar</filename> you must create a file called
127          <filename>MANIFEST.MF</filename> in the project root directory.
128          List the other JAR files as in the following example.
129          If your plug-in does not depend on other JAR files, remove the
130          <sgmltag class="attribute">manifest</sgmltag> 
131          attribute of the <sgmltag class="starttag">jar</sgmltag> tag.
132<programlisting>Manifest-Version: 1.0
133Class-Path: OtherJar.jar ASecondJar.jar</programlisting>
134        </para>
135      </sect3>
136       
137      <sect3 id="plugin_developer.organize.ant.build">
138        <title>Building the plug-in</title>
139        <para>
140          Compile the plug-in simply by typing
141          <command>ant</command>
142          in the console window. If all went well the
143          <filename>MyPlugin.jar</filename>
144          will be created in the same directory.
145        </para>
146        <para>
147          To install the plug-in copy the JAR file to the server including the dependent JAR
148          files (if any). Place all files together in the same directory. For more
149          information read
150          <xref linkend="plugins.installation" />
151        </para>
152      </sect3>
153    </sect2>
154   
155    <sect2 id="plugin_developer.organize.eclipse">
156      <title>With Eclipse</title>
157      <para>TODO</para>
158    </sect2>
159   
160  </sect1>
161
162  <sect1 id="plugin_developer.api">
163    <title>The Plug-in API</title>
164    <para>
165    </para>
166   
167    <sect2 id="plugin_developer.api.interfaces">
168   
169      <title>The main plug-in interfaces</title>
170      <para>
171        The Base2 core defines two interfaces and one
172        abstract class that are vital for implementing plug-ins:
173        <itemizedlist spacing="compact">
174          <listitem>
175            <simpara>
176              <interfacename>net.sf.basedb.core.plugin.Plugin</interfacename>
177            </simpara>
178          </listitem>
179          <listitem>
180            <simpara>
181              <interfacename>net.sf.basedb.core.plugin.InteractivePlugin</interfacename>
182            </simpara>
183          </listitem>
184          <listitem>
185            <simpara>
186              <classname>net.sf.basedb.core.plugin.AbstractPlugin</classname>
187            </simpara>
188          </listitem>
189        </itemizedlist>
190       
191        A plug-in is always required to implement the
192        <interfacename>Plugin</interfacename> interface.
193        The <interfacename>InteractivePlugin</interfacename>
194        interface is optional, and is only needed if you want user interaction.
195        The <classname>AbstractPlugin</classname> is a useful base class
196        that your plug-in can use as a superclass. It provides default implementations
197        for some of the interface methods and also has utility methods for
198        validating and storing job and configuration parameter values. Another
199        reason to use this class as a superclass is that it will shield your
200        plug-in from future changes to the Plug-in API. For example, if
201        we decide that a new method is needed in the <interfacename>Plugin</interfacename> 
202        interface we will also try to add a default implementation in
203        the <classname>AbstractPlugin</classname> class.
204      </para>
205 
206      <important>
207        <para>
208        A plug-in must also have public no-argument contructor. Otherwise, BASE will not
209        be able to create instances of the class.
210        </para>
211      </important>
212     
213      <sect3 id="plugin_developer.api.interfaces.plugin">
214        <title>net.sf.basedb.core.plugin.Plugin</title>
215        <para>This interface defines seven methods and must be implemented by all plug-ins.</para>
216        <variablelist>
217          <varlistentry>
218            <term>
219              <methodsynopsis language="java">
220                <modifier>public</modifier>
221                <type>About</type>
222                <methodname>getAbout</methodname>
223                <void />
224              </methodsynopsis>
225            </term>
226            <listitem>
227              <para>
228                Return information about the plug-in, i.e. the name, version, and a short
229                description about what the plug-in does. The
230                <classname>About</classname>
231                object also has fields for naming the author and various other contact
232                information. The returned information is copied by the core at
233                installation time into the database. The only required information is
234                the name of the plug-in. All other fields may have null values.
235              </para>
236              <example id="net.sf.basedb.core.plugin.Plugin.getAbout">
237                <title>A typical implementation stores this information in a static field</title>
238<programlisting>private static final About about = new AboutImpl
239(
240   "Spot images creator",
241   "Converts a full-size scanned image into smaller preview jpg " +
242   "images for each individual spot.",
243   "2.0",
244   "2006, Department of Theoretical Physics, Lund University",
245   null,
246   "base@thep.lu.se",
247   "http://base.thep.lu.se"
248);
249 
250public About getAbout()
251{
252   return about;
253}</programlisting>
254              </example>
255            </listitem>
256          </varlistentry>
257          <varlistentry>
258            <term>
259              <methodsynopsis language="java">
260                <modifier>public</modifier>
261                <type>Plugin.MainType</type>
262                <methodname>getMainType</methodname>
263                <void />
264              </methodsynopsis>
265            </term>
266            <listitem>
267              <para>
268                Return information about the main type of plug-in. The
269                <classname>MainType</classname>
270                is an enumeration with five possible values:
271                <itemizedlist>
272                  <listitem>
273                    <para>
274                      <constant>ANALYZE</constant>:
275                      An analysis plug-in
276                    </para>
277                  </listitem>
278                  <listitem>
279                    <para>
280                      <constant>EXPORT</constant>:
281                      A plug-in that exports data
282                    </para>
283                  </listitem>
284                  <listitem>
285                    <para>
286                      <constant>IMPORT</constant>:
287                      A plug-in that imports data
288                    </para>
289                  </listitem>
290                  <listitem>
291                    <para>
292                      <constant>INTENSITY</constant>:
293                      A plug-in that calculates the original spot intensities
294                      from raw data
295                    </para>
296                  </listitem>
297                  <listitem>
298                    <para>
299                      <constant>OTHER</constant>:
300                      Any other type of plug-in
301                    </para>
302                  </listitem>
303                </itemizedlist>
304                The returned value is stored in the database but is otherwise not used
305                by the core. Client applications (such as the web client) will probably
306                use this information to group the plug-ins, i.e., a button labeled
307                &gbExport;
308                will let you select among the export plug-ins.
309              </para>
310              <example id="net.sf.basedb.core.plugin.Plugin.getMainType">
311                <title>A typical implementation just return one of the values</title>
312<programlisting>public Plugin.MainType getMainType()
313{
314   return Plugin.MainType.OTHER;
315}</programlisting>
316              </example>
317            </listitem>
318          </varlistentry>
319          <varlistentry>
320            <term>
321              <methodsynopsis language="java">
322                <modifier>public</modifier>
323                <type>boolean</type>
324                <methodname>supportsConfigurations</methodname>
325                <void />
326              </methodsynopsis>
327            </term>
328            <listitem>
329              <para>
330                If this method returns true, the plug-in can have different
331                configurations, (i.e.
332                <classname>PluginConfiguration</classname>).
333                Note that this method may return true even if the
334                <interfacename>InteractivePlugin</interfacename>
335                interface is not implemented. The
336                <classname>AbstractPlugin</classname>
337                returns true for this method, which is the old way before the
338                introduction of this method.
339              </para>
340            </listitem>
341          </varlistentry>
342          <varlistentry>
343            <term>
344              <methodsynopsis language="java">
345                <modifier>public</modifier>
346                <type>boolean</type>
347                <methodname>requiresConfiguration</methodname>
348                <void />
349              </methodsynopsis>
350            </term>
351            <listitem>
352              <para>
353                If this method returns true, the plug-in must have a configuration
354                to be able to run. For example, some of the core import plug-ins
355                must have information about the file format, to be able to import
356                any data.
357                The
358                <classname>AbstractPlugin</classname>
359                returns false for this method, which is the old way before the
360                introduction of this method.
361              </para>
362            </listitem>
363          </varlistentry>
364          <varlistentry>
365            <term>
366              <methodsynopsis language="java">
367                <modifier>public</modifier>
368                <void />
369                <methodname>init</methodname>
370                <methodparam>
371                  <type>SessionControl</type>
372                  <parameter>sc</parameter>
373                </methodparam>
374                <methodparam>
375                  <type>ParameterValues</type>
376                  <parameter>configuration</parameter>
377                </methodparam>
378                <methodparam>
379                  <type>ParameterValues</type>
380                  <parameter>job</parameter>
381                </methodparam>
382                <exceptionname>BaseException</exceptionname>
383              </methodsynopsis>
384            </term>
385            <listitem>
386              <para>
387                Prepare the plug-in for execution (or configuration). If the plug-in needs
388                to do some initialization this is the place to do it. A typical
389                implementation however only stores the passed parameters in instance
390                variables for later use.
391              </para>
392              <para>
393                The parameters passed to this method has vital information that is
394                needed to execute the plug-in. The
395                <classname>SessionControl</classname>
396                is a central core object holding information about the logged in
397                user and is used to create
398                <classname>DbControl</classname>
399                objects which allows a plug-in to connect to the database to read, add or
400                update information. The two
401                <classname>ParameterValues</classname>
402                objects contain information about the configuration and job
403                parameters to the plug-in.
404                The <varname>configuration</varname> object holds all parameters stored
405                together with a <classname>PluginConfiguration</classname>
406                object in the database. If the plug-in is started without
407                a configuration this object is null.
408                The <varname>job</varname> object holds all parameters that are
409                stored together with a <classname>Jon</classname> object in the
410                database. This object is null if the plug-in is started without a job.
411              </para>
412              <para>
413                The difference between a configuration parameter and a job parameter is
414                that a configuration is usually something an administrator sets up,
415                while a job is an actual execution of a plug-in. For example, a
416                configuration for an import plug-in holds the regular expressions needed
417                to parse a text file and find the headers, sections and data lines,
418                while the job holds the file to parse.
419              </para>
420              <para>
421                The
422                <classname>AbstractPlugin</classname>
423                contains an implementation of this method that saves the passed objects
424                in protected instance variables. If you override this method
425                we recommend that you also call <code>super.init()</code>.
426              </para>
427              <example id="net.sf.basedb.core.plugin.Plugin.init">
428                <title>The <classname>AbstractPlugin</classname> implementation of this Plugin.init()</title>
429<programlisting>protected SessionControl sc = null;
430protected ParameterValues configuration = null;
431protected ParameterValues job = null;
432/**
433   Store copies of the session control, plug-in and job configuration. These
434   are available to subclasses in the {@link #sc}, {@link #configuration}
435   and {@link #job} variables. If a subclass overrides this method it is
436   recommended that it also calls super.init(sc, configuration, job).
437*/
438public void init(SessionControl sc,
439   ParameterValues configuration, ParameterValues job)
440   throws BaseException
441{
442   this.sc = sc;
443   this.configuration = configuration;
444   this.job = job;
445}</programlisting>
446              </example>
447            </listitem>
448          </varlistentry>
449          <varlistentry>
450            <term>
451              <methodsynopsis language="java">
452                <modifier>public</modifier>
453                <void />
454                <methodname>run</methodname>
455                <methodparam>
456                  <type>Request</type>
457                  <parameter>request</parameter>
458                </methodparam>
459                <methodparam>
460                  <type>Response</type>
461                  <parameter>response</parameter>
462                </methodparam>
463                <methodparam>
464                  <type>ProgressReporter</type>
465                  <parameter>progress</parameter>
466                </methodparam>
467              </methodsynopsis>
468            </term>
469            <listitem>
470              <para>
471                Runs the plug-in. The <varname>request</varname>
472                parameter is of historical interest only. It has no useful information
473                and can be ignored.
474              </para>
475              <para>
476                The <varname>progress</varname> parameter
477                can be used by a plug-in to report it's progress back to the core. The
478                core will usually send the progress information to the database, which
479                allows users to see exactly how the plug-in is progressing from the web
480                interface. This parameter can be null, but if it is not we recommend all
481                plug-ins to use it. However, it should be used sparingly, since each call
482                to set the progress results in a database update. If the execution
483                involves several thousands of items it is a bad idea to update the
484                progress after processing each one of them. A good starting point is to
485                divide the work into 100 pieces each representing 1% of the work, i.e.,
486                if the plug-in should export 100 000 items it should report progress
487                after every 1000 items.
488              </para>
489              <para>
490                The <varname>response</varname>
491                parameter is used to tell the core if the plug-in was successful or
492                failed. Not setting a response is considered a failure by the core. From
493                the run method it is only allowed to use the
494                <methodname>setDone()</methodname>
495                or the
496                <methodname>setError()</methodname>
497                methods.
498              </para>
499             
500              <note>
501                It is also considered bad practice to let exceptions escape
502                out from this method. Always use <code>try...catch</code>
503                to catch exceptions and use <code>response.setError()</code>
504                to reporter the error back to the core.
505              </note>
506             
507              <example id="net.sf.basedb.core.plugin.Plugin.run">
508                <title>
509                  Here is a skeleton that we recommend each plug-in to use in it's
510                  implementation of the
511                  <methodname>run()</methodname>
512                  method
513                </title>
514<programlisting>public void run(Request request, Response response, ProgressReporter progress)
515{
516   // Open a connection to the database
517   // sc is set by init() method
518   DbControl dc = sc.newDbControl();
519   try
520   {
521      // Insert code for plug-in here
522
523      // Commit the work
524      dc.commit();
525      response.setDone("Plug-in ended successfully");
526   }
527   catch (Throwable t)
528   {
529      // All exceptions must be catched and sent back
530      // using the response object
531      response.setError(t.getMessage(), Arrays.asList(t));
532   }
533   finally
534   {
535      // IMPORTANT!!! Make sure opened connections are closed
536      if (dc != null) dc.close();
537   }
538}</programlisting>
539              </example>
540            </listitem>
541          </varlistentry>
542          <varlistentry>
543            <term>
544              <methodsynopsis language="java">
545                <modifier>public</modifier>
546                <void />
547                <methodname>done</methodname>
548                <void />
549              </methodsynopsis>
550            </term>
551            <listitem>
552              <para>
553                Clean up all resources after executing the plug-in. This method must not
554                throw any exceptions.
555              </para>
556              <example id="net.sf.basedb.core.plugin.Plugin.done">
557                <title>
558                  The
559                  <classname>AbstractPlugin</classname>
560                  contains an implementation of the <methodname>done()</methodname>
561                  method simply sets the
562                  parameters passed to the
563                  <methodname>init()</methodname>
564                  method to null
565                </title>
566<programlisting>/**
567   Clears the variables set by the init method. If a subclass
568   overrides this method it is recommended that it also calls super.done().
569*/
570public void done()
571{
572   configuration = null;
573   job = null;
574   sc = null;
575}</programlisting>
576              </example>
577            </listitem>
578          </varlistentry>
579        </variablelist>
580      </sect3>
581 
582      <sect3 id="plugin_developer.api.interfaces.interactive">
583        <title>net.sf.basedb.core.plugin.InteractivePlugin</title>
584        <para>
585          If you want the plug-in to be able to interact with the user you must also implement
586          this interface. This is probably the case for most plug-ins. Among the core plug-ins
587          shipped with BASE the
588          <classname>SpotImageCreator</classname>
589          is one plug-in that does not interact with the user. Instead, the web client has
590          special JSP pages that handles all the interaction, creates a job for it and sets
591          the parameters. This, kind of hardcoded, approach can be used for other plug-ins as
592          well, but then it usually requires modification of the client application as well.
593        </para>
594        <para>
595          The
596          <interfacename>InteractivePlugin</interfacename>
597          has three main tasks:
598         
599          <orderedlist>
600          <listitem>
601            <para>
602            Tell a client application where the plug-in should be plugged
603            in.
604            </para>
605          </listitem>
606          <listitem>
607            <para>
608            Ask the users for configuration and job parameters.
609            </para>
610          </listitem>
611         
612          <listitem>
613            <para>
614            Validate parameter values entered by the user and store those in the
615            database.
616            </para>
617          </listitem>
618          </orderedlist>
619          This requires that the following methods are
620          implemented.
621        </para>
622       
623        <variablelist>
624          <varlistentry>
625            <term>
626              <methodsynopsis language="java">
627                <modifier>public</modifier>
628                <type>Set&lt;GuiContext&gt;</type>
629                <methodname>getGuiContexts</methodname>
630                <void />
631              </methodsynopsis>
632            </term>
633            <listitem>
634              <para>
635                Return information about where the plug-in should be plugged in. Each
636                place is identified by a
637                <classname>GuiContext</classname>
638                object, which is an
639                <classname>Item</classname>
640                and a
641                <classname>Type</classname>.
642                The item is one of the objects defined by the
643                <classname>net.sf.basedb.core.Item</classname>
644                enumeration and the type is either
645                <constant>Type.LIST</constant>
646                or
647                <constant>Type.ITEM</constant>, which corresponde to the
648                list view and the single-item view in the web client.
649              </para>
650              <para>
651                For example, the
652                <varname>GuiContext</varname> =
653                (<constant>Item.REPORTER</constant>,
654                <constant>Type.LIST</constant>)
655                tells a client application that this plug-in can be plugged in whenever a
656                list of reporters is displayed. The
657                <varname>GuiContext</varname> =
658                (<constant>Item.REPORTER</constant>,
659                <constant>Type.ITEM</constant>)
660                tells a client application that this plug-in can be plugged in whenever
661                a single reporter is displayed. The first case may be appropriate for a
662                plug-in that imports or exports reporters. The second case may be used by
663                a plug-in that updates the reporter information from an external source
664                (well, it may make sense to use this in the list case as well).
665              </para>
666              <para>
667                The returned information is copied by the core at installation time to
668                make it easy to ask for all plug-ins for a certain
669                <classname>GuiContext</classname>.
670              </para>
671              <para>
672                A typical implementation creates a static unmodifiable
673                <classname>Set</classname>
674                which is returned by this method. It is important that the returned set
675                cannot be modified. It may be a security issue if a misbehaving
676                client application does that.
677              </para>
678              <example id="net.sf.basedb.core.plugin.InteractivePlugin.getGuiContexts">
679                <title>
680                  A typical implementation of
681                  <methodname>getGuiContexts</methodname>
682                </title>
683<programlisting>// From the net.sf.basedb.plugins.RawDataFlatFileImporter plug-in
684private static final Set&lt;GuiContext&gt; guiContexts =
685   Collections.singleton(new GuiContext(Item.RAWBIOASSAY, GuiContext.Type.ITEM));
686
687public Set&lt;GuiContext&gt; <methodname>getGuiContexts</methodname>()
688{
689   return <returnvalue>guiContexts</returnvalue>;
690}</programlisting>
691              </example>
692            </listitem>
693          </varlistentry>
694          <varlistentry>
695            <term>
696              <methodsynopsis language="java">
697                <modifier>public</modifier>
698                <type>String</type>
699                <methodname>isInContext</methodname>
700                <methodparam>
701                  <type>GuiContext</type>
702                  <parameter>context</parameter>
703                </methodparam>
704                <methodparam>
705                  <type>Object</type>
706                  <parameter>item</parameter>
707                </methodparam>
708              </methodsynopsis>
709            </term>
710            <listitem>
711              <para>
712                This method is called to check if a particular item is usable for the
713                plug-in. This method is invoked to check if a plug-in can be used
714                in a given context. If invoked from a list context the <parameter>item</parameter>
715                parameter is <constant>null</constant>
716                The plug-in should return <constant>null</constant> if it
717                finds that it can be used. If the plug-in can't be used it
718                must decide if the reason should be a warning or an error condition.
719              </para>
720             
721              <para>
722                A warning is issued by returning a string with the warning
723                message. It should be used when the plug-in can't be used because
724                it is unrelated to the current task. For example, a plug-in for
725                importing Genepix data should return a warning when somebody wants
726                to import data to an Agilent raw bioassay.
727              </para>
728             
729              <para>
730                An error message is issued by throwing an exception. This
731                should be used when the plug-in is related to the current task
732                but still can't do what it is supposed to do. For example,
733                trying to import raw data if the logged in user doesn't have
734                write permission to the raw bioassay.
735              </para>
736             
737              <para>
738                As a rule of thumb, if there is a chance that another plug-in
739                might be able to perform the same task a warning should be used.
740                If it is guaranteed that no other plug-in can do it an error
741                message should be used.
742              </para>
743             
744              <note>
745                <para>
746                The contract of this method was changed in in BASE 2.4
747                to allow warning and error level message. Prior to BASE
748                2.4 all messages were treated as error message. We recommend
749                that existing plug-ins are updated to throw exception to indicate
750                error-level messages since the default is to not show
751                warning messages to users.
752                </para>
753              </note>
754             
755              <para>
756                Here is a real example from the
757                <classname>RawDataFlatFileImporter</classname>
758                plug-in which imports raw data to a
759                <classname>RawBioAssay</classname>.
760               
761                Thus,
762                <varname>GuiContext</varname> =
763                (<constant>Item.RAWBIOASSAY</constant>,
764                <constant>Type.ITEM</constant>),
765               
766                but the plug-in can only import data if the logged in user has write permission,
767                there is no data already, and
768                if the raw bioassay has the same raw data type as the plug-in has been
769                configured for.
770              </para>
771              <example id="net.sf.basedb.core.plugin.InteractivePlugin.isInContext">
772                <title>
773                  A simple implementation of
774                  <methodname>isInContext</methodname>
775                </title>
776<programlisting>/**
777   Returns null if the item is a {@link RawBioAssay} of the correct
778   {@link RawDataType} and doesn't already have spots.
779   @throws PermissionDeniedException If the raw bioasssay already has raw data
780   or if the logged in user doesn't have write permission
781*/
782public String isInContext(GuiContext context, Object item)
783{
784   String message = null;
785   if (item == null)
786   {
787      message = "The object is null";
788   }
789   else if (!(item instanceof RawBioAssay))
790   {
791      message = "The object is not a RawBioAssay: " + item;
792   }
793   else
794   {
795      RawBioAssay rba = (RawBioAssay)item;
796      String rawDataType = (String)configuration.getValue("rawDataType");
797      RawDataType rdt = rba.getRawDataType();
798      if (!rdt.getId().equals(rawDataType))
799      {
800         message = "Unsupported raw data type: " + rba.getRawDataType().getName();
801      }
802      else if (!rdt.isStoredInDb())
803      {
804         message = "Raw data for raw data type '" + rdt + "' is not stored in the database";
805      }
806      else if (rba.hasData())
807      {
808         throw new PermissionDeniedException("The raw bioassay already has data.");
809      }
810      else
811      {
812         rba.checkPermission(Permission.WRITE);
813      }
814   }
815   return message;   
816}</programlisting>
817              </example>
818            </listitem>
819          </varlistentry>
820          <varlistentry>
821            <term>
822              <methodsynopsis language="java">
823                <modifier>public</modifier>
824                <type>RequestInformation</type>
825                <methodname>getRequestInformation</methodname>
826                <methodparam>
827                  <type>GuiContext</type>
828                  <parameter>context</parameter>
829                </methodparam>
830                <methodparam>
831                  <type>String</type>
832                  <parameter>command</parameter>
833                </methodparam>
834                <exceptionname>BaseException</exceptionname>
835              </methodsynopsis>
836            </term>
837            <listitem>
838              <para>
839                Ask the plug-in for parameters that needs to be entered by the user. The
840                <classname>GuiContext</classname>
841                parameter is one of the contexts returned by the
842                <methodname>getGuiContexts</methodname>
843                method. The command is a string telling the plug-in what command was
844                executed. There are two predefined commands but as you will see the
845                plug-in may define it's own commands. The two predefined commands are
846                defined in the
847                <classname>net.sf.basedb.core.plugin.Request</classname>
848                class.
849                <variablelist>
850                  <varlistentry>
851                    <term>
852                      <constant>Request.COMMAND_CONFIGURE_PLUGIN</constant>
853                    </term>
854                    <listitem>
855                      <para>
856                        Used when an administrator is initiating a configuration
857                        of the plug-in.
858                      </para>
859                    </listitem>
860                  </varlistentry>
861                  <varlistentry>
862                    <term>
863                      <constant>Request.COMMAND_CONFIGURE_JOB</constant>
864                    </term>
865                    <listitem>
866                      <para>
867                        Used when a user has selected the plug-in for running a
868                        job.
869                      </para>
870                    </listitem>
871                  </varlistentry>
872                </variablelist>
873                Given this information the plug-in must return a
874                <classname>RequestInformation</classname>
875                object. This is simply a title, a description, and a list of parameters.
876                Usually the title will end up as the input form title and the
877                description as a help text for the entire form. Do not put information
878                about the individual parameters in this description, since each
879                parameter has a description of its own.
880              </para>
881              <example id="net.sf.basedb.core.plugin.InteractivePlugin.getRequestInformation">
882                <title>
883                  When running an import plug-in it needs to ask for the file to import
884                  from and if existing items should be updated or not
885                </title>
886<programlisting >// The complete request information
887private RequestInformation configure Job;
888
889// The parameter that asks for a file to import from
890private PluginParameter&lt;File&gt; file Parameter;
891
892// The parameter that asks if existing items should be updated or not
893private PluginParameter&lt;Boolean&gt; updateExistingParameter;
894
895public RequestInformation getRequestInformation(GuiContext context, String command)
896   throws BaseException
897{
898   RequestInformation requestInformation = null;
899   if (command.equals(Request.COMMAND_CONFIGURE_PLUGIN))
900   {
901      requestInformation = getConfigurePlugin();
902   }
903   else if (command.equals(Request.COMMAND_CONFIGURE_JOB))
904   {
905      requestInformation = getConfigureJob();
906   }
907   return requestInformation;
908}
909
910/**
911   Get (and build) the request information for starting a job.
912*/
913private RequestInformation getConfigureJob()
914{
915   if (configureJob == null)
916   {
917      fileParameter = new PluginParameter&lt;File&gt;(
918         "file",
919         "File",
920         "The file to import the data from",
921         new FileParameterType(null, true, 1)
922      );
923     
924      updateExistingParameter = new PluginParameter&lt;Boolean&gt;(
925         "updateExisting",
926         "Update existing items",
927         "If this option is selected, already existing items will be updated " +
928         " with the information in the file. If this option is not selected " +
929         " existing items are left untouched.",
930         new BooleanParameterType(false, true)
931      );
932
933      List&lt;PluginParameter&lt;?&gt;&gt; parameters =
934         new ArrayList&lt;PluginParameter&lt;?&gt;&gt;(2);
935      parameters.add(fileParameter);
936      parameters.add(updateExistingParameter);
937     
938      configureJob = new RequestInformation
939      (
940         Request.COMMAND_CONFIGURE_JOB,
941         "Select a file to import items from",
942         "Description",
943         parameters
944      );
945   }
946   return configureJob;
947}</programlisting>
948              </example>
949              <para>
950                As you can see it takes a lot of code to put together a
951                <classname>RequestInformation</classname>
952                object. For each parameter you need one
953                <classname>PluginParameter</classname>
954                object and one
955                <classname>ParameterType</classname>
956                object. To make life a little easier, a
957                <classname>ParameterType</classname>
958                can be reused for more than one
959                <classname>PluginParameter</classname>.
960              </para>
961             
962<programlisting>StringParameterType stringPT = new StringParameterType(255, null, true);
963PluginParameter one = new PluginParameter("one", "One", "First string", stringPT);
964PluginParameter two = new PluginParameter("two", "Two", "Second string", stringPT);
965// ... and so on</programlisting>
966              <para>
967                The
968                <classname>ParameterType</classname>
969                is an abstract base class for several subclasses each implementing a
970                specific type of parameter. The list of subclasses may grow in the
971                future, but here are the most important ones currently implemented.
972              </para>
973              <note>
974                <para>
975                  Most parameter types include support for supplying a predefined list
976                  of options to select from. In that case the list will be displayed
977                  as a drop-down list for the user, otherwise a free input field is
978                  used.
979                </para>
980              </note>
981              <variablelist>
982                <varlistentry>
983                  <term>
984                    <classname>StringParameterType</classname>
985                  </term>
986                  <listitem>
987                    <para>
988                      Asks for a string value. Includes an option for
989                      specifying the maximum length of the string.
990                    </para>
991                  </listitem>
992                </varlistentry>
993                <varlistentry>
994                  <term>
995                    <classname>FloatParameterType</classname>,
996                    <classname>DoubleParameterType</classname>,
997                    <classname>IntegerParameterType</classname>,
998                    <classname>LongParameterType</classname>
999                  </term>
1000                  <listitem>
1001                    <para>
1002                      Asks for numerical values. Includes options for
1003                      specifying a range (min/max) of allowed values.
1004                    </para>
1005                  </listitem>
1006                </varlistentry>
1007                <varlistentry>
1008                  <term>
1009                    <classname>BooleanParameterType</classname>
1010                  </term>
1011                  <listitem>
1012                    <para>Asks for a boolean value.
1013                    </para>
1014                  </listitem>
1015                </varlistentry>
1016                <varlistentry>
1017                  <term>
1018                    <classname>DateParameterType</classname>
1019                  </term>
1020                  <listitem>
1021                    <para>Asks for a date.
1022                    </para>
1023                  </listitem>
1024                </varlistentry>
1025                <varlistentry>
1026                  <term>
1027                    <classname>FileParameterType</classname>
1028                  </term>
1029                  <listitem>
1030                    <para>Asks for a file item.
1031                    </para>
1032                  </listitem>
1033                </varlistentry>
1034                <varlistentry>
1035                  <term>
1036                    <classname>ItemParameterType</classname>
1037                  </term>
1038                  <listitem>
1039                    <para>
1040                      Asks for any other item. This parameter type requires
1041                      that a list of options is supplied, except when the item
1042                      type asked for matches the current <classname>GuiContext</classname>, in which
1043                      case the currently selected item is used as the
1044                      parameter value.
1045                    </para>
1046                  </listitem>
1047                </varlistentry>
1048                <varlistentry>
1049                  <term>
1050                    <classname>PathParameterType</classname>
1051                  </term>
1052                  <listitem>
1053                    <para>
1054                      Ask for a path to a file or directory. The path may be
1055                      non-existing and should be used when a plug-in needs an
1056                      output destination, i.e., the file to export to, or a
1057                      directory where the output files should be placed.
1058                    </para>
1059                  </listitem>
1060                </varlistentry>
1061              </variablelist>
1062              <para>
1063                You can also create a
1064                <classname>PluginParameter</classname>
1065                with a null name and
1066                <classname>ParameterType</classname>.
1067                In this case, the web client will not ask for input from the user, instead
1068                it is used as a section header, allowing you to group parameters into
1069                different sections which increase the readability of the input
1070                parameters page.
1071              </para>
1072<programlisting>PluginParameter firstSection = new PluginParameter(null, "First section", null, null);
1073PluginParameter secondSection = new PluginParameter(null, "Second section", null, null);
1074// ...
1075
1076parameters.add(firstSection);
1077parameters.add(firstParameterInFirstSection);
1078parameters.add(secondParameteInFirstSection);
1079
1080parameters.add(secondSection);
1081parameters.add(firstParameterInSecondSection);
1082parameters.add(secondParameteInSecondSection);</programlisting>
1083            </listitem>
1084          </varlistentry>
1085          <varlistentry>
1086            <term>
1087              <methodsynopsis language="java">
1088                <modifier>public</modifier>
1089                <void />
1090                <methodname>configure</methodname>
1091                <methodparam>
1092                  <type>GuiContext</type>
1093                  <parameter>context</parameter>
1094                </methodparam>
1095                <methodparam>
1096                  <type>Request</type>
1097                  <parameter>request</parameter>
1098                </methodparam>
1099                <methodparam>
1100                  <type>Response</type>
1101                  <parameter>response</parameter>
1102                </methodparam>
1103              </methodsynopsis>
1104            </term>
1105            <listitem>
1106              <para>
1107                Sends parameter values entered by the user for processing by the plug-in.
1108                The plug-in must validate that the parameter values are
1109                correct and then store them in database.
1110              </para>
1111             
1112              <important>
1113                <para>
1114                No validation is done by the core, except converting the input to the
1115                correct object type, i.e. if the plug-in asked for a
1116                <classname>Float</classname>
1117                the input string is parsed and converted to a
1118                <classname>Float</classname>. If you have extended the
1119                <classname>AbstractPlugin</classname>
1120                class it is very easy to validate the parameters with the
1121                <methodname>validateRequestParameters()</methodname>
1122                method. This method takes the same list of
1123                <classname>PluginParameter</classname>:s
1124                as used in the
1125                <classname>RequestInformation</classname>
1126                object and uses that information for validation. It returns null or a
1127                list of
1128                <exceptionname>Throwable</exceptionname>:s that can be
1129                given directly to the <code>response.setError()</code>
1130                methods.
1131                </para>
1132              </important>
1133              <para>
1134                When the parameters have been validated, they need to be stored
1135                in the database. Once again, it is very easy, if you use one of the
1136                <methodname>AbstractPlugin.storeValue()</methodname>
1137                or
1138                <methodname>AbstractPlugin.storeValues()</methodname>
1139                methods.
1140              </para>
1141              <para>
1142                The configure method works much like the <methodname>Plugin.run()</methodname> 
1143                method. It must return the result in the <classname>Response</classname> object,
1144                and should not trow any exceptions.
1145              </para>
1146             
1147              <example id="net.sf.basedb.core.plugin.InteractivePlugin.configure">
1148                <title>
1149                  Configuration implementation building on the examples above
1150                </title>
1151<programlisting>public void configure(GuiContext context, Request request, Response response)
1152{
1153   String command = request.getCommand();
1154   try
1155   {
1156      if (command.equals(Request.COMMAND_CONFIGURE_PLUGIN))
1157      {
1158         // TODO
1159      }
1160      else if (command.equals(Request.COMMAND_CONFIGURE_JOB))
1161      {
1162         // Validate user input
1163         List&lt;Throwable&gt; errors =
1164            validateRequestParameters(getConfigureJob().getParameters(), request);
1165         if (errors != null)
1166         {
1167            response.setError(errors.size() +
1168               " invalid parameter(s) were found in the request", errors);
1169            return;
1170         }
1171         
1172         // Store user input
1173         storeValue(job, request, fileParameter);
1174         storeValue(job, request, updateExistingParameter);
1175         
1176         // We are happy and done
1177         response.setDone("Job configuration complete", Job.ExecutionTime.SHORT);
1178         // TODO - check file size to make a better estimate of execution time
1179      }
1180   }
1181   catch (Throwable ex)
1182   {
1183      response.setError(ex.getMessage(), Arrays.asList(ex));
1184   }
1185}</programlisting>
1186              </example>
1187             
1188              <para>
1189                Note that the call to
1190                <methodname>response.setDone()</methodname>
1191                has a second parameter
1192                <constant>Job.ExecutionTime.SHORT</constant>. It is an indication
1193                about how long time it will take to execute the
1194                plug-in. This is of interest for job queue managers which probably
1195                does not want to start too many long-running jobs at the same time
1196                blocking the entire system. Please try to use this parameter wisely and
1197                not use <constant>Job.ExecutionTime.SHORT</constant>
1198                out of old habit all the time.
1199              </para>
1200              <para>
1201                The <classname>Response</classname> class also has a
1202                <methodname>setContinue()</methodname>
1203                method which tells the core that the plug-in needs more parameters,
1204                i.e. the core will then call
1205                <methodname>getRequestInformation()</methodname>
1206                again with the new command, let the user enter values, and then call
1207                <methodname>configure()</methodname>
1208                with the new values. This process is repeated until the plug-in
1209                reports that it is done or an error occurs.
1210              </para>
1211              <para>
1212                An important note is that during this iteration it is the same instance
1213                of the plug-in that is used. However, no parameter values are stored in
1214                the database until the plugin sends a
1215                <methodname>response.setDone()</methodname>.
1216                After that, the plug-in instance is usually discarded, and a job is placed
1217                in the job queue. The execution of the plug-in happens in a new instance
1218                and maybe on a different server.
1219              </para>
1220              <tip>
1221                  <para>
1222                    You do not have to store all values the plug-in asked for in the
1223                    first place. You may even choose to store different values than
1224                    those that were entered. For example, you might ask for the mass
1225                    and height of a person and then only store the body mass index,
1226                    which is calculated from those values.
1227                  </para>
1228              </tip>
1229            </listitem>
1230          </varlistentry>
1231        </variablelist>
1232      </sect3>
1233   
1234    </sect2>
1235 
1236    <sect2 id="plugin_developer.api.callsequence">
1237      <title>What happens when...</title>
1238     
1239      <para>
1240        This section describes how the BASE core interacts with the
1241        plug-in in a number of use cases. We will outline the
1242        order the methods are invoked on the plug-in.
1243      </para>
1244     
1245      <sect3 id="plugin_developer.api.callsequence.install">
1246        <title>Installing a plug-in</title>
1247       
1248        <para>
1249          When a plug-in is installed the core is eager to find out
1250          information about the plug-in. To do this it calls the
1251          following methods in this order:
1252        </para>
1253       
1254        <orderedlist>
1255        <listitem>
1256          <para>
1257          A new instance of the plug-in class is created. The plug-in must
1258          have a public no-argument constructor.
1259          </para>
1260        </listitem>
1261       
1262        <listitem>
1263          <para>
1264          Calls are made to <methodname>Plugin.getMainType()</methodname>,
1265          <methodname>Plugin.supportsConfigurations()</methodname>,
1266          <methodname>Plugin.requiresConfiguration()</methodname> and
1267          <methodname>Plugin.getAbout()</methodname> to find out information
1268          about the plug-in. This is the only time theese methods are called.
1269          The information that is returned by them are copied and stored in
1270          the database for easy access.
1271          </para>
1272         
1273          <note>
1274            <para>
1275            The <methodname>Plugin.init()</methodname> method is
1276            never called during plug-in installation.
1277            </para>
1278          </note>
1279        </listitem>
1280       
1281        <listitem>
1282          <para>
1283          If the plug-in implements the <interfacename>InteractivePlugin</interfacename>
1284          interface the <methodname>InteractivePlugin.getGuiContexts()</methodname>
1285          method is called. This is the only time this method. The information it
1286          returns are copied and stored in the database.
1287          </para>
1288        </listitem>
1289       
1290        <listitem>
1291          <para>
1292          If the server admin decided to use the plug-in permission system, the
1293          <methodname>Plugin.getPermissions()</methodname> method is called.
1294          The returned information is copied and stored in the database.
1295          </para>
1296        </listitem>
1297       
1298        </orderedlist>
1299      </sect3>
1300   
1301      <sect3 id="plugin_developer.api.callsequence.configure">
1302        <title>Configuring a plug-in</title>
1303       
1304        <para>
1305          The plug-in must implement the <interfacename>InteractivePlugin</interfacename>
1306          interface and the <methodname>Plugin.supportsConfigurations()</methodname> method
1307          must return <constant>TRUE</constant>. The configuration is done with
1308          a wizard-like interface (see <xref linkend="plugins.configuration.wizard" />).
1309          The same plug-in instance is used throughout the entire configuration sequence.
1310        </para>
1311       
1312        <orderedlist>
1313        <listitem>
1314          <para>
1315          A new instance of the plug-in class is created. The plug-in must
1316          have a public no-argument constructor.
1317          </para>
1318        </listitem>
1319       
1320        <listitem>
1321          <para>
1322          The <methodname>Plugin.init()</methodname> method is called. The
1323          <varname>job</varname> parameter is null.
1324          </para>
1325        </listitem>
1326       
1327        <listitem id="plugin_developer.api.callsequence.configure.requestinformation">
1328          <para>
1329          The <methodname>InteractivePlugin.getRequestInformation()</methodname> 
1330          method is called. The <varname>context</varname> parameter is <constant>null</constant>
1331          and the <varname>command</varname> is the value of the string
1332          constant <constant>Request.COMMAND_CONFIGURE_PLUGIN</constant> 
1333          (_config_plugin).
1334          </para>
1335        </listitem>
1336       
1337        <listitem id="plugin_developer.api.callsequence.configure.form">
1338          <para>
1339          The web client process this information and displays a form for user
1340          input. The plug-in will have to wait some time while the user enters
1341          data.
1342          </para>
1343        </listitem>
1344       
1345        <listitem>
1346          <para>
1347          The <methodname>InteractivePlugin.configure()</methodname> method
1348          is called. The <varname>context</varname> parameter is still
1349          <constant>null</constant> and the <varname>request</varname>
1350          parameter contains the parameter values entered by the user.
1351          </para>
1352        </listitem>
1353       
1354        <listitem>
1355          <para>
1356          The plug-in must validate the values and decide whether they should be
1357          stored in the database or not. We recommend that you use the
1358          methods in the <classname>AbstractPlugin</classname> class for this.
1359          </para>
1360        </listitem>
1361       
1362        <listitem>
1363          <para>
1364          The plug-in has three different respones:
1365         
1366          <itemizedlist>
1367          <listitem>
1368            <para>
1369            <methodname>Response.setDone()</methodname>: The configuration
1370            is complete. The core will write any configuation changes to the
1371            database, call the <methodname>Plugin.done()</methodname> method and
1372            then discard the plug-in instance.
1373            </para>
1374          </listitem>
1375         
1376          <listitem>
1377            <para>
1378            <methodname>Response.setError()</methodname>: There was one or more
1379            errors. The web client will display the error messages for the user and
1380            allow the user to enter new values. The process continues with
1381            step <xref linkend="plugin_developer.api.callsequence.configure.form" />.
1382            </para>
1383          </listitem>
1384         
1385          <listitem>
1386            <para>
1387            <methodname>Response.setContinue()</methodname>: The parameters are correct
1388            but the plug-in wants more parameters. The process continues with
1389            step <xref linkend="plugin_developer.api.callsequence.configure.requestinformation" />.
1390            </para>
1391          </listitem>
1392          </itemizedlist>
1393         
1394          </para>
1395        </listitem>
1396        </orderedlist>
1397
1398      </sect3>   
1399   
1400      <sect3 id="plugin_developer.api.callsequence.context">
1401        <title>Checking if a plug-in can be used in a given context</title>
1402       
1403        <para>
1404          If the plug-in is an <interfacename>InteractivePlugin</interfacename>
1405          it has specified in which contexts it can be used by the
1406          information returned from <methodname>InteractivePlugin.getGuiContexts()</methodname>
1407          method. The web client uses this information to decide whether,
1408          for example, a <guibutton>Run plugin</guibutton>
1409          button should be displayed on a page or not. However, this is not
1410          always enough to know whether the plug-in can be used or not.
1411          For example, a raw data importer plug-in cannot be used to
1412          import raw data if the raw bioassay already has data.
1413          So, when the user clicks the button, the web client will
1414          load all plug-ins that possibly can be used in the given context
1415          and let each one of them check whether they can be used or not.
1416        </para>
1417       
1418     
1419        <orderedlist>
1420        <listitem>
1421          <para>
1422          A new instance of the plug-in class is created. The plug-in must
1423          have a public no-argument constructor.
1424          </para>
1425        </listitem>
1426       
1427        <listitem>
1428          <para>
1429          The <methodname>Plugin.init()</methodname> method is called.
1430          The <varname>job</varname> parameter is <constant>null</constant>.
1431          The <varname>configuration</varname> parameter is <constant>null</constant>
1432          if the plug-in does not have any configuration parameters.
1433          </para>
1434        </listitem>
1435       
1436        <listitem>
1437          <para>
1438          The <methodname>InteractivePlugin.isInContext()</methodname>
1439          is called. If the context is a list context, the <varname>item</varname>
1440          parameter is null, otherwise the current item is passed. The plug-in
1441          should return <constant>null</constant> if it can be used under the
1442          current circumstances, or a message explaining why not.
1443          </para>
1444        </listitem>
1445       
1446        <listitem>
1447          <para>
1448            After this, the plug-in instance is discarded. If there are
1449            several configurations for a plug-in, this procedure is repeated
1450            for each configuration.
1451          </para>
1452
1453          <warning>
1454          <para>
1455            The <methodname>Plugin.done()</methodname> method is never
1456            called! This is bug that has been reported to the developers
1457            and hopefully it will be fixed shortly.
1458          </para>
1459          </warning>
1460        </listitem>
1461        </orderedlist>
1462      </sect3>
1463   
1464      <sect3 id="plugin_developer.api.callsequence.job">
1465        <title>Creating a new job</title>
1466       
1467        <para>
1468          If the web client found that the plug-in could be
1469          used in a given context and the user selected the plug-in
1470          the job configuration sequence is started. It is a wizard-like interface
1471          identical to the configuration wizard. In fact, the same JSP pages,
1472          and calling sequence is used. See <xref linkend="plugin_developer.api.callsequence.configure" />.
1473          We do not repeat everything here. There are a few differences:
1474        </para>
1475       
1476        <itemizedlist>
1477        <listitem>
1478          <para>
1479          The <varname>job</varname> parameter is not null, but it does not contain
1480          any parameter values to start with. The plug-in should use this
1481          object to store job-related parameter values. The
1482          <varname>configuration</varname> parameter is <constant>null</constant> 
1483          if the plug-in is started without configuration. In any case,
1484          the configuration values are write-protected and cannot be modified.
1485          </para>
1486        </listitem>
1487       
1488        <listitem>
1489          <para>
1490          The first call to <methodname>InteractivePlugin.getRequestInformation()</methodname>
1491          is done with <constant>Request.COMMAND_CONFIGURE_JOB</constant> (_configjob)
1492          as the command. The <varname>context</varname> parameter reflects the
1493          current context.
1494          </para>
1495        </listitem>
1496       
1497        <listitem>
1498          <para>
1499          When calling <methodname>Response.setDone()</methodname> the plug-in
1500          should use the variant that takes an estimated execution time.
1501          If the plug-in has support for immediate execution or download
1502          (export plug-ins only), it can also respond with
1503          <methodname>Response.setExecuteImmediately()</methodname> or
1504          <methodname>Response.setDownloadImmediately()</methodname>.
1505          </para>
1506         
1507          <para>
1508          If the plug-in requested and was granted immediate execution or
1509          download the same plug-in instance is used to execute the plug-in.
1510          This may be done with the same or a new thread. Otherwise, a new
1511          job is added to the job queue, the parameter value are saved
1512          and the plug-in instance is discarded after calling the
1513          <methodname>Plugin.done()</methodname> method.
1514          </para>
1515        </listitem>
1516        </itemizedlist>
1517      </sect3>
1518   
1519      <sect3 id="plugin_developer.api.callsequence.execute">
1520        <title>Executing a job</title>
1521       
1522        <para>
1523          Normally, the creation of a job and the execution of it are
1524          two different events. The execution may as well be done on a
1525          different server. See <xref linkend="installation_upgrade.jobagents" />.
1526          This means that the execution takes place in a different instance
1527          of the plug-in class than what was used for creating the job.
1528          The exception is if a plug-in supports immediate execution or download.
1529          In this case the same instance is used, and it, of course,
1530          is always executed on the web server.
1531        </para>
1532       
1533        <orderedlist>
1534        <listitem>
1535          <para>
1536          A new instance of the plug-in class is created. The plug-in must
1537          have a public no-argument constructor.
1538          </para>
1539        </listitem>
1540       
1541        <listitem>
1542          <para>
1543          The <methodname>Plugin.init()</methodname> method is called.
1544          The <varname>job</varname> parameter contains the job
1545          configuration paramters. The <varname>configuration</varname> parameter
1546          is <constant>null</constant> if the plug-in does not have any
1547          configuration parameters.
1548          </para>
1549        </listitem>
1550       
1551        <listitem>
1552          <para>
1553          The <methodname>Plugin.run()</methodname> method is called.
1554          It is finally time for the plug-in to do the work it has bee
1555          designed for. This method should not throw any exceptions.
1556          Use the <methodname>Response.setDone()</methodname>
1557          method to report success or the <methodname>Response.setError()</methodname>
1558          to reporter errors.
1559          </para>
1560        </listitem>
1561       
1562        <listitem>
1563          <para>
1564          In both cases the <methodname>Plugin.done()</methodname>
1565          method is called and the plug-in instance is discarded.
1566          </para>
1567        </listitem>
1568       
1569        </orderedlist>
1570      </sect3>
1571   
1572    </sect2>
1573 
1574    <sect2 id="plugin_developer.api.jspparameters">
1575      <title>Using custom JSP pages for parameter input</title>
1576
1577        <para>
1578          This is an advanced option for plug-ins that require a different interface for
1579          specifying plug-in parameters than the default list showing each parameter at a
1580          time. This feature is used by setting the RequestInformation.getJspPage()
1581          property when constructing the request information object. If this property has
1582          a non-null value, the web client will send the browser to the specified JSP page
1583          instead of to the generic parameter input page.
1584        </para>
1585        <para>
1586          When setting the JSP page you should only set the file name. Do not include
1587          any path information. The web
1588          client has a special location for these JSP pages, generated from the package
1589          name of your plug-in. If the plug-in is located in the package
1590          <classname>org.company</classname>
1591          the JSP page must be located in
1592          <filename class="directory">&lt;base-dir&gt;/www/plugins/org/company/</filename>.
1593          Please note that the browser still thinks that it is showing the regular page
1594          at the usual location:
1595          <filename class="directory">&lt;base-dir&gt;/www/common/plugin/index.jsp</filename>.
1596          All links in your JSP page should be relative to that directory.
1597        </para>
1598        <para>
1599          Even if you use your own JSP page we recommend that you use the built-in
1600          facility for passing the parameters back to the plug-in. For this to work you
1601          must:
1602        </para>
1603        <itemizedlist spacing="compact">
1604          <listitem>
1605            <simpara>
1606            Generate the list of <classname>PluginParameter</classname> 
1607            objects as usual.
1608            </simpara>
1609          </listitem>
1610          <listitem>
1611            <simpara>
1612              Name all your input fields in the JSP like:
1613              <parameter>
1614                parameter:<replaceable>name-of-parameter</replaceable>
1615              </parameter>
1616            </simpara>
1617<programlisting>// Plugin generate PluginParameter
1618StringParameterType stringPT = new StringParameterType(255, null, true);
1619PluginParameter one = new PluginParameter("one", "One", "First string", stringPT);
1620PluginParameter two = new PluginParameter("two", "Two", "Second string", stringPT);
1621
1622// JSP should name fields as:
1623First string: &lt;input type="text" name="parameter:one"&gt;&lt;br&gt;
1624Second string: &lt;input type="text" name="parameter:two"&gt;</programlisting>
1625          </listitem>
1626          <listitem>
1627          <simpara>
1628            Send the form to
1629            <filename>index.jsp</filename>
1630            with the <varname>ID</varname> and <varname>cmd</varname> parameters
1631            as shown below.
1632          </simpara>
1633<programlisting>&lt;form action="index.jsp" method="post"&gt;
1634&lt;input type="hidden" name="ID" value="&lt;%=ID%&gt;"&gt;
1635&lt;input type="hidden" name="cmd" value="SetParameters"&gt;
1636...
1637&lt;/form&gt;</programlisting>
1638
1639          </listitem>
1640          </itemizedlist>
1641            <para>
1642              In your JSP page you will probably need to access some information like the
1643              <classname>SessionControl</classname>, <classname>Job</classname>
1644              and possible even the <classname>RequestInformation</classname>
1645              object created by your plug-in.
1646            </para>
1647<programlisting>// Get session control and it's ID (required to post to index.jsp)
1648final SessionControl sc = Base.getExistingSessionControl(pageContext, true);
1649final String ID = sc.getId();
1650
1651// Get information about the current request to the plug-in
1652PluginConfigurationRequest pcRequest =
1653   (PluginConfigurationRequest)sc.getSessionSetting("plugin.configure.request");
1654PluginDefinition plugin =
1655   (PluginDefinition)sc.getSessionSetting("plugin.configure.plugin");
1656PluginConfiguration pluginConfig =
1657   (PluginConfiguration)sc.getSessionSetting("plugin.configure.config");
1658PluginDefinition job =
1659   (PluginDefinition)sc.getSessionSetting("plugin.configure.job");
1660RequestInformation ri = pcRequest.getRequestInformation();</programlisting>
1661
1662    </sect2>
1663  </sect1>
1664
1665  <sect1 id="plugin_developer.import">
1666    <title>Import plug-ins</title>
1667    <para>
1668   
1669      This documentation is only available in the old format.
1670      See <ulink url="http://base.thep.lu.se/chrome/site/doc/development/plugins/import/index.html"
1671        >http://base.thep.lu.se/chrome/site/doc/development/plugins/import/index.html</ulink>
1672    </para>
1673   
1674    <sect2 id="plugin_developer.import.autodetect">
1675      <title>Autodetecting importer</title>
1676      <para></para>
1677    </sect2>
1678   
1679    <sect2 id="plugin_developer.import.abstractflatfileimporter">
1680      <title>The AbstractFlatFileImporter superclass</title>
1681      <para></para>
1682    </sect2>
1683  </sect1>
1684
1685  <sect1 id="plugin_developer.export">
1686    <title>Export plug-ins</title>
1687   
1688    <para>
1689      Export plug-ins are plug-ins that takes data from BASE, and
1690      prepares it for use with some external entity. Usually this
1691      means that data is taken from the database and put into a file
1692      with some well-defined file format.
1693      An export plug-in should return <constant>MainType.EXPORT</constant> from
1694      the <methodname>Plugin.getMainType()</methodname> method.
1695    </para>
1696   
1697    <sect2 id="plugin_developer.export.download">
1698      <title>Immediate download of exported data</title>
1699      <para>
1700        An export plug-in may want to give the user a choice
1701        between saving the exported data in the BASE file system
1702        or to download it immediately to the client computer. With the basic
1703        plug-in API the second option is not possible. The
1704        <interfacename>ImmediateDownloadExporter</interfacename> is an
1705        interface that extends the <interfacename>Plugin</interfacename>
1706        interface to provide this functionality. If your export
1707        plug-in wants to provide immediate download functionality it must
1708        implement the <interfacename>ImmediateDownloadExporter</interfacename>
1709        interface.
1710      </para>
1711     
1712      <sect3 id="plugin_developer.export.immediatedownloadexporter">
1713      <title>The ImmediateDownloadExporter interface</title>
1714      <variablelist>
1715      <varlistentry>
1716        <term>
1717          <methodsynopsis language="java">
1718            <modifier>public</modifier>
1719            <void/>
1720            <methodname>doExport</methodname>
1721            <methodparam>
1722              <type>ExportOutputStream</type>
1723              <parameter>out</parameter>
1724            </methodparam>
1725            <methodparam>
1726              <type>ProgressReporter</type>
1727              <parameter>progress</parameter>
1728            </methodparam>
1729          </methodsynopsis>
1730        </term>
1731        <listitem>
1732          <para>
1733          Perform the export. The plug-in should write the
1734          exported data to the <varname>out</varname> stream.
1735          If the <varname>progress</varname> parameter is not null,
1736          the progress should be reported at regular interval in the
1737          same manner as in the <methodname>Plugin.run()</methodname>
1738          method.
1739          </para>
1740        </listitem>
1741      </varlistentry>
1742      </variablelist>
1743     
1744      </sect3>
1745     
1746      <sect3 id="plugin_developer.export.exportoutputstream">
1747      <title>The ExportOutputStream class</title>
1748     
1749      <para>
1750        The <classname>ExportOutputStream</classname> is extends
1751        <classname>java.io.OutputStream</classname>. Use the regular
1752        <methodname>write()</methodname> methods to write data to it.
1753        It also has three additional methods, which are used to generate
1754        HTTP response headers.
1755      </para>
1756     
1757      <note>
1758        <para>
1759        These methods must be called before starting to write data to
1760        the <varname>out</varname> stream.
1761        </para>
1762      </note>
1763     
1764      <variablelist>
1765      <varlistentry>
1766        <term>
1767          <methodsynopsis language="java">
1768            <modifier>public</modifier>
1769            <void/>
1770            <methodname>setContentLength</methodname>
1771            <methodparam>
1772              <type>long</type>
1773              <parameter>contentLength</parameter>
1774            </methodparam>
1775          </methodsynopsis>
1776        </term>
1777        <listitem>
1778          <para>
1779          Set the total size of the exported data (if known).
1780          </para>
1781        </listitem>
1782      </varlistentry>
1783      <varlistentry>
1784        <term>
1785          <methodsynopsis language="java">
1786            <modifier>public</modifier>
1787            <void/>
1788            <methodname>setMimeType</methodname>
1789            <methodparam>
1790              <type>String</type>
1791              <parameter>mimeType</parameter>
1792            </methodparam>
1793          </methodsynopsis>
1794        </term>
1795        <listitem>
1796          <para>
1797          Set the MIME type of the file that is beeing generated.
1798          </para>
1799        </listitem>
1800      </varlistentry>
1801      <varlistentry>
1802        <term>
1803          <methodsynopsis language="java">
1804            <modifier>public</modifier>
1805            <void/>
1806            <methodname>setFilename</methodname>
1807            <methodparam>
1808              <type>String</type>
1809              <parameter>filename</parameter>
1810            </methodparam>
1811          </methodsynopsis>
1812        </term>
1813        <listitem>
1814          <para>
1815          Set a suggested name of the file that is beeing
1816          generated.
1817          </para>
1818        </listitem>
1819      </varlistentry>
1820      </variablelist>
1821     
1822      </sect3>
1823     
1824      <sect3 id="plugin_developer.export.callsequence">
1825        <title>Call sequence during immediate download</title>
1826
1827      <para>
1828        Supporting immediate download also means that the method call
1829        sequence is a bit altered from the standard sequence described
1830        in <xref linkend="plugin_developer.api.callsequence.execute" />.
1831      </para>
1832     
1833      <itemizedlist>
1834      <listitem>
1835        <para>
1836        The plug-in must call <methodname>Response.setDownloadImmediately()</methodname>
1837        instead of <methodname>Response.setDone()</methodname> in <methodname>Plugin.configure()</methodname>
1838        to to end the job configuration wizard. This requests that the core starts
1839        an immediate download.
1840        </para>
1841       
1842        <note>
1843          <para>
1844          Even if an immediate download is requested by the plug-in this feature
1845          may have been disabled by the server administrator. If so, the plug-in
1846          can choose if the job should be added to job queue or if this is an
1847          error condition.
1848          </para>
1849        </note>
1850      </listitem>
1851     
1852      <listitem>
1853        <para>
1854        If immediate download is granted the web client will keep the
1855        same plug-in instance and call <methodname>ImmediateDownloadExporter.doExport()</methodname>.
1856        In this case, the <methodname>Plugin.run()</methodname> is never called.
1857       
1858        <note>
1859          <para>
1860          The <methodname>Plugin.done()</methodname> method is also never
1861          called. This is a bug which has been reported to the developers.
1862          </para>
1863        </note>
1864        </para>
1865       
1866      </listitem>
1867
1868      <listitem>
1869        <para>
1870        If immediate download is not granted and the job is added to the job queue
1871        the regular job execution sequence is used. That is, the
1872        <methodname>Plugin.run()</methodname> method is called.
1873        </para>
1874      </listitem>
1875      </itemizedlist>
1876     
1877      </sect3>
1878
1879    </sect2>
1880   
1881    <sect2 id="plugin_developer.export.abstractexporter">
1882      <title>The AbstractExporterPlugin class</title>
1883   
1884      <para>
1885        This is an abstract superclass that will make it easier
1886        to implement export plug-ins that support immediate
1887        download. It defines <classname>PluginParameter</classname>
1888        objects for asking a user about a path where the exported
1889        data should be saved and if existing files should be overwritten or not.
1890        If the user leaves the path empty the immediate download functionality
1891        should be used. It also contains implementations of both the
1892        <methodname>Plugin.run()</methodname> method and the
1893        <methodname>ImmediateDownloadExporter.doExport()</methodname> method.
1894        Here is what you need to do in your own plug-in code (code examples are
1895        take from the <classname>HelpExporter</classname>):
1896      </para>
1897     
1898      <itemizedlist>
1899      <listitem>
1900        <para>
1901          Your plug-in should extend the <classname>AbstractExporterPlugin</classname>
1902          class:
1903          <programlisting>
1904public class HelpExporter
1905  extends AbstractExporterPlugin
1906  implements InteractivePlugin
1907</programlisting>
1908        </para>
1909      </listitem>
1910     
1911      <listitem>
1912        <para>
1913          You need to implement the
1914          <methodname>InteractivePlugin.getRequestInformation()</methodname>
1915          method. Use the <methodname>getSaveAsParameter()</methodname>
1916          and <methodname>getOverwriteParameter()</methodname> methods defined in the
1917          superclass to create plug-in parameters that asks for the file name to save
1918          to and if existing files can be overwritten or not.
1919          You should also check if the administrator has enabled the immediate execution
1920          functionality for your plug-in. If not, the only option is to
1921          export to a file in the BASE file system and the filename is a
1922          required parameter.
1923         
1924          <programlisting>
1925// Selected parts of the getRequestConfiguration() method
1926...
1927List&lt;PluginParameter&lt;?&gt;&gt; parameters =
1928   new ArrayList&lt;PluginParameter&lt;?&gt;&gt;();
1929...
1930PluginDefinition pd = job.getPluginDefinition();
1931boolean requireFile = pd == null ?
1932   false : !pd.getAllowImmediateExecution();
1933
1934parameters.add(getSaveAsParameter(null, null, defaultPath, requireFile));
1935parameters.add(getOverwriteParameter(null, null));
1936
1937configureJob = new RequestInformation
1938(
1939   Request.COMMAND_CONFIGURE_JOB,
1940   "Help exporter options",
1941   "Set Client that owns the helptexts, " +
1942     "the file path where the export file should be saved",
1943   parameters
1944);
1945....
1946return configureJob;
1947</programlisting>
1948        </para>
1949      </listitem>
1950
1951      <listitem>
1952        <para>
1953        You must also implement the <methodname>configure()</methodname>
1954        method and check the parameters. If no filename has been given,
1955        you should check if immediate exection is allowed and set an
1956        error if it is not. If a filename is present, use the
1957        <methodname>pathCanBeUsed()</methodname> method to check if
1958        it is possible to save the data to a file with that name. If the
1959        file already exists it can be overwritten if the <varname>OVERWRITE</varname>
1960        is <constant>TRUE</constant> or if the file has been flagged for removal.
1961        Do not forget to store the parameters with the <methodname>storeValue()</methodname>
1962        method.
1963
1964        <programlisting>
1965// Selected parts from the configure() method
1966if (request.getParameterValue(SAVE_AS) == null)
1967{
1968   if (!request.isAllowedImmediateExecution())
1969   {
1970      response.setError("Immediate download is not allowed. " +
1971         "Please specify a filename.", null);
1972      return;
1973   }
1974   Client client = (Client)request.getParameterValue("client");
1975   response.setDownloadImmediately("Export help texts for client application " +
1976     client.getName(), ExecutionTime.SHORTEST, true);
1977}
1978else
1979{
1980   if (!pathCanBeUsed((String)request.getParameterValue(SAVE_AS),
1981      (Boolean)request.getParameterValue(OVERWRITE)))
1982   {
1983      response.setError("File exists: " +
1984         (String)request.getParameterValue(SAVE_AS), null);
1985      return;
1986   }
1987   storeValue(job, request, ri.getParameter(SAVE_AS));
1988   storeValue(job, request, ri.getParameter(OVERWRITE));
1989   response.setDone("The job configuration is complete", ExecutionTime.SHORTEST);
1990}
1991</programlisting>
1992       
1993        </para>
1994      </listitem>
1995     
1996      <listitem>
1997        <para>
1998        Implement the <methodname>performExport()</methodname> method.
1999        This is defined as abstract in the <classname>AbstractExporterPlugin</classname>
2000        class. It has the same parameters as the <methodname>ImmediateDownloadExporter.doExport()</methodname>
2001        method and they have the same meaning. The only difference is that the
2002        <varname>out</varname> stream can be linked to a file and not just to the
2003        immediate download.
2004        </para>
2005      </listitem>
2006     
2007      <listitem>
2008        <para>
2009        Optionally, implement the <methodname>begin()</methodname>,
2010        <methodname>end()</methodname> and <methodname>getSuccessMessage()</methodname>
2011        methods. Theese methods do nothing by default.
2012        </para>
2013      </listitem>
2014      </itemizedlist>
2015     
2016      <para>
2017        The call sequence for plug-ins extending <classname>AbstractExporterPlugin</classname>
2018        is:
2019      </para>
2020     
2021      <orderedlist>
2022      <listitem>
2023        <para>
2024        Call <methodname>begin()</methodname>.
2025        </para>
2026      </listitem>
2027      <listitem>
2028        <para>
2029        Call <methodname>performExport()</methodname>.
2030        </para>
2031      </listitem>
2032      <listitem>
2033        <para>
2034        Call <methodname>end()</methodname>.
2035        </para>
2036      </listitem>
2037      <listitem>
2038        <para>
2039        Call <methodname>getSuccessMessage()</methodname> if running as a regular
2040        job. This method is never called when doing an immediate download since there
2041        is no place to show the message.
2042        </para>
2043      </listitem>
2044      </orderedlist>
2045     
2046    </sect2>
2047   
2048  </sect1>
2049 
2050  <sect1 id="plugin_developer.analyse">
2051    <title>Analysis plug-ins</title>
2052    <para>
2053      A plug-in becomes an analysis plug-in simply by returning
2054      <constant>Plugin.MainType.ANALYSIS</constant> from the
2055      <methodname>Plugin.getMainType()</methodname> method. The information returned from
2056      <methodname>InteractivePlugin.getGuiContexts()</methodname>
2057      must include: [<constant>Item.BIOASSAYSET</constant>, <constant>Type.ITEM</constant>] since
2058      this is the only place where the web client looks for analysis plug-ins.
2059    </para>
2060   
2061<programlisting>private static final Set&lt;GuiContext&gt; guiContexts =
2062   Collections.singleton(new GuiContext(Item.BIOASSAYSET, GuiContext.Type.ITEM));
2063
2064public Set&lt;GuiContext&gt; getGuiContexts()
2065{
2066   return guiContexts;
2067}</programlisting>
2068
2069      <para>
2070        More documentation is available in the old format.
2071        See <ulink url="http://base.thep.lu.se/chrome/site/doc/development/plugins/analysis/index.html"
2072          >http://base.thep.lu.se/chrome/site/doc/development/plugins/analysis/index.html</ulink>
2073      </para>
2074
2075
2076  </sect1>
2077 
2078  <sect1 id="plugin_developer.other">
2079    <title>Other plug-ins</title>
2080    <para></para>
2081   
2082    <sect2 id="plugin_developer.other.authentication">
2083      <title>Authentication plug-ins</title>
2084     
2085      <para>
2086        BASE provides a plug-in mechanism for authenticating users
2087        (validating the username and password) when they are logging in.
2088        This plug-in mechanism is not the same as the regular plug-in API.
2089        That is, you do not have worry about user interaction or implementing the
2090        <interfacename>Plugin</interfacename> interface.
2091      </para>
2092     
2093      <sect3 id="plugin_developer.other.authentication.internal_external">
2094        <title>Internal vs. external authentation</title>
2095     
2096        <para>
2097          BASE can authenticate users in two ways. Either it uses the internal
2098          authentiction or the external authentication. With internal
2099          authentication BASE stores logins and passwords in it's own database.
2100          With external authentication this is handled by some external
2101          application. Even with external authentication it is possible to
2102          let BASE cache the logins/passwords. This makes it possible to login to
2103          BASE if the external authentication server is down.
2104        </para>
2105       
2106        <note>
2107          <para>
2108          An external authentication server can only be used to grant or deny
2109          a user access to BASE. It cannot be used to give a user permissions,
2110          or put a user into groups or different roles inside BASE.
2111          </para>
2112        </note>
2113
2114        <para>
2115          The external authentication service is only used when a user logs in.
2116          Now, one or more of several things can happen:
2117         
2118          <itemizedlist>
2119          <listitem>
2120            <para>
2121              The ROOT user is logging on. Internal authentication is always
2122              used for the root user and the authenticator plug-in is never
2123              used.
2124            </para>
2125          </listitem>
2126
2127          <listitem>
2128            <para>
2129              The login is correct and the user is already known to BASE.
2130              If the plug-in supports extra information (name, email, phone, etc.)
2131              and the <property>auth.synchronize</property> setting
2132              is <constant>TRUE</constant> the extra information is copied to
2133              the BASE server.
2134            </para>
2135          </listitem>
2136         
2137          <listitem>
2138            <para>
2139              The login is correct, but the user is not known to BASE. This happens
2140              the first time a user logs in. BASE will create
2141              a new user account. If the driver supports extra information, it
2142              is copied to the BASE server (even if <property>auth.synchronize</property> 
2143              is not set). The new user account will get the default quota
2144              and be added to the all roles and groups which has been
2145              marked as <emphasis>default</emphasis>.
2146             
2147              <note>
2148              <para>
2149                Prior to BASE 2.4 it was hardcoded to add the new user to the
2150                <emphasis>Users</emphasis> role only.
2151              </para>
2152              </note>
2153            </para>
2154          </listitem>
2155
2156          <listitem>
2157            <para>
2158              If password caching is enabled, the password is copied to BASE.
2159              If an expiration timeout has been set, an expiration date
2160              will be calculated and set on the user account. The expiration
2161              date is only checked when the external authentication server is
2162              down.
2163            </para>
2164          </listitem>
2165
2166          <listitem>
2167            <para>
2168              The authentication server says that the login is invalid or
2169              the password is incorrect. The user will not be logged in.
2170              If a user account with the specified login already exists in
2171              BASE, it will be disabled.
2172            </para>
2173          </listitem>
2174         
2175          <listitem>
2176            <para>
2177              The authentication driver says that something else is wrong.
2178              If password caching is enabled, internal authentication will be
2179              used. Otherwise the user will not be logged in. An already
2180              existing account is not modified or disabled.
2181            </para>
2182          </listitem>
2183          </itemizedlist>
2184         
2185          <note>
2186            <para>
2187            The <guilabel>Encrypt password</guilabel> option that is
2188            available on the login page does not work with external
2189            authentication. The simple reason is that the password is
2190            encrypted with a one-way algorithm making it impossible to
2191            call <methodname>Authenticator.authenticate()</methodname>.
2192            </para>
2193          </note>
2194         
2195        </para>
2196      </sect3>
2197     
2198      <sect3 id="plugin_developer.other.authentication.authenticator">
2199        <title>The Authenticator interface</title>
2200       
2201        <para>
2202          To be able to use external authentication you must create a class
2203          that implements the
2204          <interfacename>net.sf.based.core.authentication.Authenticator</interfacename> 
2205          interface. Specify the name of the class in the <property>auth.driver</property> 
2206          setting in <filename>base.config</filename> and
2207          it's initialisation parameters in the <property>auth.init</property> setting.
2208        </para>
2209       
2210        <para>
2211          Your class must have a public no-argument constructor. The BASE
2212          application will create only one instance of the class for lifetime
2213          of the BASE server. It must be thread-safe since it may be invoked by
2214          multiple threads at the same time. Here are the methods that you must
2215          implement
2216        </para>
2217       
2218        <variablelist>
2219        <varlistentry>
2220          <term>
2221            <methodsynopsis language="java">
2222              <modifier>public</modifier>
2223              <void/>
2224              <methodname>init</methodname>
2225              <methodparam>
2226                <type>String</type>
2227                <parameter>settings</parameter>
2228              </methodparam>
2229              <exceptionname>AuthenticationException</exceptionname>
2230            </methodsynopsis>
2231          </term>
2232          <listitem>
2233            <para>
2234            This method is called just after the object has been created with it's argument
2235            taken from the <property>auth.init</property> setting in your <filename>base.config</filename> 
2236            file. This method is only called once for an instance of the object. The syntax and meaning of
2237            the parameter is driver-dependent and should be documented by the plug-in.
2238            It is irrelevant for the BASE core.
2239            </para>
2240          </listitem>
2241        </varlistentry>
2242       
2243        <varlistentry>
2244          <term>
2245            <methodsynopsis language="java">
2246              <modifier>public</modifier>
2247              <type>boolean</type>
2248              <methodname>supportsExtraInformation</methodname>
2249            </methodsynopsis>
2250          </term>
2251          <listitem>
2252            <para>
2253            This method should simply return <constant>TRUE</constant> or <constant>FALSE</constant> 
2254            depending on if the plug-in supports extra user information or not. The only required
2255            information about a user is a unique ID and the login. Extra information includes
2256            name, address, phone, email, etc.
2257            </para>
2258          </listitem>       
2259        </varlistentry>
2260
2261        <varlistentry>
2262          <term>
2263            <methodsynopsis language="java">
2264              <modifier>public</modifier>
2265              <type>AuthenticationInformation</type>
2266              <methodname>authenticate</methodname>
2267              <methodparam>
2268                <type>String</type>
2269                <parameter>login</parameter>
2270              </methodparam>
2271              <methodparam>
2272                <type>String</type>
2273                <parameter>password</parameter>
2274              </methodparam>
2275              <exceptionname>UnknownLoginException</exceptionname>
2276              <exceptionname>InvalidPasswordException</exceptionname>
2277              <exceptionname>AuthenticationException</exceptionname>
2278            </methodsynopsis>
2279          </term>
2280          <listitem>
2281            <para>
2282            Try to authenticate a login/password combination. The plug-in should return
2283            an <classname>AuthenticationInformation</classname> object if the
2284            authentication is successful or throw an exception if not.
2285           
2286            There are three exceptions to choose from:
2287           
2288            <itemizedlist>
2289            <listitem>
2290              <para>
2291              <exceptionname>UnknownLoginException</exceptionname>:
2292              This exception should be thrown if the login is not know to the
2293              external authentication system.
2294              </para>
2295            </listitem>
2296
2297            <listitem>
2298              <para>
2299              <exceptionname>InvalidPasswordException</exceptionname>:
2300              This exception should be thrown if the login is known but the
2301              password is invalid. In case it is considered a security issue
2302              to reveal that a login exists, the plugin may throw an
2303              <exceptionname>UnknowLoginException</exceptionname> instead.
2304              </para>
2305            </listitem>
2306           
2307            <listitem>
2308              <para>
2309              <exceptionname>AuthenticationException</exceptionname>:
2310              In case there is another problem, such as the authentication service
2311              beeing down. This exception triggers the use of cached passwords
2312              if caching has been enabled.
2313              </para>
2314            </listitem>
2315            </itemizedlist>
2316            </para>
2317          </listitem>       
2318        </varlistentry>
2319        </variablelist> 
2320      </sect3>
2321     
2322      <sect3 id="plugin_developer.other.authentication.settings">
2323        <title>Configuration settings</title>
2324     
2325        <para>
2326          The configuration settings for the authentication driver are located
2327          in the <filename>base.config</filename> file.
2328          Here is an overview of the settings. For more information read
2329          <xref linkend="appendix.base.config.authentication" />.
2330        </para>
2331       
2332        <variablelist>
2333        <varlistentry>
2334          <term><property>auth.driver</property></term>
2335          <listitem>
2336            <para>
2337            The class name of the authentication plug-in.
2338            </para>
2339          </listitem>
2340        </varlistentry>
2341
2342        <varlistentry>
2343          <term><property>auth.init</property></term>
2344          <listitem>
2345            <para>
2346            Initialisation parameters sent to the plug-in when calling the
2347            <methodname>Authenticator.init()</methodname> method.
2348            </para>
2349          </listitem>
2350        </varlistentry>
2351       
2352        <varlistentry>
2353          <term><property>auth.synchronize</property></term>
2354          <listitem>
2355            <para>
2356            If extra user information is synchronized at login time or not.
2357            This setting is ignored if the driver does not support extra information.
2358            </para>
2359          </listitem>
2360        </varlistentry>
2361       
2362        <varlistentry>
2363          <term><property>auth.cachepasswords</property></term>
2364          <listitem>
2365            <para>
2366              If passwords should be cached by BASE or not. If the passwords are
2367              cached a user may login to BASE even if the external authentication
2368              server is down.
2369            </para>
2370          </listitem>
2371        </varlistentry>
2372       
2373        <varlistentry>
2374          <term><property>auth.daystocache</property></term>
2375          <listitem>
2376            <para>
2377              How many days to cache the passwords if caching has been enabled.
2378              A value of 0 caches the passwords for ever.     
2379            </para>
2380          </listitem>
2381        </varlistentry>
2382        </variablelist>
2383      </sect3>
2384     
2385    </sect2>
2386   
2387    <sect2 id="plugin_developer.other.secondary">
2388      <title>Secondary file storage plugins</title>
2389      <para>
2390        This documentation is only available in the old format.
2391        See <ulink url="http://base.thep.lu.se/chrome/site/doc/development/plugins/storage/index.html"
2392          >http://base.thep.lu.se/chrome/site/doc/development/plugins/storage/index.html</ulink>
2393      </para>
2394    </sect2>
2395   
2396    <sect2 id="plugin_developer.other.unpacker">
2397      <title>File unpacker plug-ins</title>
2398      <para>
2399        The BASE web client has integrated support for unpacking of
2400        compressed files. See <xref linkend="file_system.handling.upload" />.
2401        Behind the scenes, this support is provided by plug-ins. The standard
2402        BASE distribution comes with support for ZIP files
2403        (<classname>net.sf.basedb.plugins.ZipFileUnpacker</classname>).
2404      </para>
2405      <para>
2406        To add support for additional compressed formats you have to create a plug-in that
2407        implements the <interfacename>net.sf.basedb.util.zip.FileUnpacker</interfacename>
2408        interface. The best way to do this is to extend the
2409        <classname>net.sf.basedb.util.zip.AbstractFileUnpacker</classname> which
2410        implements all methods in the <interfacename>Plugin</interfacename>
2411        and <interfacename>InteractivePlugin</interfacename>
2412        interfaces except <methodname>Plugin.getAbout()</methodname>. This leaves
2413        you with the actual unpacking of the files as the only thing to implement.
2414      </para>
2415     
2416      <note>
2417        <title>No support for configurations</title>
2418        The integrated upload in the web interface only works with plug-ins that
2419        does not require a configuration to run.
2420      </note>
2421     
2422      <variablelist>
2423        <title>Methods in the <interfacename>FileUnpacker</interfacename> interface</title>
2424        <varlistentry>
2425          <term>
2426            <methodsynopsis language="java">
2427              <modifier>public</modifier>
2428              <type>String</type>
2429              <methodname>getFormatName</methodname>
2430            </methodsynopsis>
2431          </term>
2432          <listitem>
2433            <para>
2434            Return a short string naming the file format. For example:
2435            <constant>ZIP files</constant> or <constant>TAR files</constant>.
2436            </para>
2437          </listitem>
2438        </varlistentry>
2439           
2440        <varlistentry>
2441          <term>
2442            <methodsynopsis language="java">
2443              <modifier>public</modifier>
2444              <type>Set&lt;String&gt;</type>
2445              <methodname>getExtensions</methodname>
2446            </methodsynopsis>
2447          </term>
2448          <listitem>
2449            <para>
2450            Return a set of strings with the file extensions that
2451            are most commonly used with the compressed file format.
2452            For example: <constant>[zip, jar]</constant>. Do not include
2453            the dot in the extensions. The web client and the
2454            <methodname>AbstractFlatFileUnpacker.isInContext()</methodname> method
2455            will use this information to automatically guess which plug-in to
2456            use for unpacking the files.
2457            </para>
2458          </listitem>
2459        </varlistentry>
2460       
2461        <varlistentry>
2462          <term>
2463            <methodsynopsis language="java">
2464              <modifier>public</modifier>
2465              <type>Set&lt;String&gt;</type>
2466              <methodname>getMimeTypes</methodname>
2467            </methodsynopsis>
2468          </term>
2469          <listitem>
2470            <para>
2471            Return a set of string with the MIME types that commonly used with
2472            the compressed file format. For example:
2473            <constant>[application/zip, application/java-archive]</constant>.
2474            This information is used by the
2475            <methodname>AbstractFlatFileUnpacker.isInContext()</methodname> 
2476            method to automatically guess which plug-in to use for unpacking
2477            the files.
2478            </para>
2479          </listitem>
2480        </varlistentry>
2481       
2482        <varlistentry>
2483          <term>
2484            <methodsynopsis language="java">
2485              <modifier>public</modifier>
2486              <type>int</type>
2487              <methodname>unpack</methodname>
2488              <methodparam>
2489                <type>DbControl</type>
2490                <parameter>dc</parameter>
2491              </methodparam>
2492              <methodparam>
2493                <type>Directory</type>
2494                <parameter>dir</parameter>
2495              </methodparam>
2496              <methodparam>
2497                <type>InputStream</type>
2498                <parameter>in</parameter>
2499              </methodparam>
2500              <methodparam>
2501                <type>boolean</type>
2502                <parameter>overwrite</parameter>
2503              </methodparam>
2504              <methodparam>
2505                <type>AbsoluteProgressReporter</type>
2506                <parameter>progress</parameter>
2507              </methodparam>
2508              <exceptionname>IOException</exceptionname>
2509              <exceptionname>BaseException</exceptionname>
2510            </methodsynopsis>
2511          </term>
2512          <listitem>
2513            <para>
2514            Unpack the files and store them in the BASE file system.
2515           
2516            <itemizedlist>
2517            <listitem>
2518              <para>
2519              Do not <methodname>close()</methodname> or
2520              <methodname>commit()</methodname> the
2521              <classname>DbControl</classname> passed to this method.
2522              This is done automatically by the
2523              <classname>AbstractFileUnpacker</classname> or by the web client.
2524              </para>
2525            </listitem>
2526           
2527            <listitem>
2528              <para>
2529              The <varname>dir</varname> parameter is the root directory where
2530              the unpacked files should be placed. If the compressed file
2531              contains subdirectory the plug-in must create those subdirectories
2532              unless they already exists.
2533              </para>
2534            </listitem>
2535           
2536            <listitem>
2537              <para>
2538              If the <varname>overwrite</varname> parameter is
2539              <constant>FALSE</constant> no existing file should be overwritten
2540              unless the file is <systemitem>OFFLINE</systemitem>.
2541              </para>
2542            </listitem>
2543           
2544            <listitem>
2545              <para>
2546              The <varname>in</varname> parameter is the stream
2547              containing the compressed data. The stream may come
2548              directly from the web upload or from an existing
2549              file in the BASE file system.
2550              </para>
2551            </listitem>
2552           
2553            <listitem>
2554              <para>
2555              The <varname>progress</varname> parameter, if not
2556              <constant>null</constant>, should be used to reporter the
2557              progress back to the calling code. The plug-in should count
2558              the number of bytes read from the <varname>in</varname>
2559              stream.
2560              </para>
2561            </listitem>
2562            </itemizedlist>
2563           
2564            </para>
2565          </listitem>
2566        </varlistentry>
2567      </variablelist>
2568     
2569      <para>
2570        When the compressed file is uncompressed during the file upload
2571        from the web interface, the call sequence to the plug-in is slightly
2572        altered from the standard call sequence described in
2573        <xref linkend="plugin_developer.api.callsequence.execute" />.
2574       
2575        <itemizedlist>
2576        <listitem>
2577          <para>
2578          After the plug-in instance has been created, the
2579          <methodname>Plugin.init()</methodname> method is called with <constant>null</constant>
2580          values for both the <varname>configuration</varname> and <varname>job</varname>
2581          parameters.
2582          </para>
2583        </listitem>
2584       
2585        <listitem>
2586          <para>
2587          Then, the <methodname>unpack()</methodname> method is called. The
2588          <methodname>Plugin.run()</methodname> method is never called in this case.
2589          The <methodname>Plugin.done()</methodname> method is also never called.
2590          </para>
2591        </listitem>
2592       
2593        </itemizedlist>
2594       
2595      </para>
2596     
2597    </sect2>
2598  </sect1>
2599 
2600  <sect1 id="plugin_developer.example">
2601    <title>Example plug-ins (with download)</title>
2602    <para>
2603      <para>
2604        This documentation is only available in the old format.
2605        See <ulink url="http://base.thep.lu.se/chrome/site/doc/development/index.html#plugins"
2606          >http://base.thep.lu.se/chrome/site/doc/development/index.html#plugins</ulink>
2607      </para>
2608    </para>
2609  </sect1>
2610</chapter>
Note: See TracBrowser for help on using the repository browser.