doc/src/docbook/developer/plugins.xml

Code
Comments
Other
Rev Date Author Line
3160 05 Mar 07 martin 1 <?xml version="1.0" encoding="UTF-8"?>
3160 05 Mar 07 martin 2 <!DOCTYPE chapter PUBLIC 
3160 05 Mar 07 martin 3     "-//Dawid Weiss//DTD DocBook V3.1-Based Extension for XML and graphics inclusion//EN" 
3192 13 Mar 07 martin 4     "../../../../lib/docbook/preprocess/dweiss-docbook-extensions.dtd">
3160 05 Mar 07 martin 5 <!--
3166 06 Mar 07 enell 6   $Id$:
3166 06 Mar 07 enell 7   
3675 16 Aug 07 jari 8   Copyright (C) 2007 Johan Enell, Peter Johansson, Nicklas Nordborg, Martin Svensson
3166 06 Mar 07 enell 9   
3160 05 Mar 07 martin 10   This file is part of BASE - BioArray Software Environment.
3160 05 Mar 07 martin 11   Available at http://base.thep.lu.se/
3166 06 Mar 07 enell 12   
3160 05 Mar 07 martin 13   BASE is free software; you can redistribute it and/or
3160 05 Mar 07 martin 14   modify it under the terms of the GNU General Public License
4477 05 Sep 08 jari 15   as published by the Free Software Foundation; either version 3
3160 05 Mar 07 martin 16   of the License, or (at your option) any later version.
3166 06 Mar 07 enell 17   
3160 05 Mar 07 martin 18   BASE is distributed in the hope that it will be useful,
3160 05 Mar 07 martin 19   but WITHOUT ANY WARRANTY; without even the implied warranty of
3160 05 Mar 07 martin 20   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3160 05 Mar 07 martin 21   GNU General Public License for more details.
3166 06 Mar 07 enell 22   
3160 05 Mar 07 martin 23   You should have received a copy of the GNU General Public License
4509 11 Sep 08 jari 24   along with BASE. If not, see <http://www.gnu.org/licenses/>.
3160 05 Mar 07 martin 25 -->
3160 05 Mar 07 martin 26
3161 06 Mar 07 martin 27 <chapter id="plugin_developer">
5782 04 Oct 11 nicklas 28   <?dbhtml dir="plugins" filename="index.html" ?>
3366 23 May 07 nicklas 29   <title>Plug-in developer</title>
3178 12 Mar 07 enell 30   <sect1 id="plugin_developer.organize">
5782 04 Oct 11 nicklas 31     <?dbhtml filename="organize.html" ?>
3366 23 May 07 nicklas 32     <title>How to organize your plug-in project</title>
3178 12 Mar 07 enell 33     
3178 12 Mar 07 enell 34     <sect2 id="plugin_developer.organize.ant">
3178 12 Mar 07 enell 35       <title>Using Ant</title>
3178 12 Mar 07 enell 36       <para>
3366 23 May 07 nicklas 37         Here is a simple example of how you might organize your project using ant 
3366 23 May 07 nicklas 38         (<ulink url="http://ant.apache.org">http://ant.apache.org</ulink>) as the build 
3366 23 May 07 nicklas 39         tool. This is just a recommendation that we have found to be working
3178 12 Mar 07 enell 40         well. You may choose to do it another way.
3178 12 Mar 07 enell 41       </para>
3178 12 Mar 07 enell 42
3178 12 Mar 07 enell 43       <sect3 id="plugin_developer.organize.ant.directories">
5816 20 Oct 11 nicklas 44         <title>Directory and file layout</title>
3178 12 Mar 07 enell 45         <para>
3366 23 May 07 nicklas 46         
3366 23 May 07 nicklas 47           Create a directory on your computer where you want
3366 23 May 07 nicklas 48           to store your plug-in project. This directory is the 
3366 23 May 07 nicklas 49           <filename class="directory"><replaceable>pluginname</replaceable>/</filename>
3366 23 May 07 nicklas 50           directory in the listing below. You should also create some subdirectories:
5633 18 May 11 nicklas 51         </para>
5633 18 May 11 nicklas 52         
5633 18 May 11 nicklas 53         <literallayout>
3178 12 Mar 07 enell 54 <filename class="directory"><replaceable>pluginname</replaceable>/</filename>
5816 20 Oct 11 nicklas 55 <filename class="directory">&nbsp;-&nbsp;/bin/</filename>
5816 20 Oct 11 nicklas 56 <filename class="directory">&nbsp;-&nbsp;/lib/</filename>
5816 20 Oct 11 nicklas 57 <filename class="directory">&nbsp;-&nbsp;/src/<replaceable>org/company</replaceable>/</filename>
5816 20 Oct 11 nicklas 58 <filename class="directory">&nbsp;-&nbsp;/META-INF/</filename>
5816 20 Oct 11 nicklas 59 <filename>&nbsp;&nbsp;&nbsp;-&nbsp;/META-INF/MANIFEST.MF</filename>
5816 20 Oct 11 nicklas 60 <filename>&nbsp;&nbsp;&nbsp;-&nbsp;/META-INF/extensions.xml</filename>
5816 20 Oct 11 nicklas 61 <filename class="directory">&nbsp;&nbsp;&nbsp;-&nbsp;/META-INF/lib/</filename>
5633 18 May 11 nicklas 62         </literallayout>
5633 18 May 11 nicklas 63         <para>
5633 18 May 11 nicklas 64           The <filename class="directory">bin/</filename>
3366 23 May 07 nicklas 65           directory is empty to start with. It will contain the compiled code. 
3366 23 May 07 nicklas 66           In the <filename class="directory">lib/</filename>
5633 18 May 11 nicklas 67           directory you should put <filename>base-core-3.x.x.jar</filename>
5633 18 May 11 nicklas 68           and other library files that is needed when compiling the source code,
5633 18 May 11 nicklas 69           but doesn't have to be distributed with your plug-in (since they are already
5633 18 May 11 nicklas 70           included in the BASE distribution). In the <filename class="directory">META-INF/lib/</filename>
5633 18 May 11 nicklas 71           directory you should put other library files that are needed both when compiling
5633 18 May 11 nicklas 72           and when distributing your plug-in.
5633 18 May 11 nicklas 73         </para>
5633 18 May 11 nicklas 74         <para>
5633 18 May 11 nicklas 75           The <filename class="directory">src/</filename>
3366 23 May 07 nicklas 76           directory contains your source code. In this directory you should create
3366 23 May 07 nicklas 77           subdirectories corresponding to the package name of your plug-in
3366 23 May 07 nicklas 78           class(es). See <ulink url="http://en.wikipedia.org/wiki/Java_package"
3366 23 May 07 nicklas 79           >http://en.wikipedia.org/wiki/Java_package</ulink> for information
3958 13 Nov 07 nicklas 80           about conventions for naming packages. The 
5633 18 May 11 nicklas 81           <filename class="directory">META-INF/</filename> directory contains metadata
5633 18 May 11 nicklas 82           about the plug-in and are needed for easy installation. Typically you'll
5633 18 May 11 nicklas 83           always need <filename>MANIFEST.MF</filename> and <filename>extensions.xml</filename>
5633 18 May 11 nicklas 84           but, depending on what you are developing, other files are also needed. 
3178 12 Mar 07 enell 85         </para>
3178 12 Mar 07 enell 86       </sect3>
3178 12 Mar 07 enell 87     
3178 12 Mar 07 enell 88       <sect3 id="plugin_developer.organize.ant.buildfile">
3178 12 Mar 07 enell 89         <title>The build file</title>
3178 12 Mar 07 enell 90         <para>
3178 12 Mar 07 enell 91           In the root of your directory, create the build file:
3607 27 Jul 07 nicklas 92           <filename>build.xml</filename>.
3607 27 Jul 07 nicklas 93           Here is an example that will compile your plug-in and put it in a JAR file.
3178 12 Mar 07 enell 94         </para>
3178 12 Mar 07 enell 95         <example id="plugin_developer.organize.build.file">
3178 12 Mar 07 enell 96           <title>A simple build file</title>
5633 18 May 11 nicklas 97           <programlisting language="xml">
5633 18 May 11 nicklas 98 <![CDATA[
5633 18 May 11 nicklas 99 <?xml version="1.0" encoding="UTF-8"?>
5633 18 May 11 nicklas 100 <project 
3178 12 Mar 07 enell 101    name="MyPlugin" 
3178 12 Mar 07 enell 102    default="build.plugin" 
3178 12 Mar 07 enell 103    basedir="."
5633 18 May 11 nicklas 104    >
3178 12 Mar 07 enell 105
5633 18 May 11 nicklas 106    <!-- variables used -->
5633 18 May 11 nicklas 107    <property name="plugin.name" value="MyPlugin" />
5633 18 May 11 nicklas 108    <property name="src" value="src" />
5633 18 May 11 nicklas 109    <property name="bin" value="bin" />
3178 12 Mar 07 enell 110
5633 18 May 11 nicklas 111    <!-- set up classpath for compiling -->
5633 18 May 11 nicklas 112    <path id="classpath">
5633 18 May 11 nicklas 113       <fileset dir="lib">
5633 18 May 11 nicklas 114          <include name="**/*.jar"/>
5633 18 May 11 nicklas 115       </fileset>
5633 18 May 11 nicklas 116       <fileset dir="META-INF/lib">
5633 18 May 11 nicklas 117          <include name="**/*.jar"/>
5633 18 May 11 nicklas 118       </fileset>
5633 18 May 11 nicklas 119    </path>
3178 12 Mar 07 enell 120
5633 18 May 11 nicklas 121    <!-- main target -->
5633 18 May 11 nicklas 122    <target 
3178 12 Mar 07 enell 123       name="build.plugin"  
3366 23 May 07 nicklas 124       description="Compiles the plug-in and put in jar"
5633 18 May 11 nicklas 125       >
5633 18 May 11 nicklas 126       <javac 
5633 18 May 11 nicklas 127          encoding="UTF-8"
3178 12 Mar 07 enell 128          srcdir="${src}"
3178 12 Mar 07 enell 129          destdir="${bin}"
5633 18 May 11 nicklas 130          classpathref="classpath">
5633 18 May 11 nicklas 131       </javac>
5633 18 May 11 nicklas 132       <jar 
3178 12 Mar 07 enell 133          jarfile="${plugin.name}.jar" 
3958 13 Nov 07 nicklas 134          manifest="META-INF/MANIFEST.MF"
5633 18 May 11 nicklas 135          >
5633 18 May 11 nicklas 136          
5633 18 May 11 nicklas 137          <!-- compiled source code -->
5633 18 May 11 nicklas 138          <fileset dir="${bin}" />
5633 18 May 11 nicklas 139          
5633 18 May 11 nicklas 140          <!-- metadata and extra JAR files -->
5633 18 May 11 nicklas 141          <fileset dir="." includes="META-INF/**" />
5633 18 May 11 nicklas 142       </jar>
5633 18 May 11 nicklas 143     </target>
5633 18 May 11 nicklas 144 </project>
5633 18 May 11 nicklas 145 ]]>
5633 18 May 11 nicklas 146 </programlisting>
3178 12 Mar 07 enell 147         </example>
3178 12 Mar 07 enell 148         <para>
5816 20 Oct 11 nicklas 149           If your plug-in depends on JAR files not included with the standard
5816 20 Oct 11 nicklas 150           BASE installation, you must create the <filename>META-INF/MANIFEST.MF</filename>
5816 20 Oct 11 nicklas 151           file. List the other JAR files as in the following example.
3958 13 Nov 07 nicklas 152           If your plug-in does not depend on other JAR files, you may remove the 
3366 23 May 07 nicklas 153           <sgmltag class="attribute">manifest</sgmltag> 
3366 23 May 07 nicklas 154           attribute of the <sgmltag class="starttag">jar</sgmltag> tag.
3371 24 May 07 martin 155 <programlisting>Manifest-Version: 1.0
5633 18 May 11 nicklas 156 Class-Path: lib/OtherJar.jar lib/ASecondJar.jar</programlisting>
5013 25 Jun 09 nicklas 157         See also <xref linkend="plugin_developer.classload" /> for more information
5013 25 Jun 09 nicklas 158         regarding class loading when a plug-in depends on a external JAR files.
3178 12 Mar 07 enell 159         </para>
5633 18 May 11 nicklas 160         
3763 21 Sep 07 martin 161         <para>
5633 18 May 11 nicklas 162           To make installation of your plug-in easier it is a good idea to include
5633 18 May 11 nicklas 163           the <filename>META-INF/extensions.xml</filename>. This file should
5633 18 May 11 nicklas 164           include information about your plug-in, such as the name, author, version,
5633 18 May 11 nicklas 165           and the main Java class for the plug-in. See
3763 21 Sep 07 martin 166           <xref linkend="plugin_developer.organize.autoinstallcompatible" />
3866 19 Oct 07 nicklas 167           for get more information about this feature.
3763 21 Sep 07 martin 168         </para>
3178 12 Mar 07 enell 169       </sect3>
3178 12 Mar 07 enell 170         
3178 12 Mar 07 enell 171       <sect3 id="plugin_developer.organize.ant.build">
3366 23 May 07 nicklas 172         <title>Building the plug-in</title>
3178 12 Mar 07 enell 173         <para>
3366 23 May 07 nicklas 174           Compile the plug-in simply by typing
3178 12 Mar 07 enell 175           <command>ant</command>
3178 12 Mar 07 enell 176           in the console window. If all went well the
3178 12 Mar 07 enell 177           <filename>MyPlugin.jar</filename>
3178 12 Mar 07 enell 178           will be created in the same directory.
3178 12 Mar 07 enell 179         </para>
3178 12 Mar 07 enell 180         <para>
5633 18 May 11 nicklas 181           To install the plug-in copy the JAR file to the server's plug-in directory. 
5633 18 May 11 nicklas 182           For more information about the actual installation read
3866 19 Oct 07 nicklas 183           <xref linkend="plugins.installation" />.
3178 12 Mar 07 enell 184         </para>
3178 12 Mar 07 enell 185       </sect3>
3178 12 Mar 07 enell 186     </sect2>
3178 12 Mar 07 enell 187     
3755 19 Sep 07 martin 188     <sect2 id="plugin_developer.organize.autoinstallcompatible">
3866 19 Oct 07 nicklas 189       <title>Make the plug-in compatible with the auto-installation wizard</title>
3755 19 Sep 07 martin 190       <para>
3866 19 Oct 07 nicklas 191         BASE has support for automatically detecting new plug-ins with
3866 19 Oct 07 nicklas 192         the auto-installation wizard. The wizard makes it very easy for a
3866 19 Oct 07 nicklas 193         server administrator to install new plug-ins. See 
5737 14 Sep 11 nicklas 194         <xref linkend="plugins.installation.wizard" />.
3755 19 Sep 07 martin 195       </para>
3866 19 Oct 07 nicklas 196       
3866 19 Oct 07 nicklas 197       <para>
3866 19 Oct 07 nicklas 198         The auto-install feature requires that a plug-in provides some information
3866 19 Oct 07 nicklas 199         about itself. The wizard looks in all JAR file for the file
5633 18 May 11 nicklas 200         <filename>META-INF/extensions.xml</filename>. This file contains
3866 19 Oct 07 nicklas 201         some information about the plug-in(s). Here is an example:
3866 19 Oct 07 nicklas 202       </para>
3866 19 Oct 07 nicklas 203   
3838 16 Oct 07 nicklas 204       <programlisting language="xml">
5633 18 May 11 nicklas 205 <![CDATA[
5633 18 May 11 nicklas 206 <?xml version="1.0" encoding="UTF-8" ?>
5633 18 May 11 nicklas 207 <extensions xmlns="http://base.thep.lu.se/extensions.xsd">
5633 18 May 11 nicklas 208   <!-- information about the complete package (which may contain many plug-in definitions) -->
5633 18 May 11 nicklas 209   <about>
5633 18 May 11 nicklas 210     <name>My plug-in package</name>
5633 18 May 11 nicklas 211     <description>
5633 18 May 11 nicklas 212       This package contains some very useful plug-ins...
5633 18 May 11 nicklas 213     </description>
5633 18 May 11 nicklas 214     <version>1.3</version>
5633 18 May 11 nicklas 215     <min-base-version>3.0</min-base-version>
5633 18 May 11 nicklas 216     <copyright>You</copyright>
5633 18 May 11 nicklas 217     <url>http://www.company.org/with/more/info/about/plugins</url>
5633 18 May 11 nicklas 218     <email>some.email.address@company.org</email>
5633 18 May 11 nicklas 219   </about>
5633 18 May 11 nicklas 220   
5633 18 May 11 nicklas 221   <!-- Defines a single plug-in (can be repeated multiple times) -->
5633 18 May 11 nicklas 222   <plugin-definition id="PluginX">
5633 18 May 11 nicklas 223     <about>
5633 18 May 11 nicklas 224       <name>Plug-in X</name>
5633 18 May 11 nicklas 225       <description>
5633 18 May 11 nicklas 226         Calculates the X transform of....
5633 18 May 11 nicklas 227       </description>
5633 18 May 11 nicklas 228     </about>
5633 18 May 11 nicklas 229     <plugin-class>org.company.PluginClassX</plugin-class>
5816 20 Oct 11 nicklas 230     <settings>
5816 20 Oct 11 nicklas 231       <property name="everyone-use">1</property>
5816 20 Oct 11 nicklas 232     </settings>
5633 18 May 11 nicklas 233   </plugin-definition>
5633 18 May 11 nicklas 234 </extensions>
5633 18 May 11 nicklas 235 ]]>
3838 16 Oct 07 nicklas 236 </programlisting>
3759 20 Sep 07 martin 237       <para>
5633 18 May 11 nicklas 238         The first two lines should be the same in all <filename>extensions.xml</filename> files.
3866 19 Oct 07 nicklas 239         The rest of the tags are described in following list.
3759 20 Sep 07 martin 240         <variablelist>
3759 20 Sep 07 martin 241           <varlistentry>
5633 18 May 11 nicklas 242             <term><sgmltag class="starttag">about</sgmltag></term>
3759 20 Sep 07 martin 243             <listitem>
3759 20 Sep 07 martin 244               <para>
5633 18 May 11 nicklas 245                 The first <sgmltag class="starttag">about</sgmltag> tag is information
5633 18 May 11 nicklas 246                 about the package as a whole. We recommend putting in as much information
5633 18 May 11 nicklas 247                 as possible here. Supported sub-tags are:
5633 18 May 11 nicklas 248                 
5633 18 May 11 nicklas 249                 <sgmltag class="starttag">name</sgmltag>, <sgmltag class="starttag">description</sgmltag>,
5633 18 May 11 nicklas 250                 <sgmltag class="starttag">version</sgmltag>, <sgmltag class="starttag">min-base-version</sgmltag>,
5633 18 May 11 nicklas 251                 <sgmltag class="starttag">max-base-version</sgmltag>, <sgmltag class="starttag">contact</sgmltag>,
5633 18 May 11 nicklas 252                 <sgmltag class="starttag">email</sgmltag>, <sgmltag class="starttag">url</sgmltag> and
5633 18 May 11 nicklas 253                 <sgmltag class="starttag">copyright</sgmltag>
3759 20 Sep 07 martin 254               </para>
5633 18 May 11 nicklas 255               <para>
5633 18 May 11 nicklas 256                 Each plug-in that is defined in this file may have it's <sgmltag class="starttag">about</sgmltag>
5633 18 May 11 nicklas 257                 tag which override the global information. Typically, you'll only overide the name and
5816 20 Oct 11 nicklas 258                 description tags and maybe also the min/max BASE version tags.
5633 18 May 11 nicklas 259               </para>
3759 20 Sep 07 martin 260             </listitem>
3759 20 Sep 07 martin 261           </varlistentry>
3759 20 Sep 07 martin 262           <varlistentry>
5633 18 May 11 nicklas 263             <term><sgmltag class="starttag">plugin-definition</sgmltag></term>
3759 20 Sep 07 martin 264             <listitem>
3759 20 Sep 07 martin 265               <para>
5633 18 May 11 nicklas 266                 This is the main element for defining a plug-in. It can override the global 
5633 18 May 11 nicklas 267                 <sgmltag class="starttag">about</sgmltag> information. We recommend that at
5633 18 May 11 nicklas 268                 least a <sgmltag class="starttag">name</sgmltag> and <sgmltag class="starttag">description</sgmltag>
5633 18 May 11 nicklas 269                 is provided.                
3759 20 Sep 07 martin 270               </para>
3759 20 Sep 07 martin 271             </listitem>
3759 20 Sep 07 martin 272           </varlistentry>
3759 20 Sep 07 martin 273           <varlistentry>
3759 20 Sep 07 martin 274             <term>
5633 18 May 11 nicklas 275               <sgmltag class="starttag">plugin-class</sgmltag>
3759 20 Sep 07 martin 276             </term>
3759 20 Sep 07 martin 277             <listitem>
3759 20 Sep 07 martin 278               <para>
5633 18 May 11 nicklas 279                 The value is the fill class name of the plug-in's main
5633 18 May 11 nicklas 280                 class.
3759 20 Sep 07 martin 281               </para>
3759 20 Sep 07 martin 282             </listitem>
3759 20 Sep 07 martin 283           </varlistentry>
3759 20 Sep 07 martin 284           <varlistentry>
3759 20 Sep 07 martin 285             <term>
5633 18 May 11 nicklas 286               <sgmltag class="starttag">min-base-version</sgmltag>
5633 18 May 11 nicklas 287               <sgmltag class="starttag">max-base-version</sgmltag>
3759 20 Sep 07 martin 288             </term>
3759 20 Sep 07 martin 289             <listitem>
3759 20 Sep 07 martin 290               <para>
5633 18 May 11 nicklas 291                 Optional sub-tags in the <sgmltag class="starttag">about</sgmltag> section.
5633 18 May 11 nicklas 292                 Values are two- or three-digits separated by a dot. For example,
5633 18 May 11 nicklas 293                 3.0.0 and 3.1. If values are given the plug-in will only be installed
5633 18 May 11 nicklas 294                 if the server's BASE version is within the bounds.
3759 20 Sep 07 martin 295               </para>
3759 20 Sep 07 martin 296             </listitem>
3759 20 Sep 07 martin 297           </varlistentry>
5816 20 Oct 11 nicklas 298           <varlistentry>
5816 20 Oct 11 nicklas 299             <term>
5816 20 Oct 11 nicklas 300               <sgmltag class="starttag">settings</sgmltag>
5816 20 Oct 11 nicklas 301             </term>
5816 20 Oct 11 nicklas 302             <listitem>
5816 20 Oct 11 nicklas 303               <para>
5816 20 Oct 11 nicklas 304                 Optional sub-tag that can contain one or more <sgmltag class="starttag">property</sgmltag>
5816 20 Oct 11 nicklas 305                 tags. The settings can be used to configure some properties of the plug-in
5816 20 Oct 11 nicklas 306                 definition. So far, the following properties are recognized:
5816 20 Oct 11 nicklas 307               </para>
5816 20 Oct 11 nicklas 308               
5816 20 Oct 11 nicklas 309               <itemizedlist>
5816 20 Oct 11 nicklas 310                 <listitem>
5816 20 Oct 11 nicklas 311                   <para>
5816 20 Oct 11 nicklas 312                     <property>everyone-use</property>: If set, the plug-in is shared to the
5816 20 Oct 11 nicklas 313                     <emphasis>EVERYONE</emphasis> group with use permissions.
5816 20 Oct 11 nicklas 314                    </para>
5816 20 Oct 11 nicklas 315                 </listitem>
5816 20 Oct 11 nicklas 316                 <listitem>
5816 20 Oct 11 nicklas 317                   <para>
5816 20 Oct 11 nicklas 318                     <property>immediate-execution</property>: If set, the plug-in is given
5816 20 Oct 11 nicklas 319                     permissions to use the immediate execution feature. This is typically
5816 20 Oct 11 nicklas 320                     used for export plug-in that need to support immediate download.
5816 20 Oct 11 nicklas 321                    </para>
5816 20 Oct 11 nicklas 322                 </listitem>
5816 20 Oct 11 nicklas 323                 <listitem>
5816 20 Oct 11 nicklas 324                   <para>
5816 20 Oct 11 nicklas 325                     <property>max-memory</property>: The maximum memory (in bytes) to
5816 20 Oct 11 nicklas 326                     give to the plug-in when it is executed on a job agent. This setting
5816 20 Oct 11 nicklas 327                     is ignored when plug-ins are executed within the web client.
5816 20 Oct 11 nicklas 328                    </para>
5816 20 Oct 11 nicklas 329                 </listitem>
5816 20 Oct 11 nicklas 330                 <listitem>
5816 20 Oct 11 nicklas 331                   <para>
5816 20 Oct 11 nicklas 332                     <property>deprecated</property>: The plug-in has been deprecated.
5816 20 Oct 11 nicklas 333                     If it already exists on the BASE installation it will be disabled.
5816 20 Oct 11 nicklas 334                     If it doesn't exists, it will not be installed.
5816 20 Oct 11 nicklas 335                    </para>
5816 20 Oct 11 nicklas 336                 </listitem>
5816 20 Oct 11 nicklas 337               </itemizedlist>
5816 20 Oct 11 nicklas 338               
5816 20 Oct 11 nicklas 339             </listitem>
5816 20 Oct 11 nicklas 340           </varlistentry>
3759 20 Sep 07 martin 341         </variablelist>
3759 20 Sep 07 martin 342       </para>
5633 18 May 11 nicklas 343       
5633 18 May 11 nicklas 344       <sect3 id="plugin_developer.organize.autoinstallcompatible.configurations">
5633 18 May 11 nicklas 345         <title>Installing plug-in configurations</title>
5633 18 May 11 nicklas 346       
5633 18 May 11 nicklas 347         <para>
5633 18 May 11 nicklas 348           The installation wizard has support for installing plug-in configurations.
5633 18 May 11 nicklas 349           If some of your plug-ins has support for different configurations that you want
5633 18 May 11 nicklas 350           to ship as part of the package, use the "Plug-in configuration exporter" in BASE
5633 18 May 11 nicklas 351           and include the generated file in <filename>META-INF/plugin-configurations.xml</filename>
5633 18 May 11 nicklas 352           inside your JAR file.
5633 18 May 11 nicklas 353         </para>
5633 18 May 11 nicklas 354       
5816 20 Oct 11 nicklas 355         <note>
5816 20 Oct 11 nicklas 356           <para>
6576 22 Oct 14 nicklas 357           As of BASE 3.3.2 the installation wizard can also install configurations
6576 22 Oct 14 nicklas 358           for plug-ins defined by the BASE core or other extensions. Simply include
6576 22 Oct 14 nicklas 359           the configuration settings for the plug-in as you would do with a configuration
6576 22 Oct 14 nicklas 360           for a plug-in defined by your own extension.
5816 20 Oct 11 nicklas 361           </para>
5816 20 Oct 11 nicklas 362         </note>
5816 20 Oct 11 nicklas 363       
5633 18 May 11 nicklas 364       </sect3>
3755 19 Sep 07 martin 365     </sect2>
3755 19 Sep 07 martin 366     
3178 12 Mar 07 enell 367   </sect1>
3178 12 Mar 07 enell 368
3178 12 Mar 07 enell 369   <sect1 id="plugin_developer.api">
5782 04 Oct 11 nicklas 370     <?dbhtml filename="api.html" ?>
3366 23 May 07 nicklas 371     <title>The Plug-in API</title>
3166 06 Mar 07 enell 372     <para>
3167 06 Mar 07 enell 373     </para>
3178 12 Mar 07 enell 374     
3178 12 Mar 07 enell 375     <sect2 id="plugin_developer.api.interfaces">
3178 12 Mar 07 enell 376     
3366 23 May 07 nicklas 377       <title>The main plug-in interfaces</title>
3178 12 Mar 07 enell 378       <para>
5633 18 May 11 nicklas 379         The BASE API defines two interfaces and one
3366 23 May 07 nicklas 380         abstract class that are vital for implementing plug-ins:
3178 12 Mar 07 enell 381         <itemizedlist spacing="compact">
3166 06 Mar 07 enell 382           <listitem>
3178 12 Mar 07 enell 383             <simpara>
3944 09 Nov 07 martin 384               <interfacename docapi="net.sf.basedb.core.plugin">net.sf.basedb.core.plugin.Plugin</interfacename>
3178 12 Mar 07 enell 385             </simpara>
3178 12 Mar 07 enell 386           </listitem>
3178 12 Mar 07 enell 387           <listitem>
3178 12 Mar 07 enell 388             <simpara>
3944 09 Nov 07 martin 389               <interfacename docapi="net.sf.basedb.core.plugin">net.sf.basedb.core.plugin.InteractivePlugin</interfacename>
3178 12 Mar 07 enell 390             </simpara>
3178 12 Mar 07 enell 391           </listitem>
3366 23 May 07 nicklas 392           <listitem>
3366 23 May 07 nicklas 393             <simpara>
3944 09 Nov 07 martin 394               <classname docapi="net.sf.basedb.core.plugin">net.sf.basedb.core.plugin.AbstractPlugin</classname>
3366 23 May 07 nicklas 395             </simpara>
3366 23 May 07 nicklas 396           </listitem>
3178 12 Mar 07 enell 397         </itemizedlist>
3366 23 May 07 nicklas 398         
3565 17 Jul 07 nicklas 399         A plug-in must always implement the 
3944 09 Nov 07 martin 400         <interfacename docapi="net.sf.basedb.core.plugin">Plugin</interfacename> interface. 
3944 09 Nov 07 martin 401         The <interfacename docapi="net.sf.basedb.core.plugin">InteractivePlugin</interfacename>
3366 23 May 07 nicklas 402         interface is optional, and is only needed if you want user interaction.
3944 09 Nov 07 martin 403         The <classname docapi="net.sf.basedb.core.plugin">AbstractPlugin</classname> is a useful base class
3366 23 May 07 nicklas 404         that your plug-in can use as a superclass. It provides default implementations
3366 23 May 07 nicklas 405         for some of the interface methods and also has utility methods for
3366 23 May 07 nicklas 406         validating and storing job and configuration parameter values. Another
3366 23 May 07 nicklas 407         reason to use this class as a superclass is that it will shield your 
3366 23 May 07 nicklas 408         plug-in from future changes to the Plug-in API. For example, if
3944 09 Nov 07 martin 409         we decide that a new method is needed in the <interfacename docapi="net.sf.basedb.core.plugin">Plugin</interfacename> 
3366 23 May 07 nicklas 410         interface we will also try to add a default implementation in 
3944 09 Nov 07 martin 411         the <classname docapi="net.sf.basedb.core.plugin">AbstractPlugin</classname> class.
3178 12 Mar 07 enell 412       </para>
3178 12 Mar 07 enell 413   
3366 23 May 07 nicklas 414       <important>
3366 23 May 07 nicklas 415         <para>
3366 23 May 07 nicklas 416         A plug-in must also have public no-argument contructor. Otherwise, BASE will not
3565 17 Jul 07 nicklas 417         be able to create new instances of the plug-in class.
3366 23 May 07 nicklas 418         </para>
3366 23 May 07 nicklas 419       </important>
3366 23 May 07 nicklas 420       
3178 12 Mar 07 enell 421       <sect3 id="plugin_developer.api.interfaces.plugin">
3565 17 Jul 07 nicklas 422         <title>The net.sf.basedb.core.plugin.Plugin interface</title>
3565 17 Jul 07 nicklas 423         <para>
3565 17 Jul 07 nicklas 424           This interface defines the following methods and must be implemented 
3565 17 Jul 07 nicklas 425           by all plug-ins.
3565 17 Jul 07 nicklas 426         </para>
3178 12 Mar 07 enell 427         <variablelist>
3178 12 Mar 07 enell 428           <varlistentry>
3178 12 Mar 07 enell 429             <term>
3178 12 Mar 07 enell 430               <methodsynopsis language="java">
3178 12 Mar 07 enell 431                 <modifier>public</modifier>
3178 12 Mar 07 enell 432                 <type>Plugin.MainType</type>
3178 12 Mar 07 enell 433                 <methodname>getMainType</methodname>
3178 12 Mar 07 enell 434                 <void />
3178 12 Mar 07 enell 435               </methodsynopsis>
3178 12 Mar 07 enell 436             </term>
3178 12 Mar 07 enell 437             <listitem>
3178 12 Mar 07 enell 438               <para>
3366 23 May 07 nicklas 439                 Return information about the main type of plug-in. The
3944 09 Nov 07 martin 440                 <classname docapi="net.sf.basedb.core.plugin">Plugin.MainType</classname>
3366 23 May 07 nicklas 441                 is an enumeration with five possible values:
3178 12 Mar 07 enell 442                 <itemizedlist>
3178 12 Mar 07 enell 443                   <listitem>
3178 12 Mar 07 enell 444                     <para>
3366 23 May 07 nicklas 445                       <constant>ANALYZE</constant>: 
3366 23 May 07 nicklas 446                       An analysis plug-in
3178 12 Mar 07 enell 447                     </para>
3178 12 Mar 07 enell 448                   </listitem>
3178 12 Mar 07 enell 449                   <listitem>
3178 12 Mar 07 enell 450                     <para>
3366 23 May 07 nicklas 451                       <constant>EXPORT</constant>:
3479 12 Jun 07 peter 452                       A plug-in that exports data
3178 12 Mar 07 enell 453                     </para>
3178 12 Mar 07 enell 454                   </listitem>
3178 12 Mar 07 enell 455                   <listitem>
3178 12 Mar 07 enell 456                     <para>
3366 23 May 07 nicklas 457                       <constant>IMPORT</constant>:
3366 23 May 07 nicklas 458                       A plug-in that imports data
3178 12 Mar 07 enell 459                     </para>
3178 12 Mar 07 enell 460                   </listitem>
3178 12 Mar 07 enell 461                   <listitem>
3178 12 Mar 07 enell 462                     <para>
3366 23 May 07 nicklas 463                       <constant>INTENSITY</constant>:
3366 23 May 07 nicklas 464                       A plug-in that calculates the original spot intensities
3178 12 Mar 07 enell 465                       from raw data
3178 12 Mar 07 enell 466                     </para>
3178 12 Mar 07 enell 467                   </listitem>
3178 12 Mar 07 enell 468                   <listitem>
3178 12 Mar 07 enell 469                     <para>
3366 23 May 07 nicklas 470                       <constant>OTHER</constant>:
3366 23 May 07 nicklas 471                       Any other type of plug-in
3178 12 Mar 07 enell 472                     </para>
3178 12 Mar 07 enell 473                   </listitem>
3178 12 Mar 07 enell 474                 </itemizedlist>
3178 12 Mar 07 enell 475                 The returned value is stored in the database but is otherwise not used
3178 12 Mar 07 enell 476                 by the core. Client applications (such as the web client) will probably
3366 23 May 07 nicklas 477                 use this information to group the plug-ins, i.e., a button labeled 
3394 28 May 07 martin 478                 &gbExport;
3366 23 May 07 nicklas 479                 will let you select among the export plug-ins.
3178 12 Mar 07 enell 480               </para>
3178 12 Mar 07 enell 481               <example id="net.sf.basedb.core.plugin.Plugin.getMainType">
3178 12 Mar 07 enell 482                 <title>A typical implementation just return one of the values</title>
3838 16 Oct 07 nicklas 483 <programlisting language="java">
3838 16 Oct 07 nicklas 484 public Plugin.MainType getMainType()
3166 06 Mar 07 enell 485 {
3166 06 Mar 07 enell 486    return Plugin.MainType.OTHER;
3371 24 May 07 martin 487 }</programlisting>
3178 12 Mar 07 enell 488               </example>
3178 12 Mar 07 enell 489             </listitem>
3178 12 Mar 07 enell 490           </varlistentry>
3178 12 Mar 07 enell 491           <varlistentry>
3178 12 Mar 07 enell 492             <term>
3178 12 Mar 07 enell 493               <methodsynopsis language="java">
3178 12 Mar 07 enell 494                 <modifier>public</modifier>
3178 12 Mar 07 enell 495                 <type>boolean</type>
3178 12 Mar 07 enell 496                 <methodname>supportsConfigurations</methodname>
3178 12 Mar 07 enell 497                 <void />
3178 12 Mar 07 enell 498               </methodsynopsis>
3178 12 Mar 07 enell 499             </term>
3178 12 Mar 07 enell 500             <listitem>
3178 12 Mar 07 enell 501               <para>
3479 12 Jun 07 peter 502                 If this method returns true, the plug-in can have different
3178 12 Mar 07 enell 503                 configurations, (i.e.
3944 09 Nov 07 martin 504                 <classname docapi="net.sf.basedb.core">PluginConfiguration</classname>).
3366 23 May 07 nicklas 505                 Note that this method may return true even if the
3944 09 Nov 07 martin 506                 <interfacename docapi="net.sf.basedb.core.plugin">InteractivePlugin</interfacename>
3487 13 Jun 07 peter 507                 interface is not implemented. The
3944 09 Nov 07 martin 508                 <classname docapi="net.sf.basedb.core.plugin">AbstractPlugin</classname>
3479 12 Jun 07 peter 509                 returns true for this method, which is the old way before the
3178 12 Mar 07 enell 510                 introduction of this method.
3178 12 Mar 07 enell 511               </para>
3178 12 Mar 07 enell 512             </listitem>
3178 12 Mar 07 enell 513           </varlistentry>
3178 12 Mar 07 enell 514           <varlistentry>
3178 12 Mar 07 enell 515             <term>
3178 12 Mar 07 enell 516               <methodsynopsis language="java">
3178 12 Mar 07 enell 517                 <modifier>public</modifier>
3178 12 Mar 07 enell 518                 <type>boolean</type>
3178 12 Mar 07 enell 519                 <methodname>requiresConfiguration</methodname>
3178 12 Mar 07 enell 520                 <void />
3178 12 Mar 07 enell 521               </methodsynopsis>
3178 12 Mar 07 enell 522             </term>
3178 12 Mar 07 enell 523             <listitem>
3178 12 Mar 07 enell 524               <para>
3479 12 Jun 07 peter 525                 If this method returns true, the plug-in must have a configuration
3366 23 May 07 nicklas 526                 to be able to run. For example, some of the core import plug-ins 
3479 12 Jun 07 peter 527                 must have information about the file format, to be able to import
3366 23 May 07 nicklas 528                 any data. 
3366 23 May 07 nicklas 529                 The
3944 09 Nov 07 martin 530                 <classname docapi="net.sf.basedb.core.plugin">AbstractPlugin</classname>
3479 12 Jun 07 peter 531                 returns false for this method, which is the old way before the
3178 12 Mar 07 enell 532                 introduction of this method.
3178 12 Mar 07 enell 533               </para>
3178 12 Mar 07 enell 534             </listitem>
3178 12 Mar 07 enell 535           </varlistentry>
3178 12 Mar 07 enell 536           <varlistentry>
3178 12 Mar 07 enell 537             <term>
3178 12 Mar 07 enell 538               <methodsynopsis language="java">
3178 12 Mar 07 enell 539                 <modifier>public</modifier>
3565 17 Jul 07 nicklas 540                 <type>Collection&lt;Permissions&gt;</type>
3565 17 Jul 07 nicklas 541                 <methodname>getPermissions</methodname>
3178 12 Mar 07 enell 542                 <void />
3565 17 Jul 07 nicklas 543               </methodsynopsis>
3565 17 Jul 07 nicklas 544             </term>
3565 17 Jul 07 nicklas 545             <listitem>
3565 17 Jul 07 nicklas 546               <para>
3565 17 Jul 07 nicklas 547                 Return a collection of permissions that the plug-in needs
3565 17 Jul 07 nicklas 548                 to be able to function as expected. This method may return null
3565 17 Jul 07 nicklas 549                 or an empty collection. In this case the plug-in permission system
3609 27 Jul 07 peter 550                 is not used and the plug-in always gets the same permissions as the
3565 17 Jul 07 nicklas 551                 logged in user. If permissions are specified the plug-in should
3605 26 Jul 07 peter 552                 list all permissions it requires. Permissions that are not listed
3565 17 Jul 07 nicklas 553                 are denied.
3565 17 Jul 07 nicklas 554               </para>
3565 17 Jul 07 nicklas 555               <note>
3565 17 Jul 07 nicklas 556                 <para>
3565 17 Jul 07 nicklas 557                 The final assignment of permissions to a plug-in is always
3565 17 Jul 07 nicklas 558                 at the hands of a server administrator. He/she may decide to
3565 17 Jul 07 nicklas 559                 disable the plug-in permission system or revoke some of the
3565 17 Jul 07 nicklas 560                 requested permissions. The permissions returned by this method is
3565 17 Jul 07 nicklas 561                 only a recommendation that the server administrator may or may not
3565 17 Jul 07 nicklas 562                 accept. See <xref linkend="plugins.permissions" />
3565 17 Jul 07 nicklas 563                 for more information about plug-in permissions.
3565 17 Jul 07 nicklas 564                 </para>
3565 17 Jul 07 nicklas 565               </note>
3565 17 Jul 07 nicklas 566             </listitem>
3565 17 Jul 07 nicklas 567           </varlistentry>
3565 17 Jul 07 nicklas 568           <varlistentry>
3565 17 Jul 07 nicklas 569             <term>
3565 17 Jul 07 nicklas 570               <methodsynopsis language="java">
3565 17 Jul 07 nicklas 571                 <modifier>public</modifier>
3565 17 Jul 07 nicklas 572                 <void />
3178 12 Mar 07 enell 573                 <methodname>init</methodname>
3178 12 Mar 07 enell 574                 <methodparam>
3178 12 Mar 07 enell 575                   <type>SessionControl</type>
3178 12 Mar 07 enell 576                   <parameter>sc</parameter>
3178 12 Mar 07 enell 577                 </methodparam>
3178 12 Mar 07 enell 578                 <methodparam>
3178 12 Mar 07 enell 579                   <type>ParameterValues</type>
3178 12 Mar 07 enell 580                   <parameter>configuration</parameter>
3178 12 Mar 07 enell 581                 </methodparam>
3178 12 Mar 07 enell 582                 <methodparam>
3178 12 Mar 07 enell 583                   <type>ParameterValues</type>
3178 12 Mar 07 enell 584                   <parameter>job</parameter>
3178 12 Mar 07 enell 585                 </methodparam>
3366 23 May 07 nicklas 586                 <exceptionname>BaseException</exceptionname>
3178 12 Mar 07 enell 587               </methodsynopsis>
3178 12 Mar 07 enell 588             </term>
3178 12 Mar 07 enell 589             <listitem>
3178 12 Mar 07 enell 590               <para>
3565 17 Jul 07 nicklas 591                 Prepare the plug-in for execution or configuration. If the plug-in needs
3178 12 Mar 07 enell 592                 to do some initialization this is the place to do it. A typical
3178 12 Mar 07 enell 593                 implementation however only stores the passed parameters in instance
5633 18 May 11 nicklas 594                 variables for later use. Since it is not possible to know what the user is going to
3565 17 Jul 07 nicklas 595                 do at this stage, we recommend lazy initialisation of all other resources.
3178 12 Mar 07 enell 596               </para>
3178 12 Mar 07 enell 597               <para>
3178 12 Mar 07 enell 598                 The parameters passed to this method has vital information that is
3366 23 May 07 nicklas 599                 needed to execute the plug-in. The
3944 09 Nov 07 martin 600                 <classname docapi="net.sf.basedb.core">SessionControl</classname>
3479 12 Jun 07 peter 601                 is a central core object holding information about the logged in
3479 12 Jun 07 peter 602                 user and is used to create
3944 09 Nov 07 martin 603                 <classname docapi="net.sf.basedb.core">DbControl</classname>
3366 23 May 07 nicklas 604                 objects which allows a plug-in to connect to the database to read, add or
3178 12 Mar 07 enell 605                 update information. The two
3944 09 Nov 07 martin 606                 <classname docapi="net.sf.basedb.core.plugin">ParameterValues</classname>
3479 12 Jun 07 peter 607                 objects contain information about the configuration and job 
3366 23 May 07 nicklas 608                 parameters to the plug-in. 
3366 23 May 07 nicklas 609                 The <varname>configuration</varname> object holds all parameters stored
3944 09 Nov 07 martin 610                 together with a <classname docapi="net.sf.basedb.core">PluginConfiguration</classname>
3366 23 May 07 nicklas 611                 object in the database. If the plug-in is started without
3366 23 May 07 nicklas 612                 a configuration this object is null.
3366 23 May 07 nicklas 613                 The <varname>job</varname> object holds all parameters that are
3944 09 Nov 07 martin 614                 stored together with a <classname docapi="net.sf.basedb.core">Job</classname> object in the 
3366 23 May 07 nicklas 615                 database. This object is null if the plug-in is started without a job.
3178 12 Mar 07 enell 616               </para>
3178 12 Mar 07 enell 617               <para>
3366 23 May 07 nicklas 618                 The difference between a configuration parameter and a job parameter is
3178 12 Mar 07 enell 619                 that a configuration is usually something an administrator sets up,
3366 23 May 07 nicklas 620                 while a job is an actual execution of a plug-in. For example, a
3366 23 May 07 nicklas 621                 configuration for an import plug-in holds the regular expressions needed
3178 12 Mar 07 enell 622                 to parse a text file and find the headers, sections and data lines,
3178 12 Mar 07 enell 623                 while the job holds the file to parse.
3178 12 Mar 07 enell 624               </para>
3178 12 Mar 07 enell 625               <para>
3178 12 Mar 07 enell 626                 The
3944 09 Nov 07 martin 627                 <classname docapi="net.sf.basedb.core.plugin">AbstractPlugin</classname>
3366 23 May 07 nicklas 628                 contains an implementation of this method that saves the passed objects
3366 23 May 07 nicklas 629                 in protected instance variables. If you override this method 
3366 23 May 07 nicklas 630                 we recommend that you also call <code>super.init()</code>.
3178 12 Mar 07 enell 631               </para>
3178 12 Mar 07 enell 632               <example id="net.sf.basedb.core.plugin.Plugin.init">
3944 09 Nov 07 martin 633                 <title>The <classname docapi="net.sf.basedb.core.plugin">AbstractPlugin</classname> implementation of Plugin.init()</title>
3838 16 Oct 07 nicklas 634 <programlisting language="java">
3838 16 Oct 07 nicklas 635 protected SessionControl sc = null;
3166 06 Mar 07 enell 636 protected ParameterValues configuration = null;
3166 06 Mar 07 enell 637 protected ParameterValues job = null;
3166 06 Mar 07 enell 638 /**
3366 23 May 07 nicklas 639    Store copies of the session control, plug-in and job configuration. These
3166 06 Mar 07 enell 640    are available to subclasses in the {@link #sc}, {@link #configuration}
3166 06 Mar 07 enell 641    and {@link #job} variables. If a subclass overrides this method it is 
3166 06 Mar 07 enell 642    recommended that it also calls super.init(sc, configuration, job).
3166 06 Mar 07 enell 643 */
3166 06 Mar 07 enell 644 public void init(SessionControl sc, 
3166 06 Mar 07 enell 645    ParameterValues configuration, ParameterValues job)
3166 06 Mar 07 enell 646    throws BaseException
3166 06 Mar 07 enell 647 {
3166 06 Mar 07 enell 648    this.sc = sc;
3166 06 Mar 07 enell 649    this.configuration = configuration;
3166 06 Mar 07 enell 650    this.job = job;
3371 24 May 07 martin 651 }</programlisting>
3178 12 Mar 07 enell 652               </example>
3178 12 Mar 07 enell 653             </listitem>
3178 12 Mar 07 enell 654           </varlistentry>
3178 12 Mar 07 enell 655           <varlistentry>
3178 12 Mar 07 enell 656             <term>
3178 12 Mar 07 enell 657               <methodsynopsis language="java">
3178 12 Mar 07 enell 658                 <modifier>public</modifier>
3178 12 Mar 07 enell 659                 <void />
3178 12 Mar 07 enell 660                 <methodname>run</methodname>
3178 12 Mar 07 enell 661                 <methodparam>
3178 12 Mar 07 enell 662                   <type>Request</type>
3178 12 Mar 07 enell 663                   <parameter>request</parameter>
3178 12 Mar 07 enell 664                 </methodparam>
3178 12 Mar 07 enell 665                 <methodparam>
3178 12 Mar 07 enell 666                   <type>Response</type>
3178 12 Mar 07 enell 667                   <parameter>response</parameter>
3178 12 Mar 07 enell 668                 </methodparam>
3178 12 Mar 07 enell 669                 <methodparam>
3178 12 Mar 07 enell 670                   <type>ProgressReporter</type>
3178 12 Mar 07 enell 671                   <parameter>progress</parameter>
3178 12 Mar 07 enell 672                 </methodparam>
3178 12 Mar 07 enell 673               </methodsynopsis>
3178 12 Mar 07 enell 674             </term>
3178 12 Mar 07 enell 675             <listitem>
3178 12 Mar 07 enell 676               <para>
3565 17 Jul 07 nicklas 677                 Run the plug-in.
3565 17 Jul 07 nicklas 678               </para>
3565 17 Jul 07 nicklas 679               <para>
3565 17 Jul 07 nicklas 680                 The <varname>request</varname>
3366 23 May 07 nicklas 681                 parameter is of historical interest only. It has no useful information 
3366 23 May 07 nicklas 682                 and can be ignored.
3178 12 Mar 07 enell 683               </para>
3178 12 Mar 07 enell 684               <para>
3366 23 May 07 nicklas 685                 The <varname>progress</varname> parameter
5816 20 Oct 11 nicklas 686                 should be used by a plug-in to report its progress back to the core. The
3178 12 Mar 07 enell 687                 core will usually send the progress information to the database, which
3366 23 May 07 nicklas 688                 allows users to see exactly how the plug-in is progressing from the web
5816 20 Oct 11 nicklas 689                 interface. This parameter is allowed to be null, but BASE will always 
5816 20 Oct 11 nicklas 690                 use a progress reporter. The plug-in should try to not over-use the progress
5816 20 Oct 11 nicklas 691                 reporter. The default implementation used by BASE has a time threshold so 
5816 20 Oct 11 nicklas 692                 that calls that occur too often with too little change in the progress 
5816 20 Oct 11 nicklas 693                 are ignored. A good starting point is to
3178 12 Mar 07 enell 694                 divide the work into 100 pieces each representing 1% of the work, i.e.,
3366 23 May 07 nicklas 695                 if the plug-in should export 100 000 items it should report progress
3178 12 Mar 07 enell 696                 after every 1000 items.
3178 12 Mar 07 enell 697               </para>
3178 12 Mar 07 enell 698               <para>
3366 23 May 07 nicklas 699                 The <varname>response</varname>
3366 23 May 07 nicklas 700                 parameter is used to tell the core if the plug-in was successful or
3178 12 Mar 07 enell 701                 failed. Not setting a response is considered a failure by the core. From
5407 13 Sep 10 nicklas 702                 the run method it is only allowed to use on of the
5407 13 Sep 10 nicklas 703                 <methodname>Response.setDone()</methodname>,
5407 13 Sep 10 nicklas 704                 <methodname>Response.setError()</methodname> or 
5407 13 Sep 10 nicklas 705                 <methodname>Response.setContinue()</methodname>
3366 23 May 07 nicklas 706                 methods.
3178 12 Mar 07 enell 707               </para>
3366 23 May 07 nicklas 708               
3565 17 Jul 07 nicklas 709               <important>
3366 23 May 07 nicklas 710                 It is also considered bad practice to let exceptions escape
3366 23 May 07 nicklas 711                 out from this method. Always use <code>try...catch</code>
3565 17 Jul 07 nicklas 712                 to catch exceptions and use <code>Response.setError()</code>
3662 14 Aug 07 martin 713                 to report the error back to the core.
3565 17 Jul 07 nicklas 714               </important>
3366 23 May 07 nicklas 715               
3178 12 Mar 07 enell 716               <example id="net.sf.basedb.core.plugin.Plugin.run">
3178 12 Mar 07 enell 717                 <title>
5816 20 Oct 11 nicklas 718                   Here is a skeleton for the  <methodname>run()</methodname> method
3178 12 Mar 07 enell 719                 </title>
3838 16 Oct 07 nicklas 720 <programlisting language="java">
3838 16 Oct 07 nicklas 721 public void run(Request request, Response response, ProgressReporter progress)
3166 06 Mar 07 enell 722 {
3166 06 Mar 07 enell 723    // Open a connection to the database
3166 06 Mar 07 enell 724    // sc is set by init() method
3166 06 Mar 07 enell 725    DbControl dc = sc.newDbControl();
3166 06 Mar 07 enell 726    try
3166 06 Mar 07 enell 727    {
3366 23 May 07 nicklas 728       // Insert code for plug-in here
3166 06 Mar 07 enell 729
3166 06 Mar 07 enell 730       // Commit the work
3166 06 Mar 07 enell 731       dc.commit();
3366 23 May 07 nicklas 732       response.setDone("Plug-in ended successfully");
3166 06 Mar 07 enell 733    }
3166 06 Mar 07 enell 734    catch (Throwable t)
3166 06 Mar 07 enell 735    {
3166 06 Mar 07 enell 736       // All exceptions must be catched and sent back 
3166 06 Mar 07 enell 737       // using the response object
3166 06 Mar 07 enell 738       response.setError(t.getMessage(), Arrays.asList(t));
3166 06 Mar 07 enell 739    }
3166 06 Mar 07 enell 740    finally
3166 06 Mar 07 enell 741    {
3166 06 Mar 07 enell 742       // IMPORTANT!!! Make sure opened connections are closed
3166 06 Mar 07 enell 743       if (dc != null) dc.close();
3166 06 Mar 07 enell 744    }
3371 24 May 07 martin 745 }</programlisting>
3178 12 Mar 07 enell 746               </example>
3178 12 Mar 07 enell 747             </listitem>
3178 12 Mar 07 enell 748           </varlistentry>
3178 12 Mar 07 enell 749           <varlistentry>
3178 12 Mar 07 enell 750             <term>
3178 12 Mar 07 enell 751               <methodsynopsis language="java">
3178 12 Mar 07 enell 752                 <modifier>public</modifier>
3178 12 Mar 07 enell 753                 <void />
3178 12 Mar 07 enell 754                 <methodname>done</methodname>
3178 12 Mar 07 enell 755                 <void />
3178 12 Mar 07 enell 756               </methodsynopsis>
3178 12 Mar 07 enell 757             </term>
3178 12 Mar 07 enell 758             <listitem>
3178 12 Mar 07 enell 759               <para>
3487 13 Jun 07 peter 760                 Clean up all resources after executing the plug-in. This method must not
3178 12 Mar 07 enell 761                 throw any exceptions.
3178 12 Mar 07 enell 762               </para>
3178 12 Mar 07 enell 763               <example id="net.sf.basedb.core.plugin.Plugin.done">
3178 12 Mar 07 enell 764                 <title>
3178 12 Mar 07 enell 765                   The
3944 09 Nov 07 martin 766                   <classname docapi="net.sf.basedb.core.plugin">AbstractPlugin</classname>
3366 23 May 07 nicklas 767                   contains an implementation of the <methodname>done()</methodname>
3366 23 May 07 nicklas 768                   method simply sets the
3178 12 Mar 07 enell 769                   parameters passed to the
3178 12 Mar 07 enell 770                   <methodname>init()</methodname>
3178 12 Mar 07 enell 771                   method to null
3178 12 Mar 07 enell 772                 </title>
3838 16 Oct 07 nicklas 773 <programlisting language="java">
3838 16 Oct 07 nicklas 774 /**
3166 06 Mar 07 enell 775    Clears the variables set by the init method. If a subclass 
3166 06 Mar 07 enell 776    overrides this method it is recommended that it also calls super.done().
3166 06 Mar 07 enell 777 */
3166 06 Mar 07 enell 778 public void done()
3166 06 Mar 07 enell 779 {
3166 06 Mar 07 enell 780    configuration = null;
3166 06 Mar 07 enell 781    job = null;
3166 06 Mar 07 enell 782    sc = null;
3371 24 May 07 martin 783 }</programlisting>
3178 12 Mar 07 enell 784               </example>
3178 12 Mar 07 enell 785             </listitem>
3178 12 Mar 07 enell 786           </varlistentry>
3178 12 Mar 07 enell 787         </variablelist>
3178 12 Mar 07 enell 788       </sect3>
3178 12 Mar 07 enell 789   
3178 12 Mar 07 enell 790       <sect3 id="plugin_developer.api.interfaces.interactive">
3565 17 Jul 07 nicklas 791         <title>The net.sf.basedb.core.plugin.InteractivePlugin interface</title>
3178 12 Mar 07 enell 792         <para>
3366 23 May 07 nicklas 793           If you want the plug-in to be able to interact with the user you must also implement
3366 23 May 07 nicklas 794           this interface. This is probably the case for most plug-ins. Among the core plug-ins
3366 23 May 07 nicklas 795           shipped with BASE the
3944 09 Nov 07 martin 796           <classname docapi="net.sf.basedb.plugins">SpotImageCreator</classname>
3487 13 Jun 07 peter 797           is one plug-in that does not interact with the user. Instead, the web client has
3178 12 Mar 07 enell 798           special JSP pages that handles all the interaction, creates a job for it and sets
5816 20 Oct 11 nicklas 799           the parameters. This approach can also be used for other plug-ins if, for example,
5816 20 Oct 11 nicklas 800           an extension is used to provide the gui.
3178 12 Mar 07 enell 801         </para>
3178 12 Mar 07 enell 802         <para>
3178 12 Mar 07 enell 803           The
3944 09 Nov 07 martin 804           <interfacename docapi="net.sf.basedb.core.plugin">InteractivePlugin</interfacename>
3366 23 May 07 nicklas 805           has three main tasks:
3366 23 May 07 nicklas 806           
3366 23 May 07 nicklas 807           <orderedlist>
3366 23 May 07 nicklas 808           <listitem>
3366 23 May 07 nicklas 809             <para>
3366 23 May 07 nicklas 810             Tell a client application where the plug-in should be plugged
3366 23 May 07 nicklas 811             in.
3366 23 May 07 nicklas 812             </para>
3366 23 May 07 nicklas 813           </listitem>
3366 23 May 07 nicklas 814           <listitem>
3366 23 May 07 nicklas 815             <para>
3366 23 May 07 nicklas 816             Ask the users for configuration and job parameters.
3366 23 May 07 nicklas 817             </para>
3366 23 May 07 nicklas 818           </listitem>
3366 23 May 07 nicklas 819           
3366 23 May 07 nicklas 820           <listitem>
3366 23 May 07 nicklas 821             <para>
3366 23 May 07 nicklas 822             Validate parameter values entered by the user and store those in the
3366 23 May 07 nicklas 823             database.
3366 23 May 07 nicklas 824             </para>
3366 23 May 07 nicklas 825           </listitem>
3366 23 May 07 nicklas 826           </orderedlist>
3366 23 May 07 nicklas 827           This requires that the following methods are 
3366 23 May 07 nicklas 828           implemented.
3178 12 Mar 07 enell 829         </para>
3366 23 May 07 nicklas 830         
3178 12 Mar 07 enell 831         <variablelist>
3178 12 Mar 07 enell 832           <varlistentry>
3178 12 Mar 07 enell 833             <term>
3178 12 Mar 07 enell 834               <methodsynopsis language="java">
3178 12 Mar 07 enell 835                 <modifier>public</modifier>
3178 12 Mar 07 enell 836                 <type>Set&lt;GuiContext&gt;</type>
3168 07 Mar 07 enell 837                 <methodname>getGuiContexts</methodname>
3178 12 Mar 07 enell 838                 <void />
3178 12 Mar 07 enell 839               </methodsynopsis>
3178 12 Mar 07 enell 840             </term>
3178 12 Mar 07 enell 841             <listitem>
3178 12 Mar 07 enell 842               <para>
3366 23 May 07 nicklas 843                 Return information about where the plug-in should be plugged in. Each
3178 12 Mar 07 enell 844                 place is identified by a
3944 09 Nov 07 martin 845                 <classname docapi="net.sf.basedb.core.plugin">GuiContext</classname>
3178 12 Mar 07 enell 846                 object, which is an
3944 09 Nov 07 martin 847                 <classname docapi="net.sf.basedb.core">Item</classname>
3178 12 Mar 07 enell 848                 and a
3944 09 Nov 07 martin 849                 <classname docapi="net.sf.basedb.core">Type</classname>.
3366 23 May 07 nicklas 850                 The item is one of the objects defined by the
3944 09 Nov 07 martin 851                 <classname docapi="net.sf.basedb.core">Item</classname>
3178 12 Mar 07 enell 852                 enumeration and the type is either
3178 12 Mar 07 enell 853                 <constant>Type.LIST</constant>
3178 12 Mar 07 enell 854                 or
3366 23 May 07 nicklas 855                 <constant>Type.ITEM</constant>, which corresponde to the
3366 23 May 07 nicklas 856                 list view and the single-item view in the web client.
3178 12 Mar 07 enell 857               </para>
3178 12 Mar 07 enell 858               <para>
3178 12 Mar 07 enell 859                 For example, the
3366 23 May 07 nicklas 860                 <varname>GuiContext</varname> = 
3366 23 May 07 nicklas 861                 (<constant>Item.REPORTER</constant>, 
3366 23 May 07 nicklas 862                 <constant>Type.LIST</constant>)
3366 23 May 07 nicklas 863                 tells a client application that this plug-in can be plugged in whenever a
3178 12 Mar 07 enell 864                 list of reporters is displayed. The
3366 23 May 07 nicklas 865                 <varname>GuiContext</varname> =
3366 23 May 07 nicklas 866                 (<constant>Item.REPORTER</constant>,
3366 23 May 07 nicklas 867                 <constant>Type.ITEM</constant>)
3366 23 May 07 nicklas 868                 tells a client application that this plug-in can be plugged in whenever
3178 12 Mar 07 enell 869                 a single reporter is displayed. The first case may be appropriate for a
3366 23 May 07 nicklas 870                 plug-in that imports or exports reporters. The second case may be used by
3366 23 May 07 nicklas 871                 a plug-in that updates the reporter information from an external source
3178 12 Mar 07 enell 872                 (well, it may make sense to use this in the list case as well).
3178 12 Mar 07 enell 873               </para>
3178 12 Mar 07 enell 874               <para>
3178 12 Mar 07 enell 875                 The returned information is copied by the core at installation time to
3366 23 May 07 nicklas 876                 make it easy to ask for all plug-ins for a certain
3944 09 Nov 07 martin 877                 <classname docapi="net.sf.basedb.core.plugin">GuiContext</classname>.
3178 12 Mar 07 enell 878               </para>
3178 12 Mar 07 enell 879               <para>
3178 12 Mar 07 enell 880                 A typical implementation creates a static unmodifiable
3178 12 Mar 07 enell 881                 <classname>Set</classname>
3178 12 Mar 07 enell 882                 which is returned by this method. It is important that the returned set
3487 13 Jun 07 peter 883                 cannot be modified. It may be a security issue if a misbehaving
3178 12 Mar 07 enell 884                 client application does that.
3178 12 Mar 07 enell 885               </para>
3178 12 Mar 07 enell 886               <example id="net.sf.basedb.core.plugin.InteractivePlugin.getGuiContexts">
3178 12 Mar 07 enell 887                 <title>
3178 12 Mar 07 enell 888                   A typical implementation of
3178 12 Mar 07 enell 889                   <methodname>getGuiContexts</methodname>
3178 12 Mar 07 enell 890                 </title>
3838 16 Oct 07 nicklas 891 <programlisting language="java">
3838 16 Oct 07 nicklas 892 // From the net.sf.basedb.plugins.RawDataFlatFileImporter plug-in
3168 07 Mar 07 enell 893 private static final Set&lt;GuiContext&gt; guiContexts = 
3168 07 Mar 07 enell 894    Collections.singleton(new GuiContext(Item.RAWBIOASSAY, GuiContext.Type.ITEM));
3168 07 Mar 07 enell 895
3869 19 Oct 07 nicklas 896 public Set&lt;GuiContext&gt; getGuiContexts()
3168 07 Mar 07 enell 897 {
3869 19 Oct 07 nicklas 898    return guiContexts;
3371 24 May 07 martin 899 }</programlisting>
3178 12 Mar 07 enell 900               </example>
3178 12 Mar 07 enell 901             </listitem>
3178 12 Mar 07 enell 902           </varlistentry>
3178 12 Mar 07 enell 903           <varlistentry>
3178 12 Mar 07 enell 904             <term>
3178 12 Mar 07 enell 905               <methodsynopsis language="java">
3178 12 Mar 07 enell 906                 <modifier>public</modifier>
3178 12 Mar 07 enell 907                 <type>String</type>
3168 07 Mar 07 enell 908                 <methodname>isInContext</methodname>
3178 12 Mar 07 enell 909                 <methodparam>
3178 12 Mar 07 enell 910                   <type>GuiContext</type>
3178 12 Mar 07 enell 911                   <parameter>context</parameter>
3178 12 Mar 07 enell 912                 </methodparam>
3178 12 Mar 07 enell 913                 <methodparam>
3178 12 Mar 07 enell 914                   <type>Object</type>
3178 12 Mar 07 enell 915                   <parameter>item</parameter>
3178 12 Mar 07 enell 916                 </methodparam>
3178 12 Mar 07 enell 917               </methodsynopsis>
3178 12 Mar 07 enell 918             </term>
3178 12 Mar 07 enell 919             <listitem>
3178 12 Mar 07 enell 920               <para>
3178 12 Mar 07 enell 921                 This method is called to check if a particular item is usable for the
3495 14 Jun 07 nicklas 922                 plug-in. This method is invoked to check if a plug-in can be used
3495 14 Jun 07 nicklas 923                 in a given context. If invoked from a list context the <parameter>item</parameter>
3495 14 Jun 07 nicklas 924                 parameter is <constant>null</constant>.  
3495 14 Jun 07 nicklas 925                 The plug-in should return <constant>null</constant> if it
3495 14 Jun 07 nicklas 926                 finds that it can be used. If the plug-in can't be used it
3495 14 Jun 07 nicklas 927                 must decide if the reason should be a warning or an error condition.
3495 14 Jun 07 nicklas 928               </para>
3495 14 Jun 07 nicklas 929               
3495 14 Jun 07 nicklas 930               <para>
3495 14 Jun 07 nicklas 931                 A warning is issued by returning a string with the warning
3495 14 Jun 07 nicklas 932                 message. It should be used when the plug-in can't be used because
3495 14 Jun 07 nicklas 933                 it is unrelated to the current task. For example, a plug-in for
3495 14 Jun 07 nicklas 934                 importing Genepix data should return a warning when somebody wants
3495 14 Jun 07 nicklas 935                 to import data to an Agilent raw bioassay.
3495 14 Jun 07 nicklas 936               </para>
3495 14 Jun 07 nicklas 937               
3495 14 Jun 07 nicklas 938               <para>
3495 14 Jun 07 nicklas 939                 An error message is issued by throwing an exception. This 
3495 14 Jun 07 nicklas 940                 should be used when the plug-in is related to the current task
3495 14 Jun 07 nicklas 941                 but still can't do what it is supposed to do. For example,
3495 14 Jun 07 nicklas 942                 trying to import raw data if the logged in user doesn't have
3495 14 Jun 07 nicklas 943                 write permission to the raw bioassay.
3495 14 Jun 07 nicklas 944               </para>
3495 14 Jun 07 nicklas 945               
3495 14 Jun 07 nicklas 946               <para>
3495 14 Jun 07 nicklas 947                 As a rule of thumb, if there is a chance that another plug-in
3495 14 Jun 07 nicklas 948                 might be able to perform the same task a warning should be used.
3495 14 Jun 07 nicklas 949                 If it is guaranteed that no other plug-in can do it an error
3495 14 Jun 07 nicklas 950                 message should be used.
3495 14 Jun 07 nicklas 951               </para>
3495 14 Jun 07 nicklas 952               
3178 12 Mar 07 enell 953               <para>
3178 12 Mar 07 enell 954                 Here is a real example from the
3944 09 Nov 07 martin 955                 <classname docapi="net.sf.basedb.plugins">RawDataFlatFileImporter</classname>
3366 23 May 07 nicklas 956                 plug-in which imports raw data to a
3944 09 Nov 07 martin 957                 <classname docapi="net.sf.basedb.core">RawBioAssay</classname>. 
3366 23 May 07 nicklas 958                 
3366 23 May 07 nicklas 959                 Thus,
3366 23 May 07 nicklas 960                 <varname>GuiContext</varname> = 
3366 23 May 07 nicklas 961                 (<constant>Item.RAWBIOASSAY</constant>,
3366 23 May 07 nicklas 962                 <constant>Type.ITEM</constant>), 
3366 23 May 07 nicklas 963                 
3495 14 Jun 07 nicklas 964                 but the plug-in  can only import  data if the logged in user has write permission,
3495 14 Jun 07 nicklas 965                 there is no data already, and
3366 23 May 07 nicklas 966                 if the raw bioassay has the same raw data type as the plug-in has been
3178 12 Mar 07 enell 967                 configured for.
3178 12 Mar 07 enell 968               </para>
3178 12 Mar 07 enell 969               <example id="net.sf.basedb.core.plugin.InteractivePlugin.isInContext">
3178 12 Mar 07 enell 970                 <title>
3869 19 Oct 07 nicklas 971                   A realistic implementation of the
3869 19 Oct 07 nicklas 972                   <methodname>isInContext()</methodname> method
3178 12 Mar 07 enell 973                 </title>
3838 16 Oct 07 nicklas 974 <programlisting language="java">
3838 16 Oct 07 nicklas 975 /**
3168 07 Mar 07 enell 976    Returns null if the item is a {@link RawBioAssay} of the correct
3495 14 Jun 07 nicklas 977    {@link RawDataType} and doesn't already have spots.
3495 14 Jun 07 nicklas 978    @throws PermissionDeniedException If the raw bioasssay already has raw data
3495 14 Jun 07 nicklas 979    or if the logged in user doesn't have write permission
3168 07 Mar 07 enell 980 */
3168 07 Mar 07 enell 981 public String isInContext(GuiContext context, Object item)
3168 07 Mar 07 enell 982 {
3168 07 Mar 07 enell 983    String message = null;
3168 07 Mar 07 enell 984    if (item == null)
3168 07 Mar 07 enell 985    {
3168 07 Mar 07 enell 986       message = "The object is null";
3168 07 Mar 07 enell 987    }
3168 07 Mar 07 enell 988    else if (!(item instanceof RawBioAssay))
3168 07 Mar 07 enell 989    {
3168 07 Mar 07 enell 990       message = "The object is not a RawBioAssay: " + item;
3168 07 Mar 07 enell 991    }
3168 07 Mar 07 enell 992    else
3168 07 Mar 07 enell 993    {
3168 07 Mar 07 enell 994       RawBioAssay rba = (RawBioAssay)item;
3168 07 Mar 07 enell 995       String rawDataType = (String)configuration.getValue("rawDataType");
3495 14 Jun 07 nicklas 996       RawDataType rdt = rba.getRawDataType();
3495 14 Jun 07 nicklas 997       if (!rdt.getId().equals(rawDataType))
3168 07 Mar 07 enell 998       {
3869 19 Oct 07 nicklas 999          // Warning
3495 14 Jun 07 nicklas 1000          message = "Unsupported raw data type: " + rba.getRawDataType().getName();
3168 07 Mar 07 enell 1001       }
3495 14 Jun 07 nicklas 1002       else if (!rdt.isStoredInDb())
3168 07 Mar 07 enell 1003       {
3869 19 Oct 07 nicklas 1004          // Warning
3495 14 Jun 07 nicklas 1005          message = "Raw data for raw data type '" + rdt + "' is not stored in the database";
3168 07 Mar 07 enell 1006       }
3495 14 Jun 07 nicklas 1007       else if (rba.hasData())
3495 14 Jun 07 nicklas 1008       {
3869 19 Oct 07 nicklas 1009          // Error
3495 14 Jun 07 nicklas 1010          throw new PermissionDeniedException("The raw bioassay already has data.");
3495 14 Jun 07 nicklas 1011       }
3495 14 Jun 07 nicklas 1012       else
3495 14 Jun 07 nicklas 1013       {
3869 19 Oct 07 nicklas 1014          // Error
3495 14 Jun 07 nicklas 1015          rba.checkPermission(Permission.WRITE);
3495 14 Jun 07 nicklas 1016       }
3168 07 Mar 07 enell 1017    }
3168 07 Mar 07 enell 1018    return message;    
3371 24 May 07 martin 1019 }</programlisting>
3178 12 Mar 07 enell 1020               </example>
3178 12 Mar 07 enell 1021             </listitem>
3178 12 Mar 07 enell 1022           </varlistentry>
3178 12 Mar 07 enell 1023           <varlistentry>
3178 12 Mar 07 enell 1024             <term>
3178 12 Mar 07 enell 1025               <methodsynopsis language="java">
3178 12 Mar 07 enell 1026                 <modifier>public</modifier>
3178 12 Mar 07 enell 1027                 <type>RequestInformation</type>
3178 12 Mar 07 enell 1028                 <methodname>getRequestInformation</methodname>
3178 12 Mar 07 enell 1029                 <methodparam>
3178 12 Mar 07 enell 1030                   <type>GuiContext</type>
3178 12 Mar 07 enell 1031                   <parameter>context</parameter>
3178 12 Mar 07 enell 1032                 </methodparam>
3178 12 Mar 07 enell 1033                 <methodparam>
3178 12 Mar 07 enell 1034                   <type>String</type>
3178 12 Mar 07 enell 1035                   <parameter>command</parameter>
3178 12 Mar 07 enell 1036                 </methodparam>
3178 12 Mar 07 enell 1037                 <exceptionname>BaseException</exceptionname>
3178 12 Mar 07 enell 1038               </methodsynopsis>
3178 12 Mar 07 enell 1039             </term>
3178 12 Mar 07 enell 1040             <listitem>
3178 12 Mar 07 enell 1041               <para>
3605 26 Jul 07 peter 1042                 Ask the plug-in for parameters that need to be entered by the user. The
3944 09 Nov 07 martin 1043                 <classname docapi="net.sf.basedb.core.plugin">GuiContext</classname>
3178 12 Mar 07 enell 1044                 parameter is one of the contexts returned by the
3178 12 Mar 07 enell 1045                 <methodname>getGuiContexts</methodname>
3479 12 Jun 07 peter 1046                 method. The command is a string telling the plug-in what command was
3178 12 Mar 07 enell 1047                 executed. There are two predefined commands but as you will see the
3609 27 Jul 07 peter 1048                 plug-in may define its own commands. The two predefined commands are
3178 12 Mar 07 enell 1049                 defined in the
3944 09 Nov 07 martin 1050                 <classname docapi="net.sf.basedb.core.plugin">net.sf.basedb.core.plugin.Request</classname>
3178 12 Mar 07 enell 1051                 class.
3178 12 Mar 07 enell 1052                 <variablelist>
3178 12 Mar 07 enell 1053                   <varlistentry>
3178 12 Mar 07 enell 1054                     <term>
3178 12 Mar 07 enell 1055                       <constant>Request.COMMAND_CONFIGURE_PLUGIN</constant>
3178 12 Mar 07 enell 1056                     </term>
3178 12 Mar 07 enell 1057                     <listitem>
3178 12 Mar 07 enell 1058                       <para>
3178 12 Mar 07 enell 1059                         Used when an administrator is initiating a configuration
3366 23 May 07 nicklas 1060                         of the plug-in.
3178 12 Mar 07 enell 1061                       </para>
3178 12 Mar 07 enell 1062                     </listitem>
3178 12 Mar 07 enell 1063                   </varlistentry>
3178 12 Mar 07 enell 1064                   <varlistentry>
3178 12 Mar 07 enell 1065                     <term>
3178 12 Mar 07 enell 1066                       <constant>Request.COMMAND_CONFIGURE_JOB</constant>
3178 12 Mar 07 enell 1067                     </term>
3178 12 Mar 07 enell 1068                     <listitem>
3178 12 Mar 07 enell 1069                       <para>
3366 23 May 07 nicklas 1070                         Used when a user has selected the plug-in for running a
3178 12 Mar 07 enell 1071                         job.
3178 12 Mar 07 enell 1072                       </para>
3178 12 Mar 07 enell 1073                     </listitem>
3178 12 Mar 07 enell 1074                   </varlistentry>
3178 12 Mar 07 enell 1075                 </variablelist>
3366 23 May 07 nicklas 1076                 Given this information the plug-in must return a
3944 09 Nov 07 martin 1077                 <classname docapi="net.sf.basedb.core">RequestInformation</classname>
3479 12 Jun 07 peter 1078                 object. This is simply a title, a description, and a list of parameters.
3178 12 Mar 07 enell 1079                 Usually the title will end up as the input form title and the
3178 12 Mar 07 enell 1080                 description as a help text for the entire form. Do not put information
3178 12 Mar 07 enell 1081                 about the individual parameters in this description, since each
3479 12 Jun 07 peter 1082                 parameter has a description of its own.
3178 12 Mar 07 enell 1083               </para>
3182 12 Mar 07 enell 1084               <example id="net.sf.basedb.core.plugin.InteractivePlugin.getRequestInformation">
3178 12 Mar 07 enell 1085                 <title>
3366 23 May 07 nicklas 1086                   When running an import plug-in it needs to ask for the file to import
3178 12 Mar 07 enell 1087                   from and if existing items should be updated or not
3178 12 Mar 07 enell 1088                 </title>
3838 16 Oct 07 nicklas 1089 <programlisting language="java">
3838 16 Oct 07 nicklas 1090 // The complete request information
3169 07 Mar 07 enell 1091 private RequestInformation configure Job;
3168 07 Mar 07 enell 1092
3168 07 Mar 07 enell 1093 // The parameter that asks for a file to import from
3169 07 Mar 07 enell 1094 private PluginParameter&lt;File&gt; file Parameter;
3168 07 Mar 07 enell 1095
3168 07 Mar 07 enell 1096 // The parameter that asks if existing items should be updated or not
3168 07 Mar 07 enell 1097 private PluginParameter&lt;Boolean&gt; updateExistingParameter;
3168 07 Mar 07 enell 1098
3168 07 Mar 07 enell 1099 public RequestInformation getRequestInformation(GuiContext context, String command)
3168 07 Mar 07 enell 1100    throws BaseException
3168 07 Mar 07 enell 1101 {
3168 07 Mar 07 enell 1102    RequestInformation requestInformation = null;
3168 07 Mar 07 enell 1103    if (command.equals(Request.COMMAND_CONFIGURE_PLUGIN))
3168 07 Mar 07 enell 1104    {
3168 07 Mar 07 enell 1105       requestInformation = getConfigurePlugin();
3168 07 Mar 07 enell 1106    }
3168 07 Mar 07 enell 1107    else if (command.equals(Request.COMMAND_CONFIGURE_JOB))
3168 07 Mar 07 enell 1108    {
3168 07 Mar 07 enell 1109       requestInformation = getConfigureJob();
3168 07 Mar 07 enell 1110    }
3168 07 Mar 07 enell 1111    return requestInformation;
3168 07 Mar 07 enell 1112 }
3168 07 Mar 07 enell 1113
3168 07 Mar 07 enell 1114 /**
3168 07 Mar 07 enell 1115    Get (and build) the request information for starting a job.
3168 07 Mar 07 enell 1116 */
3168 07 Mar 07 enell 1117 private RequestInformation getConfigureJob()
3168 07 Mar 07 enell 1118 {
3168 07 Mar 07 enell 1119    if (configureJob == null)
3168 07 Mar 07 enell 1120    {
3869 19 Oct 07 nicklas 1121       // A file is required
3168 07 Mar 07 enell 1122       fileParameter = new PluginParameter&lt;File&gt;(
3168 07 Mar 07 enell 1123          "file",
3168 07 Mar 07 enell 1124          "File",
3168 07 Mar 07 enell 1125          "The file to import the data from",
3168 07 Mar 07 enell 1126          new FileParameterType(null, true, 1)
3168 07 Mar 07 enell 1127       ); 
3168 07 Mar 07 enell 1128       
3869 19 Oct 07 nicklas 1129       // The default value is 'false'
3168 07 Mar 07 enell 1130       updateExistingParameter = new PluginParameter&lt;Boolean&gt;(
3168 07 Mar 07 enell 1131          "updateExisting",
3168 07 Mar 07 enell 1132          "Update existing items",
3168 07 Mar 07 enell 1133          "If this option is selected, already existing items will be updated " +
3487 13 Jun 07 peter 1134          " with the information in the file. If this option is not selected " +
3168 07 Mar 07 enell 1135          " existing items are left untouched.",
3168 07 Mar 07 enell 1136          new BooleanParameterType(false, true)
3168 07 Mar 07 enell 1137       );
3168 07 Mar 07 enell 1138
3168 07 Mar 07 enell 1139       List&lt;PluginParameter&lt;?&gt;&gt; parameters = 
3168 07 Mar 07 enell 1140          new ArrayList&lt;PluginParameter&lt;?&gt;&gt;(2);
3168 07 Mar 07 enell 1141       parameters.add(fileParameter);
3168 07 Mar 07 enell 1142       parameters.add(updateExistingParameter);
3168 07 Mar 07 enell 1143       
3168 07 Mar 07 enell 1144       configureJob = new RequestInformation
3168 07 Mar 07 enell 1145       (
3168 07 Mar 07 enell 1146          Request.COMMAND_CONFIGURE_JOB,
3168 07 Mar 07 enell 1147          "Select a file to import items from",
3170 07 Mar 07 enell 1148          "Description",
3168 07 Mar 07 enell 1149          parameters
3168 07 Mar 07 enell 1150       );
3168 07 Mar 07 enell 1151    }
3168 07 Mar 07 enell 1152    return configureJob;
3371 24 May 07 martin 1153 }</programlisting>
3178 12 Mar 07 enell 1154               </example>
3178 12 Mar 07 enell 1155               <para>
3366 23 May 07 nicklas 1156                 As you can see it takes a lot of code to put together a
3944 09 Nov 07 martin 1157                 <classname docapi="net.sf.basedb.core">RequestInformation</classname>
3366 23 May 07 nicklas 1158                 object. For each parameter you need one
3944 09 Nov 07 martin 1159                 <classname docapi="net.sf.basedb.core">PluginParameter</classname>
3178 12 Mar 07 enell 1160                 object and one
3944 09 Nov 07 martin 1161                 <classname docapi="net.sf.basedb.core">ParameterType</classname>
3366 23 May 07 nicklas 1162                 object. To make life a little easier, a
3944 09 Nov 07 martin 1163                 <classname docapi="net.sf.basedb.core">ParameterType</classname>
3178 12 Mar 07 enell 1164                 can be reused for more than one
3944 09 Nov 07 martin 1165                 <classname docapi="net.sf.basedb.core">PluginParameter</classname>.
3178 12 Mar 07 enell 1166               </para>
3178 12 Mar 07 enell 1167               
3838 16 Oct 07 nicklas 1168 <programlisting language="java">
3838 16 Oct 07 nicklas 1169 StringParameterType stringPT = new StringParameterType(255, null, true);
3168 07 Mar 07 enell 1170 PluginParameter one = new PluginParameter("one", "One", "First string", stringPT);
3168 07 Mar 07 enell 1171 PluginParameter two = new PluginParameter("two", "Two", "Second string", stringPT);
3838 16 Oct 07 nicklas 1172 // ... and so on
3838 16 Oct 07 nicklas 1173 </programlisting>
3168 07 Mar 07 enell 1174               <para>
3178 12 Mar 07 enell 1175                 The
3944 09 Nov 07 martin 1176                 <classname docapi="net.sf.basedb.core">ParameterType</classname>
3178 12 Mar 07 enell 1177                 is an abstract base class for several subclasses each implementing a
3178 12 Mar 07 enell 1178                 specific type of parameter. The list of subclasses may grow in the
3178 12 Mar 07 enell 1179                 future, but here are the most important ones currently implemented.
3168 07 Mar 07 enell 1180               </para>
3178 12 Mar 07 enell 1181               <note>
3178 12 Mar 07 enell 1182                 <para>
3178 12 Mar 07 enell 1183                   Most parameter types include support for supplying a predefined list
3178 12 Mar 07 enell 1184                   of options to select from. In that case the list will be displayed
3178 12 Mar 07 enell 1185                   as a drop-down list for the user, otherwise a free input field is
3178 12 Mar 07 enell 1186                   used.
3178 12 Mar 07 enell 1187                 </para>
3178 12 Mar 07 enell 1188               </note>
3178 12 Mar 07 enell 1189               <variablelist>
3178 12 Mar 07 enell 1190                 <varlistentry>
3178 12 Mar 07 enell 1191                   <term>
3944 09 Nov 07 martin 1192                     <classname docapi="net.sf.basedb.core">StringParameterType</classname>
3178 12 Mar 07 enell 1193                   </term>
3178 12 Mar 07 enell 1194                   <listitem>
3178 12 Mar 07 enell 1195                     <para>
3178 12 Mar 07 enell 1196                       Asks for a string value. Includes an option for
3178 12 Mar 07 enell 1197                       specifying the maximum length of the string.
3178 12 Mar 07 enell 1198                     </para>
3178 12 Mar 07 enell 1199                   </listitem>
3178 12 Mar 07 enell 1200                 </varlistentry>
3178 12 Mar 07 enell 1201                 <varlistentry>
3178 12 Mar 07 enell 1202                   <term>
3944 09 Nov 07 martin 1203                     <classname docapi="net.sf.basedb.core">FloatParameterType</classname>, 
3944 09 Nov 07 martin 1204                     <classname docapi="net.sf.basedb.core">DoubleParameterType</classname>, 
3944 09 Nov 07 martin 1205                     <classname docapi="net.sf.basedb.core">IntegerParameterType</classname>, 
3944 09 Nov 07 martin 1206                     <classname docapi="net.sf.basedb.core">LongParameterType</classname>
3178 12 Mar 07 enell 1207                   </term>
3178 12 Mar 07 enell 1208                   <listitem>
3178 12 Mar 07 enell 1209                     <para>
3178 12 Mar 07 enell 1210                       Asks for numerical values. Includes options for
3178 12 Mar 07 enell 1211                       specifying a range (min/max) of allowed values.
3178 12 Mar 07 enell 1212                     </para>
3178 12 Mar 07 enell 1213                   </listitem>
3178 12 Mar 07 enell 1214                 </varlistentry>
3178 12 Mar 07 enell 1215                 <varlistentry>
3178 12 Mar 07 enell 1216                   <term>
3944 09 Nov 07 martin 1217                     <classname docapi="net.sf.basedb.core">BooleanParameterType</classname>
3178 12 Mar 07 enell 1218                   </term>
3178 12 Mar 07 enell 1219                   <listitem>
3178 12 Mar 07 enell 1220                     <para>Asks for a boolean value.
3178 12 Mar 07 enell 1221                     </para>
3178 12 Mar 07 enell 1222                   </listitem>
3178 12 Mar 07 enell 1223                 </varlistentry>
3178 12 Mar 07 enell 1224                 <varlistentry>
3178 12 Mar 07 enell 1225                   <term>
3944 09 Nov 07 martin 1226                     <classname docapi="net.sf.basedb.core">DateParameterType</classname>
3178 12 Mar 07 enell 1227                   </term>
3178 12 Mar 07 enell 1228                   <listitem>
3178 12 Mar 07 enell 1229                     <para>Asks for a date.
3178 12 Mar 07 enell 1230                     </para>
3178 12 Mar 07 enell 1231                   </listitem>
3178 12 Mar 07 enell 1232                 </varlistentry>
3178 12 Mar 07 enell 1233                 <varlistentry>
3178 12 Mar 07 enell 1234                   <term>
3944 09 Nov 07 martin 1235                     <classname docapi="net.sf.basedb.core">FileParameterType</classname>
3178 12 Mar 07 enell 1236                   </term>
3178 12 Mar 07 enell 1237                   <listitem>
3178 12 Mar 07 enell 1238                     <para>Asks for a file item.
3178 12 Mar 07 enell 1239                     </para>
3178 12 Mar 07 enell 1240                   </listitem>
3178 12 Mar 07 enell 1241                 </varlistentry>
3178 12 Mar 07 enell 1242                 <varlistentry>
3178 12 Mar 07 enell 1243                   <term>
3944 09 Nov 07 martin 1244                     <classname docapi="net.sf.basedb.core">ItemParameterType</classname>
3178 12 Mar 07 enell 1245                   </term>
3178 12 Mar 07 enell 1246                   <listitem>
3178 12 Mar 07 enell 1247                     <para>
3178 12 Mar 07 enell 1248                       Asks for any other item. This parameter type requires
3178 12 Mar 07 enell 1249                       that a list of options is supplied, except when the item
3944 09 Nov 07 martin 1250                       type asked for matches the current <classname docapi="net.sf.basedb.core.plugin">GuiContext</classname>, in which
3178 12 Mar 07 enell 1251                       case the currently selected item is used as the
3178 12 Mar 07 enell 1252                       parameter value.
3178 12 Mar 07 enell 1253                     </para>
3178 12 Mar 07 enell 1254                   </listitem>
3178 12 Mar 07 enell 1255                 </varlistentry>
3178 12 Mar 07 enell 1256                 <varlistentry>
3178 12 Mar 07 enell 1257                   <term>
3944 09 Nov 07 martin 1258                     <classname docapi="net.sf.basedb.core">PathParameterType</classname>
3178 12 Mar 07 enell 1259                   </term>
3178 12 Mar 07 enell 1260                   <listitem>
3178 12 Mar 07 enell 1261                     <para>
3178 12 Mar 07 enell 1262                       Ask for a path to a file or directory. The path may be
3366 23 May 07 nicklas 1263                       non-existing and should be used when a plug-in needs an
3178 12 Mar 07 enell 1264                       output destination, i.e., the file to export to, or a
3178 12 Mar 07 enell 1265                       directory where the output files should be placed.
3178 12 Mar 07 enell 1266                     </para>
3178 12 Mar 07 enell 1267                   </listitem>
3178 12 Mar 07 enell 1268                 </varlistentry>
3178 12 Mar 07 enell 1269               </variablelist>
3178 12 Mar 07 enell 1270               <para>
3178 12 Mar 07 enell 1271                 You can also create a
3944 09 Nov 07 martin 1272                 <classname docapi="net.sf.basedb.core">PluginParameter</classname>
3178 12 Mar 07 enell 1273                 with a null name and
3944 09 Nov 07 martin 1274                 <classname docapi="net.sf.basedb.core">ParameterType</classname>.
3366 23 May 07 nicklas 1275                 In this case, the web client will not ask for input from the user, instead
3178 12 Mar 07 enell 1276                 it is used as a section header, allowing you to group parameters into
3178 12 Mar 07 enell 1277                 different sections which increase the readability of the input
3178 12 Mar 07 enell 1278                 parameters page.
3178 12 Mar 07 enell 1279               </para>
3838 16 Oct 07 nicklas 1280 <programlisting language="java">
3838 16 Oct 07 nicklas 1281 PluginParameter firstSection = new PluginParameter(null, "First section", null, null);
3168 07 Mar 07 enell 1282 PluginParameter secondSection = new PluginParameter(null, "Second section", null, null);
3168 07 Mar 07 enell 1283 // ...
3168 07 Mar 07 enell 1284
3168 07 Mar 07 enell 1285 parameters.add(firstSection);
3168 07 Mar 07 enell 1286 parameters.add(firstParameterInFirstSection);
3168 07 Mar 07 enell 1287 parameters.add(secondParameteInFirstSection);
3168 07 Mar 07 enell 1288
3168 07 Mar 07 enell 1289 parameters.add(secondSection);
3168 07 Mar 07 enell 1290 parameters.add(firstParameterInSecondSection);
3838 16 Oct 07 nicklas 1291 parameters.add(secondParameteInSecondSection);
3838 16 Oct 07 nicklas 1292 </programlisting>
3178 12 Mar 07 enell 1293             </listitem>
3178 12 Mar 07 enell 1294           </varlistentry>
3178 12 Mar 07 enell 1295           <varlistentry>
3178 12 Mar 07 enell 1296             <term>
3178 12 Mar 07 enell 1297               <methodsynopsis language="java">
3178 12 Mar 07 enell 1298                 <modifier>public</modifier>
3178 12 Mar 07 enell 1299                 <void />
3178 12 Mar 07 enell 1300                 <methodname>configure</methodname>
3178 12 Mar 07 enell 1301                 <methodparam>
3178 12 Mar 07 enell 1302                   <type>GuiContext</type>
3178 12 Mar 07 enell 1303                   <parameter>context</parameter>
3178 12 Mar 07 enell 1304                 </methodparam>
3178 12 Mar 07 enell 1305                 <methodparam>
3178 12 Mar 07 enell 1306                   <type>Request</type>
3178 12 Mar 07 enell 1307                   <parameter>request</parameter>
3178 12 Mar 07 enell 1308                 </methodparam>
3178 12 Mar 07 enell 1309                 <methodparam>
3178 12 Mar 07 enell 1310                   <type>Response</type>
3178 12 Mar 07 enell 1311                   <parameter>response</parameter>
3178 12 Mar 07 enell 1312                 </methodparam>
3178 12 Mar 07 enell 1313               </methodsynopsis>
3178 12 Mar 07 enell 1314             </term>
3178 12 Mar 07 enell 1315             <listitem>
3178 12 Mar 07 enell 1316               <para>
3366 23 May 07 nicklas 1317                 Sends parameter values entered by the user for processing by the plug-in.
3366 23 May 07 nicklas 1318                 The plug-in must validate that the parameter values are
3178 12 Mar 07 enell 1319                 correct and then store them in database.
3178 12 Mar 07 enell 1320               </para>
3366 23 May 07 nicklas 1321               
3366 23 May 07 nicklas 1322               <important>
3366 23 May 07 nicklas 1323                 <para>
3178 12 Mar 07 enell 1324                 No validation is done by the core, except converting the input to the
3366 23 May 07 nicklas 1325                 correct object type, i.e. if the plug-in asked for a
3178 12 Mar 07 enell 1326                 <classname>Float</classname>
3366 23 May 07 nicklas 1327                 the input string is parsed and converted to a 
3366 23 May 07 nicklas 1328                 <classname>Float</classname>. If you have extended the
3944 09 Nov 07 martin 1329                 <classname docapi="net.sf.basedb.core.plugin">AbstractPlugin</classname>
3366 23 May 07 nicklas 1330                 class it is very easy to validate the parameters with the
3869 19 Oct 07 nicklas 1331                 <methodname>AbstractPlugin.validateRequestParameters()</methodname>
3178 12 Mar 07 enell 1332                 method. This method takes the same list of
3944 09 Nov 07 martin 1333                 <classname docapi="net.sf.basedb.core">PluginParameter</classname>:s
3366 23 May 07 nicklas 1334                 as used in the
3944 09 Nov 07 martin 1335                 <classname docapi="net.sf.basedb.core">RequestInformation</classname>
3178 12 Mar 07 enell 1336                 object and uses that information for validation. It returns null or a
3178 12 Mar 07 enell 1337                 list of
3366 23 May 07 nicklas 1338                 <exceptionname>Throwable</exceptionname>:s that can be 
3366 23 May 07 nicklas 1339                 given directly to the <code>response.setError()</code>
3366 23 May 07 nicklas 1340                 methods.
3366 23 May 07 nicklas 1341                 </para>
3366 23 May 07 nicklas 1342               </important>
3178 12 Mar 07 enell 1343               <para>
3479 12 Jun 07 peter 1344                 When the parameters have been validated, they need to be stored
3479 12 Jun 07 peter 1345                 in the database. Once again, it is very easy, if you use one of the
3178 12 Mar 07 enell 1346                 <methodname>AbstractPlugin.storeValue()</methodname>
3178 12 Mar 07 enell 1347                 or
3178 12 Mar 07 enell 1348                 <methodname>AbstractPlugin.storeValues()</methodname>
3178 12 Mar 07 enell 1349                 methods.
3178 12 Mar 07 enell 1350               </para>
3178 12 Mar 07 enell 1351               <para>
3366 23 May 07 nicklas 1352                 The configure method works much like the <methodname>Plugin.run()</methodname> 
3944 09 Nov 07 martin 1353                 method. It must return the result in the <classname docapi="net.sf.basedb.core.plugin">Response</classname> object, 
3565 17 Jul 07 nicklas 1354                 and should not throw any exceptions.
3178 12 Mar 07 enell 1355               </para>
3366 23 May 07 nicklas 1356               
3178 12 Mar 07 enell 1357               <example id="net.sf.basedb.core.plugin.InteractivePlugin.configure">
3178 12 Mar 07 enell 1358                 <title>
3178 12 Mar 07 enell 1359                   Configuration implementation building on the examples above
3178 12 Mar 07 enell 1360                 </title>
3838 16 Oct 07 nicklas 1361 <programlisting language="java">
3838 16 Oct 07 nicklas 1362 public void configure(GuiContext context, Request request, Response response)
3169 07 Mar 07 enell 1363 {
3169 07 Mar 07 enell 1364    String command = request.getCommand();
3169 07 Mar 07 enell 1365    try
3169 07 Mar 07 enell 1366    {
3169 07 Mar 07 enell 1367       if (command.equals(Request.COMMAND_CONFIGURE_PLUGIN))
3169 07 Mar 07 enell 1368       {
3169 07 Mar 07 enell 1369          // TODO
3169 07 Mar 07 enell 1370       }
3169 07 Mar 07 enell 1371       else if (command.equals(Request.COMMAND_CONFIGURE_JOB))
3169 07 Mar 07 enell 1372       {
3169 07 Mar 07 enell 1373          // Validate user input
3169 07 Mar 07 enell 1374          List&lt;Throwable&gt; errors = 
3169 07 Mar 07 enell 1375             validateRequestParameters(getConfigureJob().getParameters(), request);
3169 07 Mar 07 enell 1376          if (errors != null)
3169 07 Mar 07 enell 1377          {
3169 07 Mar 07 enell 1378             response.setError(errors.size() +
3169 07 Mar 07 enell 1379                " invalid parameter(s) were found in the request", errors);
3169 07 Mar 07 enell 1380             return;
3169 07 Mar 07 enell 1381          }
3169 07 Mar 07 enell 1382          
3169 07 Mar 07 enell 1383          // Store user input
3169 07 Mar 07 enell 1384          storeValue(job, request, fileParameter);
3169 07 Mar 07 enell 1385          storeValue(job, request, updateExistingParameter);
3169 07 Mar 07 enell 1386          
3169 07 Mar 07 enell 1387          // We are happy and done
5633 18 May 11 nicklas 1388          File file = (File)job.getValue("file");
5633 18 May 11 nicklas 1389          response.setSuggestedJobName("Import data from file " + file.getName());
3169 07 Mar 07 enell 1390          response.setDone("Job configuration complete", Job.ExecutionTime.SHORT);
3169 07 Mar 07 enell 1391       }
3169 07 Mar 07 enell 1392    }
3169 07 Mar 07 enell 1393    catch (Throwable ex)
3169 07 Mar 07 enell 1394    {
3169 07 Mar 07 enell 1395       response.setError(ex.getMessage(), Arrays.asList(ex));
3169 07 Mar 07 enell 1396    }
3371 24 May 07 martin 1397 }</programlisting>
3178 12 Mar 07 enell 1398               </example>
3366 23 May 07 nicklas 1399               
3178 12 Mar 07 enell 1400               <para>
3366 23 May 07 nicklas 1401                 Note that the call to
3366 23 May 07 nicklas 1402                 <methodname>response.setDone()</methodname>
3178 12 Mar 07 enell 1403                 has a second parameter
3366 23 May 07 nicklas 1404                 <constant>Job.ExecutionTime.SHORT</constant>. It is an indication 
3366 23 May 07 nicklas 1405                 about how long time it will take to execute the
3366 23 May 07 nicklas 1406                 plug-in. This is of interest for job queue managers which probably
3487 13 Jun 07 peter 1407                 does not want to start too many long-running jobs at the same time
3178 12 Mar 07 enell 1408                 blocking the entire system. Please try to use this parameter wisely and
3366 23 May 07 nicklas 1409                 not use <constant>Job.ExecutionTime.SHORT</constant>
3366 23 May 07 nicklas 1410                 out of old habit all the time.
3178 12 Mar 07 enell 1411               </para>
3178 12 Mar 07 enell 1412               <para>
3944 09 Nov 07 martin 1413                 The <classname docapi="net.sf.basedb.core.plugin">Response</classname> class also has a
3178 12 Mar 07 enell 1414                 <methodname>setContinue()</methodname>
3366 23 May 07 nicklas 1415                 method which tells the core that the plug-in needs more parameters,
3178 12 Mar 07 enell 1416                 i.e. the core will then call
3178 12 Mar 07 enell 1417                 <methodname>getRequestInformation()</methodname>
3366 23 May 07 nicklas 1418                 again with the new command, let the user enter values, and then call
3178 12 Mar 07 enell 1419                 <methodname>configure()</methodname>
3366 23 May 07 nicklas 1420                 with the new values. This process is repeated until the plug-in
3178 12 Mar 07 enell 1421                 reports that it is done or an error occurs.
3178 12 Mar 07 enell 1422               </para>
3869 19 Oct 07 nicklas 1423               <tip>
3869 19 Oct 07 nicklas 1424                 <para>
3869 19 Oct 07 nicklas 1425                 You do not have to store all values the plug-in asked for in the
3869 19 Oct 07 nicklas 1426                 first place. You may even choose to store different values than
3869 19 Oct 07 nicklas 1427                 those that were entered. For example, you might ask for the mass
3869 19 Oct 07 nicklas 1428                 and height of a person and then only store the body mass index,
3869 19 Oct 07 nicklas 1429                 which is calculated from those values.
3869 19 Oct 07 nicklas 1430                 </para>
3869 19 Oct 07 nicklas 1431               </tip>
3178 12 Mar 07 enell 1432               <para>
3178 12 Mar 07 enell 1433                 An important note is that during this iteration it is the same instance
3366 23 May 07 nicklas 1434                 of the plug-in that is used. However, no parameter values are stored in
3366 23 May 07 nicklas 1435                 the database until the plugin sends a 
3366 23 May 07 nicklas 1436                 <methodname>response.setDone()</methodname>.
3366 23 May 07 nicklas 1437                 After that, the plug-in instance is usually discarded, and a job is placed
3366 23 May 07 nicklas 1438                 in the job queue. The execution  of the plug-in happens in a new instance 
3869 19 Oct 07 nicklas 1439                 and maybe on a different server. This means that a plug-in can't store
3869 19 Oct 07 nicklas 1440                 state from the configuration phase internally and expect it to be there
3869 19 Oct 07 nicklas 1441                 in the execution phase. Everything the plug-in needs to do it's job must
3869 19 Oct 07 nicklas 1442                 be stored as parameters in the database.
3178 12 Mar 07 enell 1443               </para>
3869 19 Oct 07 nicklas 1444               <para>
3869 19 Oct 07 nicklas 1445                 The only exception to the above rule is if the plug-in answers with
3869 19 Oct 07 nicklas 1446                 <methodname>Response.setExecuteImmediately()</methodname>
3869 19 Oct 07 nicklas 1447                 or <methodname>Response.setDownloadImmediately()</methodname>.
3869 19 Oct 07 nicklas 1448                 Doing so bypasses the entire job queue system and requests that the
3869 19 Oct 07 nicklas 1449                 job is started immediately. This is a permission that has to
3869 19 Oct 07 nicklas 1450                 be granted to each plug-in by the server administrator. If the 
3869 19 Oct 07 nicklas 1451                 plug-in has this permission, the same object instance that
3869 19 Oct 07 nicklas 1452                 was used in the configuration phase is also used in the execution
3869 19 Oct 07 nicklas 1453                 phase. This is the only case where a plug-in can retain internal 
3869 19 Oct 07 nicklas 1454                 state between the two phases.
3869 19 Oct 07 nicklas 1455               </para>
3178 12 Mar 07 enell 1456             </listitem>
3178 12 Mar 07 enell 1457           </varlistentry>
3178 12 Mar 07 enell 1458         </variablelist>
3178 12 Mar 07 enell 1459       </sect3>
3170 07 Mar 07 enell 1460     
3170 07 Mar 07 enell 1461     </sect2>
3178 12 Mar 07 enell 1462   
3366 23 May 07 nicklas 1463     <sect2 id="plugin_developer.api.callsequence">
3565 17 Jul 07 nicklas 1464       <title>How the BASE core interacts with the plug-in when...</title>
3366 23 May 07 nicklas 1465       
3182 12 Mar 07 enell 1466       <para>
3366 23 May 07 nicklas 1467         This section describes how the BASE core interacts with the
3366 23 May 07 nicklas 1468         plug-in in a number of use cases. We will outline the 
3366 23 May 07 nicklas 1469         order the methods are invoked on the plug-in.
3182 12 Mar 07 enell 1470       </para>
3170 07 Mar 07 enell 1471       
3366 23 May 07 nicklas 1472       <sect3 id="plugin_developer.api.callsequence.install">
3366 23 May 07 nicklas 1473         <title>Installing a plug-in</title>
3366 23 May 07 nicklas 1474         
3178 12 Mar 07 enell 1475         <para>
3366 23 May 07 nicklas 1476           When a plug-in is installed the core is eager to find out
3366 23 May 07 nicklas 1477           information about the plug-in. To do this it calls the
3366 23 May 07 nicklas 1478           following methods in this order:
3366 23 May 07 nicklas 1479         </para>
3366 23 May 07 nicklas 1480         
3366 23 May 07 nicklas 1481         <orderedlist>
3366 23 May 07 nicklas 1482         <listitem>
3366 23 May 07 nicklas 1483           <para>
3366 23 May 07 nicklas 1484           A new instance of the plug-in class is created. The plug-in must
3366 23 May 07 nicklas 1485           have a public no-argument constructor.
3366 23 May 07 nicklas 1486           </para>
3366 23 May 07 nicklas 1487         </listitem>
3366 23 May 07 nicklas 1488         
3366 23 May 07 nicklas 1489         <listitem>
3366 23 May 07 nicklas 1490           <para>
3366 23 May 07 nicklas 1491           Calls are made to <methodname>Plugin.getMainType()</methodname>,
5633 18 May 11 nicklas 1492           <methodname>Plugin.supportsConfigurations()</methodname> and
5633 18 May 11 nicklas 1493           <methodname>Plugin.requiresConfiguration()</methodname> to find out information
3662 14 Aug 07 martin 1494           about the plug-in. This is the only time these methods are called.
3366 23 May 07 nicklas 1495           The information that is returned by them are copied and stored in 
3366 23 May 07 nicklas 1496           the database for easy access.
3366 23 May 07 nicklas 1497           </para>
3366 23 May 07 nicklas 1498           
3366 23 May 07 nicklas 1499           <note>
3366 23 May 07 nicklas 1500             <para>
3366 23 May 07 nicklas 1501             The <methodname>Plugin.init()</methodname> method is
3366 23 May 07 nicklas 1502             never called during plug-in installation.
3366 23 May 07 nicklas 1503             </para>
3366 23 May 07 nicklas 1504           </note>
3366 23 May 07 nicklas 1505         </listitem>
3366 23 May 07 nicklas 1506         
3366 23 May 07 nicklas 1507         <listitem>
3366 23 May 07 nicklas 1508           <para>
3944 09 Nov 07 martin 1509           If the plug-in implements the <interfacename docapi="net.sf.basedb.core.plugin">InteractivePlugin</interfacename>
3366 23 May 07 nicklas 1510           interface the <methodname>InteractivePlugin.getGuiContexts()</methodname>
3565 17 Jul 07 nicklas 1511           method is called. This is the only time this method is called and the information it
3366 23 May 07 nicklas 1512           returns are copied and stored in the database.
3366 23 May 07 nicklas 1513           </para>
3366 23 May 07 nicklas 1514         </listitem>
3366 23 May 07 nicklas 1515         
3366 23 May 07 nicklas 1516         <listitem>
3366 23 May 07 nicklas 1517           <para>
3366 23 May 07 nicklas 1518           If the server admin decided to use the plug-in permission system, the
3366 23 May 07 nicklas 1519           <methodname>Plugin.getPermissions()</methodname> method is called.
3366 23 May 07 nicklas 1520           The returned information is copied and stored in the database.
3366 23 May 07 nicklas 1521           </para>
3366 23 May 07 nicklas 1522         </listitem>
3366 23 May 07 nicklas 1523         
3366 23 May 07 nicklas 1524         </orderedlist>
3366 23 May 07 nicklas 1525       </sect3>
3366 23 May 07 nicklas 1526     
3366 23 May 07 nicklas 1527       <sect3 id="plugin_developer.api.callsequence.configure">
3366 23 May 07 nicklas 1528         <title>Configuring a plug-in</title>
3366 23 May 07 nicklas 1529         
3366 23 May 07 nicklas 1530         <para>
3944 09 Nov 07 martin 1531           The plug-in must implement the <interfacename docapi="net.sf.basedb.core.plugin">InteractivePlugin</interfacename>
3366 23 May 07 nicklas 1532           interface and the <methodname>Plugin.supportsConfigurations()</methodname> method
3366 23 May 07 nicklas 1533           must return <constant>TRUE</constant>. The configuration is done with
3366 23 May 07 nicklas 1534           a wizard-like interface (see <xref linkend="plugins.configuration.wizard" />). 
3366 23 May 07 nicklas 1535           The same plug-in instance is used throughout the entire configuration sequence.
3366 23 May 07 nicklas 1536         </para>
3366 23 May 07 nicklas 1537         
3366 23 May 07 nicklas 1538         <orderedlist>
3366 23 May 07 nicklas 1539         <listitem>
3366 23 May 07 nicklas 1540           <para>
3366 23 May 07 nicklas 1541           A new instance of the plug-in class is created. The plug-in must
3366 23 May 07 nicklas 1542           have a public no-argument constructor.
3366 23 May 07 nicklas 1543           </para>
3366 23 May 07 nicklas 1544         </listitem>
3366 23 May 07 nicklas 1545         
3366 23 May 07 nicklas 1546         <listitem>
3366 23 May 07 nicklas 1547           <para>
3366 23 May 07 nicklas 1548           The <methodname>Plugin.init()</methodname> method is called. The 
3366 23 May 07 nicklas 1549           <varname>job</varname> parameter is null.
3366 23 May 07 nicklas 1550           </para>
3366 23 May 07 nicklas 1551         </listitem>
3366 23 May 07 nicklas 1552         
3366 23 May 07 nicklas 1553         <listitem id="plugin_developer.api.callsequence.configure.requestinformation">
3366 23 May 07 nicklas 1554           <para>
3366 23 May 07 nicklas 1555           The <methodname>InteractivePlugin.getRequestInformation()</methodname> 
3366 23 May 07 nicklas 1556           method is called. The <varname>context</varname> parameter is <constant>null</constant>
3366 23 May 07 nicklas 1557           and the <varname>command</varname> is the value of the string 
3366 23 May 07 nicklas 1558           constant <constant>Request.COMMAND_CONFIGURE_PLUGIN</constant> 
3869 19 Oct 07 nicklas 1559           (<constant>_config_plugin</constant>).
3366 23 May 07 nicklas 1560           </para>
3366 23 May 07 nicklas 1561         </listitem>
3366 23 May 07 nicklas 1562         
3366 23 May 07 nicklas 1563         <listitem id="plugin_developer.api.callsequence.configure.form">
3366 23 May 07 nicklas 1564           <para>
3869 19 Oct 07 nicklas 1565           The web client process the returned information and displays a form for user
3366 23 May 07 nicklas 1566           input. The plug-in will have to wait some time while the user enters 
3366 23 May 07 nicklas 1567           data.
3366 23 May 07 nicklas 1568           </para>
3366 23 May 07 nicklas 1569         </listitem>
3366 23 May 07 nicklas 1570         
3366 23 May 07 nicklas 1571         <listitem>
3366 23 May 07 nicklas 1572           <para>
3366 23 May 07 nicklas 1573           The <methodname>InteractivePlugin.configure()</methodname> method
3366 23 May 07 nicklas 1574           is called. The <varname>context</varname> parameter is still 
3366 23 May 07 nicklas 1575           <constant>null</constant> and the <varname>request</varname>
3366 23 May 07 nicklas 1576           parameter contains the parameter values entered by the user.
3366 23 May 07 nicklas 1577           </para>
3366 23 May 07 nicklas 1578         </listitem>
3366 23 May 07 nicklas 1579         
3366 23 May 07 nicklas 1580         <listitem>
3366 23 May 07 nicklas 1581           <para>
3479 12 Jun 07 peter 1582           The plug-in must validate the values and decide whether they should be
3366 23 May 07 nicklas 1583           stored in the database or not. We recommend that you use the
3944 09 Nov 07 martin 1584           methods in the <classname docapi="net.sf.basedb.core.plugin">AbstractPlugin</classname> class for this.
3366 23 May 07 nicklas 1585           </para>
3366 23 May 07 nicklas 1586         </listitem>
3366 23 May 07 nicklas 1587         
3366 23 May 07 nicklas 1588         <listitem>
3366 23 May 07 nicklas 1589           <para>
3565 17 Jul 07 nicklas 1590           The plug-in can choose between three different respones:
3366 23 May 07 nicklas 1591           
3366 23 May 07 nicklas 1592           <itemizedlist>
3366 23 May 07 nicklas 1593           <listitem>
3366 23 May 07 nicklas 1594             <para>
3366 23 May 07 nicklas 1595             <methodname>Response.setDone()</methodname>: The configuration
3366 23 May 07 nicklas 1596             is complete. The core will write any configuation changes to the
3366 23 May 07 nicklas 1597             database, call the <methodname>Plugin.done()</methodname> method and 
3366 23 May 07 nicklas 1598             then discard the plug-in instance.
3366 23 May 07 nicklas 1599             </para>
3366 23 May 07 nicklas 1600           </listitem>
3366 23 May 07 nicklas 1601           
3366 23 May 07 nicklas 1602           <listitem>
3366 23 May 07 nicklas 1603             <para>
3366 23 May 07 nicklas 1604             <methodname>Response.setError()</methodname>: There was one or more
3366 23 May 07 nicklas 1605             errors. The web client will display the error messages for the user and
3366 23 May 07 nicklas 1606             allow the user to enter new values. The process continues with 
3366 23 May 07 nicklas 1607             step <xref linkend="plugin_developer.api.callsequence.configure.form" />.
3366 23 May 07 nicklas 1608             </para>
3366 23 May 07 nicklas 1609           </listitem>
3366 23 May 07 nicklas 1610           
3366 23 May 07 nicklas 1611           <listitem>
3366 23 May 07 nicklas 1612             <para>
3366 23 May 07 nicklas 1613             <methodname>Response.setContinue()</methodname>: The parameters are correct
3366 23 May 07 nicklas 1614             but the plug-in wants more parameters. The process continues with
3565 17 Jul 07 nicklas 1615             step <xref linkend="plugin_developer.api.callsequence.configure.requestinformation" />
3565 17 Jul 07 nicklas 1616             but the <varname>command</varname> has the value that was passed to the 
3565 17 Jul 07 nicklas 1617             <methodname>setContinue()</methodname> method.
3366 23 May 07 nicklas 1618             </para>
3366 23 May 07 nicklas 1619           </listitem>
3366 23 May 07 nicklas 1620           </itemizedlist>
3366 23 May 07 nicklas 1621           
3366 23 May 07 nicklas 1622           </para>
3366 23 May 07 nicklas 1623         </listitem>
3366 23 May 07 nicklas 1624         </orderedlist>
3366 23 May 07 nicklas 1625
3366 23 May 07 nicklas 1626       </sect3>    
3366 23 May 07 nicklas 1627     
3366 23 May 07 nicklas 1628       <sect3 id="plugin_developer.api.callsequence.context">
3366 23 May 07 nicklas 1629         <title>Checking if a plug-in can be used in a given context</title>
3366 23 May 07 nicklas 1630         
3366 23 May 07 nicklas 1631         <para>
3944 09 Nov 07 martin 1632           If the plug-in is an <interfacename docapi="net.sf.basedb.core.plugin">InteractivePlugin</interfacename>
3366 23 May 07 nicklas 1633           it has specified in which contexts it can be used by the 
3366 23 May 07 nicklas 1634           information returned from <methodname>InteractivePlugin.getGuiContexts()</methodname>
3479 12 Jun 07 peter 1635           method. The web client uses this information to decide whether,
3479 12 Jun 07 peter 1636           for example, a <guibutton>Run plugin</guibutton>
3479 12 Jun 07 peter 1637           button should be displayed on a page or not. However, this is not
3479 12 Jun 07 peter 1638           always enough to know whether the plug-in can be used or not.
3487 13 Jun 07 peter 1639           For example, a raw data importer plug-in cannot be used to
3366 23 May 07 nicklas 1640           import raw data if the raw bioassay already has data.
3366 23 May 07 nicklas 1641           So, when the user clicks the button, the web client will
3479 12 Jun 07 peter 1642           load all plug-ins that possibly can be used in the given context
3479 12 Jun 07 peter 1643           and let each one of them check whether they can be used or not.
3366 23 May 07 nicklas 1644         </para>
3366 23 May 07 nicklas 1645         
3366 23 May 07 nicklas 1646       
3366 23 May 07 nicklas 1647         <orderedlist>
3366 23 May 07 nicklas 1648         <listitem>
3366 23 May 07 nicklas 1649           <para>
3366 23 May 07 nicklas 1650           A new instance of the plug-in class is created. The plug-in must
3366 23 May 07 nicklas 1651           have a public no-argument constructor.
3366 23 May 07 nicklas 1652           </para>
3366 23 May 07 nicklas 1653         </listitem>
3366 23 May 07 nicklas 1654         
3366 23 May 07 nicklas 1655         <listitem>
3366 23 May 07 nicklas 1656           <para>
3366 23 May 07 nicklas 1657           The <methodname>Plugin.init()</methodname> method is called.
3366 23 May 07 nicklas 1658           The <varname>job</varname> parameter is <constant>null</constant>. 
3366 23 May 07 nicklas 1659           The <varname>configuration</varname> parameter is <constant>null</constant>
3487 13 Jun 07 peter 1660           if the plug-in does not have any configuration parameters.
3366 23 May 07 nicklas 1661           </para>
3366 23 May 07 nicklas 1662         </listitem>
3366 23 May 07 nicklas 1663         
3366 23 May 07 nicklas 1664         <listitem>
3366 23 May 07 nicklas 1665           <para>
3366 23 May 07 nicklas 1666           The <methodname>InteractivePlugin.isInContext()</methodname>
3366 23 May 07 nicklas 1667           is called. If the context is a list context, the <varname>item</varname>
3366 23 May 07 nicklas 1668           parameter is null, otherwise the current item is passed. The plug-in 
3366 23 May 07 nicklas 1669           should return <constant>null</constant> if it can be used under the 
3366 23 May 07 nicklas 1670           current circumstances, or a message explaining why not.
3366 23 May 07 nicklas 1671           </para>
3366 23 May 07 nicklas 1672         </listitem>
3366 23 May 07 nicklas 1673         
3366 23 May 07 nicklas 1674         <listitem>
3366 23 May 07 nicklas 1675           <para>
3501 15 Jun 07 enell 1676             After this, <methodname>Plugin.done()</methodname> is called and 
3501 15 Jun 07 enell 1677             the plug-in instance is discarded. If there are
3479 12 Jun 07 peter 1678             several configurations for a plug-in, this procedure is repeated
3366 23 May 07 nicklas 1679             for each configuration.
3366 23 May 07 nicklas 1680           </para>
3366 23 May 07 nicklas 1681         </listitem>
3366 23 May 07 nicklas 1682         </orderedlist>
3366 23 May 07 nicklas 1683       </sect3>
3366 23 May 07 nicklas 1684     
3366 23 May 07 nicklas 1685       <sect3 id="plugin_developer.api.callsequence.job">
3366 23 May 07 nicklas 1686         <title>Creating a new job</title>
3366 23 May 07 nicklas 1687         
3366 23 May 07 nicklas 1688         <para>
3366 23 May 07 nicklas 1689           If the web client found that the plug-in could be
3662 14 Aug 07 martin 1690           used in a given context and the user selected the plug-in,
3366 23 May 07 nicklas 1691           the job configuration sequence is started. It is a wizard-like interface
3366 23 May 07 nicklas 1692           identical to the configuration wizard. In fact, the same JSP pages,
3366 23 May 07 nicklas 1693           and calling sequence is used. See <xref linkend="plugin_developer.api.callsequence.configure" />.
3487 13 Jun 07 peter 1694           We do not repeat everything here. There are a few differences:
3366 23 May 07 nicklas 1695         </para>
3366 23 May 07 nicklas 1696         
3366 23 May 07 nicklas 1697         <itemizedlist>
3366 23 May 07 nicklas 1698         <listitem>
3366 23 May 07 nicklas 1699           <para>
3487 13 Jun 07 peter 1700           The <varname>job</varname> parameter is not null, but it does not contain
3366 23 May 07 nicklas 1701           any parameter values to start with. The plug-in should use this
3366 23 May 07 nicklas 1702           object to store job-related parameter values. The 
3366 23 May 07 nicklas 1703           <varname>configuration</varname> parameter is <constant>null</constant> 
3366 23 May 07 nicklas 1704           if the plug-in is started without configuration. In any case,
3487 13 Jun 07 peter 1705           the  configuration values are write-protected and cannot be modified.
3366 23 May 07 nicklas 1706           </para>
3366 23 May 07 nicklas 1707         </listitem>
3366 23 May 07 nicklas 1708         
3366 23 May 07 nicklas 1709         <listitem>
3366 23 May 07 nicklas 1710           <para>
3366 23 May 07 nicklas 1711           The first call to <methodname>InteractivePlugin.getRequestInformation()</methodname>
3869 19 Oct 07 nicklas 1712           is done with <constant>Request.COMMAND_CONFIGURE_JOB</constant> (<constant>_configjob</constant>)
3366 23 May 07 nicklas 1713           as the command. The <varname>context</varname> parameter reflects the 
3366 23 May 07 nicklas 1714           current context.
3366 23 May 07 nicklas 1715           </para>
3366 23 May 07 nicklas 1716         </listitem>
3366 23 May 07 nicklas 1717         
3366 23 May 07 nicklas 1718         <listitem>
3366 23 May 07 nicklas 1719           <para>
3366 23 May 07 nicklas 1720           When calling <methodname>Response.setDone()</methodname> the plug-in
3366 23 May 07 nicklas 1721           should use the variant that takes an estimated execution time.
3366 23 May 07 nicklas 1722           If the plug-in has support for immediate execution or download 
3479 12 Jun 07 peter 1723           (export plug-ins only), it can also respond with 
3366 23 May 07 nicklas 1724           <methodname>Response.setExecuteImmediately()</methodname> or
3366 23 May 07 nicklas 1725           <methodname>Response.setDownloadImmediately()</methodname>.
3366 23 May 07 nicklas 1726           </para>
3366 23 May 07 nicklas 1727           
3366 23 May 07 nicklas 1728           <para>
3366 23 May 07 nicklas 1729           If the plug-in requested and was granted immediate execution or 
3366 23 May 07 nicklas 1730           download the same plug-in instance is used to execute the plug-in.
3479 12 Jun 07 peter 1731           This may be done with the same or a new thread. Otherwise, a new
3366 23 May 07 nicklas 1732           job is added to the job queue, the parameter value are saved
3366 23 May 07 nicklas 1733           and the plug-in instance is discarded after calling the
3366 23 May 07 nicklas 1734           <methodname>Plugin.done()</methodname> method.
3366 23 May 07 nicklas 1735           </para>
3366 23 May 07 nicklas 1736         </listitem>
3366 23 May 07 nicklas 1737         </itemizedlist>
3366 23 May 07 nicklas 1738       </sect3>
3366 23 May 07 nicklas 1739     
3366 23 May 07 nicklas 1740       <sect3 id="plugin_developer.api.callsequence.execute">
3366 23 May 07 nicklas 1741         <title>Executing a job</title>
3366 23 May 07 nicklas 1742         
3366 23 May 07 nicklas 1743         <para>
3366 23 May 07 nicklas 1744           Normally, the creation of a job and the execution of it are
3366 23 May 07 nicklas 1745           two different events. The execution may as well be done on a
5738 15 Sep 11 nicklas 1746           different server. See <xref linkend="installation.jobagents" />.
3366 23 May 07 nicklas 1747           This means that the execution takes place in a different instance
3366 23 May 07 nicklas 1748           of the plug-in class than what was used for creating the job.
3366 23 May 07 nicklas 1749           The exception is if a plug-in supports immediate execution or download.
3869 19 Oct 07 nicklas 1750           In this case the same instance is used, and it is, of course,
3869 19 Oct 07 nicklas 1751           always executed on the web server.
3366 23 May 07 nicklas 1752         </para>
3366 23 May 07 nicklas 1753         
3366 23 May 07 nicklas 1754         <orderedlist>
3366 23 May 07 nicklas 1755         <listitem>
3366 23 May 07 nicklas 1756           <para>
3366 23 May 07 nicklas 1757           A new instance of the plug-in class is created. The plug-in must
3366 23 May 07 nicklas 1758           have a public no-argument constructor.
3366 23 May 07 nicklas 1759           </para>
3366 23 May 07 nicklas 1760         </listitem>
3366 23 May 07 nicklas 1761         
3366 23 May 07 nicklas 1762         <listitem>
3366 23 May 07 nicklas 1763           <para>
3366 23 May 07 nicklas 1764           The <methodname>Plugin.init()</methodname> method is called.
3366 23 May 07 nicklas 1765           The <varname>job</varname> parameter contains the job
3609 27 Jul 07 peter 1766           configuration parameters. The <varname>configuration</varname> parameter 
3487 13 Jun 07 peter 1767           is <constant>null</constant> if the plug-in does not have any 
3366 23 May 07 nicklas 1768           configuration parameters.
3366 23 May 07 nicklas 1769           </para>
3366 23 May 07 nicklas 1770         </listitem>
3366 23 May 07 nicklas 1771         
3366 23 May 07 nicklas 1772         <listitem>
3366 23 May 07 nicklas 1773           <para>
3366 23 May 07 nicklas 1774           The <methodname>Plugin.run()</methodname> method is called. 
3662 14 Aug 07 martin 1775           It is finally time for the plug-in to do the work it has been
3487 13 Jun 07 peter 1776           designed for. This method should not throw any exceptions.
3366 23 May 07 nicklas 1777           Use the <methodname>Response.setDone()</methodname>
5407 13 Sep 10 nicklas 1778           method to report success, the <methodname>Response.setError()</methodname>
5407 13 Sep 10 nicklas 1779           method to report errors or the <methodname>Response.setContinue()</methodname>
5407 13 Sep 10 nicklas 1780           method to respond to a shutdown signal and tell the core to resume the
5633 18 May 11 nicklas 1781           job once the system is up and running again. The <methodname>Response.setContinue()</methodname>
5633 18 May 11 nicklas 1782           can also be used when the system is not shutting down. The job will then be
5633 18 May 11 nicklas 1783           put back into the job queue and executed again later.
3366 23 May 07 nicklas 1784           </para>
3366 23 May 07 nicklas 1785         </listitem>
3366 23 May 07 nicklas 1786         
3366 23 May 07 nicklas 1787         <listitem>
3366 23 May 07 nicklas 1788           <para>
5407 13 Sep 10 nicklas 1789           In all cases the <methodname>Plugin.done()</methodname>
3366 23 May 07 nicklas 1790           method is called and the plug-in instance is discarded.
3366 23 May 07 nicklas 1791           </para>
3366 23 May 07 nicklas 1792         </listitem>
3366 23 May 07 nicklas 1793         
3366 23 May 07 nicklas 1794         </orderedlist>
3366 23 May 07 nicklas 1795       </sect3>
3366 23 May 07 nicklas 1796     
3366 23 May 07 nicklas 1797     </sect2>
3366 23 May 07 nicklas 1798   
5816 20 Oct 11 nicklas 1799     <sect2 id="plugin_developer.signals">
5816 20 Oct 11 nicklas 1800       <title>Abort a running a plug-in</title>
5816 20 Oct 11 nicklas 1801       
5816 20 Oct 11 nicklas 1802       <para>
5816 20 Oct 11 nicklas 1803         BASE includes a simple signalling system that can be used to send
5816 20 Oct 11 nicklas 1804         signals to plug-ins. The system was primarly developed to allow a user
5816 20 Oct 11 nicklas 1805         to kill a plug-in when it is executing. Therfore, the focus of this chapter
5816 20 Oct 11 nicklas 1806         will be how to implement a plug-in to make it possible to kill it
5816 20 Oct 11 nicklas 1807         during it's execution.
5816 20 Oct 11 nicklas 1808       </para>
5816 20 Oct 11 nicklas 1809       
5816 20 Oct 11 nicklas 1810       <para>
5816 20 Oct 11 nicklas 1811         Since we don't want to do this by brute force such as destroying the
5816 20 Oct 11 nicklas 1812         process or stopping thread the plug-in executes in, cooperation is needed
5816 20 Oct 11 nicklas 1813         by the plug-in. First, the plug-in must implement the 
5816 20 Oct 11 nicklas 1814         <interfacename docapi="net.sf.basedb.core.signal">SignalTarget</interfacename>
5816 20 Oct 11 nicklas 1815         interface. From this, a <interfacename 
5816 20 Oct 11 nicklas 1816         docapi="net.sf.basedb.core.signal">SignalHandler</interfacename> can be created.
5816 20 Oct 11 nicklas 1817         A plug-in may choose to implement it's own signal handler or use an existing
5816 20 Oct 11 nicklas 1818         implementation. BASE, for example, provides the <classname docapi="net.sf.basedb.core.signal"
5816 20 Oct 11 nicklas 1819         >ThreadSignalHandler</classname> implementation that supports the <constant>ABORT</constant> signal.
5816 20 Oct 11 nicklas 1820         This is a simple implementation that just calls <code>Thread.interrupt()</code>
5816 20 Oct 11 nicklas 1821         on the plug-in worker thread. This may cause two different effects:
5816 20 Oct 11 nicklas 1822       </para>
5816 20 Oct 11 nicklas 1823       
5816 20 Oct 11 nicklas 1824       <itemizedlist>
5816 20 Oct 11 nicklas 1825       <listitem>
5816 20 Oct 11 nicklas 1826         <para>
5816 20 Oct 11 nicklas 1827         The <code>Thread.interrupted()</code> flag is set. The plug-in must check this
5816 20 Oct 11 nicklas 1828         at regular intervals and if the flag is set it must cleanup, rollback 
5816 20 Oct 11 nicklas 1829         open transactions and exit as soon as possible.
5816 20 Oct 11 nicklas 1830         </para>
5816 20 Oct 11 nicklas 1831       </listitem>
5816 20 Oct 11 nicklas 1832       
5816 20 Oct 11 nicklas 1833       <listitem>
5816 20 Oct 11 nicklas 1834         <para>
5816 20 Oct 11 nicklas 1835         If the plug-in is waiting in a blocking call that is interruptable, for
5816 20 Oct 11 nicklas 1836         example <code>Thread.sleep()</code>, an <classname>InterruptedException</classname>
5816 20 Oct 11 nicklas 1837         is thrown. This should cause the same actions as if the flag was set to happen.
5816 20 Oct 11 nicklas 1838         </para>
5816 20 Oct 11 nicklas 1839         
5816 20 Oct 11 nicklas 1840         <warning>
5816 20 Oct 11 nicklas 1841           <title>Not all blocking calls are interruptable</title>
5816 20 Oct 11 nicklas 1842           <para>
5816 20 Oct 11 nicklas 1843           For example calling <code>InputStream.read()</code> may leave the
5816 20 Oct 11 nicklas 1844           plug-in waiting in a non-interruptable state. In this case there
5816 20 Oct 11 nicklas 1845           is nothing BASE can do to wake it up again.
5816 20 Oct 11 nicklas 1846           </para>
5816 20 Oct 11 nicklas 1847         </warning>
5816 20 Oct 11 nicklas 1848       </listitem>
5816 20 Oct 11 nicklas 1849       </itemizedlist>
5816 20 Oct 11 nicklas 1850       
5816 20 Oct 11 nicklas 1851       <example id="net.sf.basedb.core.signal.SignalTarget.example1">
5816 20 Oct 11 nicklas 1852         <title>
5816 20 Oct 11 nicklas 1853           A plug-in that uses the <classname>ThreadSignalHandler</classname>
5816 20 Oct 11 nicklas 1854         </title>
5816 20 Oct 11 nicklas 1855       
5816 20 Oct 11 nicklas 1856       <programlisting language="java">
5816 20 Oct 11 nicklas 1857 <![CDATA[
5816 20 Oct 11 nicklas 1858 private ThreadSignalHandler signalHandler;
5816 20 Oct 11 nicklas 1859 public SignalHandler getSignalHandler()
5816 20 Oct 11 nicklas 1860 {
5816 20 Oct 11 nicklas 1861    signalHandler = new ThreadSignalHandler();
5816 20 Oct 11 nicklas 1862    return signalHandler;
5816 20 Oct 11 nicklas 1863 }
5816 20 Oct 11 nicklas 1864
5816 20 Oct 11 nicklas 1865 public void run(Request request, Response response, ProgressReporter progress)
5816 20 Oct 11 nicklas 1866 {
5816 20 Oct 11 nicklas 1867    if (signalHandler != null) signalHandler.setWorkerThread(null);
5816 20 Oct 11 nicklas 1868    beginTransaction();
5816 20 Oct 11 nicklas 1869    boolean done = false;
5816 20 Oct 11 nicklas 1870    boolean interrupted = false;
5816 20 Oct 11 nicklas 1871    while (!done && !interrupted)
5816 20 Oct 11 nicklas 1872    {
5816 20 Oct 11 nicklas 1873       try
5816 20 Oct 11 nicklas 1874       {
5816 20 Oct 11 nicklas 1875          done = doSomeWork(); // NOTE! This must not take forever!
5816 20 Oct 11 nicklas 1876          interrupted = Thread.interrupted();
5816 20 Oct 11 nicklas 1877       }
5816 20 Oct 11 nicklas 1878       catch (InterruptedException ex)
5816 20 Oct 11 nicklas 1879       {
5816 20 Oct 11 nicklas 1880          // NOTE! Try-catch is only needed if thread calls 
5816 20 Oct 11 nicklas 1881          // a blocking method that is interruptable 
5816 20 Oct 11 nicklas 1882          interrupted = true;
5816 20 Oct 11 nicklas 1883       }
5816 20 Oct 11 nicklas 1884    }
5816 20 Oct 11 nicklas 1885    if (interrupted)
5816 20 Oct 11 nicklas 1886    {
5816 20 Oct 11 nicklas 1887       rollbackTransaction();
5816 20 Oct 11 nicklas 1888       response.setError("Aborted by user", null);
5816 20 Oct 11 nicklas 1889    }
5816 20 Oct 11 nicklas 1890    else
5816 20 Oct 11 nicklas 1891    {
5816 20 Oct 11 nicklas 1892       commitTransaction();
5816 20 Oct 11 nicklas 1893       response.setDone("Done");
5816 20 Oct 11 nicklas 1894    }
5816 20 Oct 11 nicklas 1895 }
5816 20 Oct 11 nicklas 1896 ]]>
5816 20 Oct 11 nicklas 1897 </programlisting>
5816 20 Oct 11 nicklas 1898       </example>
5816 20 Oct 11 nicklas 1899             
5816 20 Oct 11 nicklas 1900       <para>
5816 20 Oct 11 nicklas 1901         Other signal handler implementations are
5816 20 Oct 11 nicklas 1902         <classname docapi="net.sf.basedb.core.signal">ProgressReporterSignalHandler</classname>
5816 20 Oct 11 nicklas 1903         and <classname docapi="net.sf.basedb.core.signal">EnhancedThreadSignalHandler</classname>.
5816 20 Oct 11 nicklas 1904         The latter handler also has support for the <constant>SHUTDOWN</constant> signal
5816 20 Oct 11 nicklas 1905         which is sent to plug-in when the system is shutting down. Clever plug-ins may use
5816 20 Oct 11 nicklas 1906         this to enable them to be restarted when the system is up and running again.
5816 20 Oct 11 nicklas 1907         See that javadoc for information about how to use it. For more information about the 
5816 20 Oct 11 nicklas 1908         signalling system as a whole, see <xref linkend="core_api.signals" />.
5816 20 Oct 11 nicklas 1909       </para>
5816 20 Oct 11 nicklas 1910       
5816 20 Oct 11 nicklas 1911     </sect2>
5816 20 Oct 11 nicklas 1912   
5816 20 Oct 11 nicklas 1913   
3366 23 May 07 nicklas 1914     <sect2 id="plugin_developer.api.jspparameters">
3366 23 May 07 nicklas 1915       <title>Using custom JSP pages for parameter input</title>
3366 23 May 07 nicklas 1916
3366 23 May 07 nicklas 1917         <para>
3366 23 May 07 nicklas 1918           This is an advanced option for plug-ins that require a different interface for
3565 17 Jul 07 nicklas 1919           specifying plug-in parameters than the default list showing one parameter at a
3565 17 Jul 07 nicklas 1920           time. This feature is used by setting the 
3565 17 Jul 07 nicklas 1921           <methodname>RequestInformation.getJspPage()</methodname>
3366 23 May 07 nicklas 1922           property when constructing the request information object. If this property has
3178 12 Mar 07 enell 1923           a non-null value, the web client will send the browser to the specified JSP page
3178 12 Mar 07 enell 1924           instead of to the generic parameter input page.
3178 12 Mar 07 enell 1925         </para>
3178 12 Mar 07 enell 1926         <para>
4963 08 Jun 09 nicklas 1927           When setting the JSP page you can either specify an absolute path
5633 18 May 11 nicklas 1928           or only the filename of the JSP file. If only the filename is specified, 
4963 08 Jun 09 nicklas 1929           the JSP file is expected to be located in a special location, generated
4963 08 Jun 09 nicklas 1930           from the package name of your plug-in. If the plug-in is located in the package
4963 08 Jun 09 nicklas 1931           <classname>org.company</classname> the JSP file must be located in
3366 23 May 07 nicklas 1932           <filename class="directory">&lt;base-dir&gt;/www/plugins/org/company/</filename>.
4963 08 Jun 09 nicklas 1933         </para>
4963 08 Jun 09 nicklas 1934         
4963 08 Jun 09 nicklas 1935         <para>
4963 08 Jun 09 nicklas 1936           An absolute path starts with '/' and may or may not include the
4963 08 Jun 09 nicklas 1937           root directory of the BASE installation. If, for example, BASE is intalled to
4963 08 Jun 09 nicklas 1938           <userinput>http://your.base.server.com/base</userinput>, the following absolute 
4963 08 Jun 09 nicklas 1939           paths are equivalent  <filename>/base/path/to/file.jsp</filename>, 
4963 08 Jun 09 nicklas 1940           <filename>/path/to/file.jsp</filename>.
4963 08 Jun 09 nicklas 1941         </para>
4963 08 Jun 09 nicklas 1942         <para>
4963 08 Jun 09 nicklas 1943           In both cases, please note that the browser still thinks that it is showing 
4963 08 Jun 09 nicklas 1944           the regular parameter input page at the usual location:
3366 23 May 07 nicklas 1945           <filename class="directory">&lt;base-dir&gt;/www/common/plugin/index.jsp</filename>.
3366 23 May 07 nicklas 1946           All links in your JSP page should be relative to that directory.
3178 12 Mar 07 enell 1947         </para>
3178 12 Mar 07 enell 1948         <para>
3178 12 Mar 07 enell 1949           Even if you use your own JSP page we recommend that you use the built-in
3366 23 May 07 nicklas 1950           facility for passing the parameters back to the plug-in. For this to work you
3178 12 Mar 07 enell 1951           must:
3178 12 Mar 07 enell 1952         </para>
3178 12 Mar 07 enell 1953         <itemizedlist spacing="compact">
3178 12 Mar 07 enell 1954           <listitem>
3366 23 May 07 nicklas 1955             <simpara>
3944 09 Nov 07 martin 1956             Generate the list of <classname docapi="net.sf.basedb.core">PluginParameter</classname> 
3366 23 May 07 nicklas 1957             objects as usual.
3366 23 May 07 nicklas 1958             </simpara>
3178 12 Mar 07 enell 1959           </listitem>
3178 12 Mar 07 enell 1960           <listitem>
3178 12 Mar 07 enell 1961             <simpara>
3366 23 May 07 nicklas 1962               Name all your input fields in the JSP like:
3178 12 Mar 07 enell 1963               <parameter>
3366 23 May 07 nicklas 1964                 parameter:<replaceable>name-of-parameter</replaceable>
3178 12 Mar 07 enell 1965               </parameter>
3178 12 Mar 07 enell 1966             </simpara>
3838 16 Oct 07 nicklas 1967 <programlisting language="java:nogutter">
3838 16 Oct 07 nicklas 1968 // Plug-in generate PluginParameter
3170 07 Mar 07 enell 1969 StringParameterType stringPT = new StringParameterType(255, null, true);
3170 07 Mar 07 enell 1970 PluginParameter one = new PluginParameter("one", "One", "First string", stringPT);
3170 07 Mar 07 enell 1971 PluginParameter two = new PluginParameter("two", "Two", "Second string", stringPT);
3170 07 Mar 07 enell 1972
3170 07 Mar 07 enell 1973 // JSP should name fields as:
3170 07 Mar 07 enell 1974 First string: &lt;input type="text" name="parameter:one"&gt;&lt;br&gt;
3838 16 Oct 07 nicklas 1975 Second string: &lt;input type="text" name="parameter:two"&gt;
3838 16 Oct 07 nicklas 1976 </programlisting>
3178 12 Mar 07 enell 1977           </listitem>
3178 12 Mar 07 enell 1978           <listitem>
3178 12 Mar 07 enell 1979           <simpara>
3178 12 Mar 07 enell 1980             Send the form to
3178 12 Mar 07 enell 1981             <filename>index.jsp</filename>
3518 20 Jun 07 nicklas 1982             with the <varname>ID</varname>, 
3518 20 Jun 07 nicklas 1983             <varname>cmd</varname> and <varname>requestId</varname> 
3518 20 Jun 07 nicklas 1984             parameters as shown below.
3178 12 Mar 07 enell 1985           </simpara>
3838 16 Oct 07 nicklas 1986 <programlisting language="xml">
5633 18 May 11 nicklas 1987 <![CDATA[
5633 18 May 11 nicklas 1988 <form action="index.jsp" method="post">
5633 18 May 11 nicklas 1989 <input type="hidden" name="ID" value="<%=ID%>">
5633 18 May 11 nicklas 1990 <input type="hidden" name="requestId" value="<%=request.getParameter("requestId")%>">
5633 18 May 11 nicklas 1991 <input type="hidden" name="cmd" value="SetParameters">
3170 07 Mar 07 enell 1992 ...
5633 18 May 11 nicklas 1993 </form>
5633 18 May 11 nicklas 1994 ]]>
3838 16 Oct 07 nicklas 1995 </programlisting>
3518 20 Jun 07 nicklas 1996           <simpara>
3518 20 Jun 07 nicklas 1997             The <varname>ID</varname> is the session ID for the logged
3518 20 Jun 07 nicklas 1998             in user and is required. The <varname>requestId</varname>
3518 20 Jun 07 nicklas 1999             is the ID for this particular plug-in/job configuration
3518 20 Jun 07 nicklas 2000             sequence. It is optional, but we recommend that you use it
3518 20 Jun 07 nicklas 2001             since it protects your plug-in from getting mixed up with 
5633 18 May 11 nicklas 2002             other plug-in configuration wizards. The <varname>cmd=SetParameters</varname>
3518 20 Jun 07 nicklas 2003             tells BASE to send the parameters to the plug-in for validation
3518 20 Jun 07 nicklas 2004             and saving.
3518 20 Jun 07 nicklas 2005           </simpara>
3366 23 May 07 nicklas 2006
4974 15 Jun 09 nicklas 2007           <simpara>
4974 15 Jun 09 nicklas 2008             Values are sent as strings to BASE that converts them to the
4974 15 Jun 09 nicklas 2009             proper value type before they are passed on to your plug-in. 
4974 15 Jun 09 nicklas 2010             However, there is one case that can't be
4974 15 Jun 09 nicklas 2011             accurately represented with custom JSP pages, namely 'null' values.
4974 15 Jun 09 nicklas 2012             A null value is sent by not sending any value at all. This is not
4974 15 Jun 09 nicklas 2013             possible with a fixed form. It is of course possible to add some custom
4974 15 Jun 09 nicklas 2014             JavaScript that adds and removes form elements as needed, but it is
4974 15 Jun 09 nicklas 2015             also possible to let the empty string represent null. Just include a 
4974 15 Jun 09 nicklas 2016             hidden parameter like this if you want an empty value for the 'one' 
4974 15 Jun 09 nicklas 2017             parameter converted to null:
4974 15 Jun 09 nicklas 2018           </simpara>
4974 15 Jun 09 nicklas 2019 <programlisting language="xml">
4974 15 Jun 09 nicklas 2020 &lt;input type="hidden" name="parameter:one:emptyIsNull" value="1"&gt;
4974 15 Jun 09 nicklas 2021 </programlisting>
3366 23 May 07 nicklas 2022           </listitem>
3366 23 May 07 nicklas 2023           </itemizedlist>
3518 20 Jun 07 nicklas 2024           
3518 20 Jun 07 nicklas 2025           <para>
3518 20 Jun 07 nicklas 2026             If you want a &gbCancel; button to abort the configuration
5633 18 May 11 nicklas 2027             this should be linked to a page reload with with the url:
3518 20 Jun 07 nicklas 2028             <uri>index.jsp?ID=&lt;%=ID%&gt;&amp;cmd=CancelWizard</uri>. This
3518 20 Jun 07 nicklas 2029             allows BASE to clean up resources that has been put in global
3518 20 Jun 07 nicklas 2030             session variables.
3518 20 Jun 07 nicklas 2031           </para>
3518 20 Jun 07 nicklas 2032           
3178 12 Mar 07 enell 2033             <para>
3178 12 Mar 07 enell 2034               In your JSP page you will probably need to access some information like the
3944 09 Nov 07 martin 2035               <classname docapi="net.sf.basedb.core">SessionControl</classname>, <classname docapi="net.sf.basedb.core">Job</classname>
3944 09 Nov 07 martin 2036               and possible even the <classname docapi="net.sf.basedb.core">RequestInformation</classname>
3366 23 May 07 nicklas 2037               object created by your plug-in.
3178 12 Mar 07 enell 2038             </para>
3838 16 Oct 07 nicklas 2039 <programlisting language="java">
3838 16 Oct 07 nicklas 2040 // Get session control and its ID (required to post to index.jsp)
3170 07 Mar 07 enell 2041 final SessionControl sc = Base.getExistingSessionControl(pageContext, true);
3170 07 Mar 07 enell 2042 final String ID = sc.getId();
3170 07 Mar 07 enell 2043
3366 23 May 07 nicklas 2044 // Get information about the current request to the plug-in
3170 07 Mar 07 enell 2045 PluginConfigurationRequest pcRequest = 
3170 07 Mar 07 enell 2046    (PluginConfigurationRequest)sc.getSessionSetting("plugin.configure.request");
3170 07 Mar 07 enell 2047 PluginDefinition plugin = 
3170 07 Mar 07 enell 2048    (PluginDefinition)sc.getSessionSetting("plugin.configure.plugin");
3170 07 Mar 07 enell 2049 PluginConfiguration pluginConfig = 
3170 07 Mar 07 enell 2050    (PluginConfiguration)sc.getSessionSetting("plugin.configure.config");
3170 07 Mar 07 enell 2051 PluginDefinition job = 
3170 07 Mar 07 enell 2052    (PluginDefinition)sc.getSessionSetting("plugin.configure.job");
3838 16 Oct 07 nicklas 2053 RequestInformation ri = pcRequest.getRequestInformation();
3838 16 Oct 07 nicklas 2054 </programlisting>
3366 23 May 07 nicklas 2055
3178 12 Mar 07 enell 2056     </sect2>
3166 06 Mar 07 enell 2057   </sect1>
3166 06 Mar 07 enell 2058
3178 12 Mar 07 enell 2059   <sect1 id="plugin_developer.import">
5782 04 Oct 11 nicklas 2060     <?dbhtml filename="import.html" ?>
3366 23 May 07 nicklas 2061     <title>Import plug-ins</title>
3565 17 Jul 07 nicklas 2062
3315 09 May 07 nicklas 2063     <para>
5633 18 May 11 nicklas 2064       A plug-in becomes an import plugin simply by returning 
3565 17 Jul 07 nicklas 2065       <constant>Plugin.MainType.IMPORT</constant>
3565 17 Jul 07 nicklas 2066       from the <methodname>Plugin.getMainType()</methodname> method.
3315 09 May 07 nicklas 2067     </para>
3315 09 May 07 nicklas 2068     
3178 12 Mar 07 enell 2069     <sect2 id="plugin_developer.import.autodetect">
3565 17 Jul 07 nicklas 2070       <title>Autodetect file formats</title>
3565 17 Jul 07 nicklas 2071       <para>
3565 17 Jul 07 nicklas 2072         BASE has built-in functionality for autodetecting file formats. 
3565 17 Jul 07 nicklas 2073         Your plug-in can be part of that feature if it reads it data
3565 17 Jul 07 nicklas 2074         from a single file. It must also implement the 
3944 09 Nov 07 martin 2075         <interfacename docapi="net.sf.basedb.core.plugin">AutoDetectingImporter</interfacename>
3565 17 Jul 07 nicklas 2076         interface. 
3565 17 Jul 07 nicklas 2077       </para>
3565 17 Jul 07 nicklas 2078
3565 17 Jul 07 nicklas 2079       <sect3 id="plugin_developer.api.interfaces.autodetecting">
3565 17 Jul 07 nicklas 2080         <title>The net.sf.basedb.core.plugin.AutoDetectingImporter interface</title>
3565 17 Jul 07 nicklas 2081
3565 17 Jul 07 nicklas 2082         <variablelist>
3565 17 Jul 07 nicklas 2083         <varlistentry>
3565 17 Jul 07 nicklas 2084           <term>
3565 17 Jul 07 nicklas 2085             <methodsynopsis language="java">
3565 17 Jul 07 nicklas 2086               <modifier>public</modifier>
3565 17 Jul 07 nicklas 2087               <type>boolean</type>
3565 17 Jul 07 nicklas 2088               <methodname>isImportable</methodname>
3565 17 Jul 07 nicklas 2089               <methodparam>
3565 17 Jul 07 nicklas 2090                 <type>InputStream</type>
3565 17 Jul 07 nicklas 2091                 <parameter>in</parameter>
3565 17 Jul 07 nicklas 2092               </methodparam>
3565 17 Jul 07 nicklas 2093               <exceptionname>BaseException</exceptionname>
3565 17 Jul 07 nicklas 2094             </methodsynopsis>
3565 17 Jul 07 nicklas 2095           </term>
3565 17 Jul 07 nicklas 2096           <listitem>
3565 17 Jul 07 nicklas 2097             <para>
3565 17 Jul 07 nicklas 2098               Check the input stream if it seems to contain data that can be imported by
3565 17 Jul 07 nicklas 2099               the plugin. Usually it means scanning a few lines for some header 
5633 18 May 11 nicklas 2100               matching a predefined string or regular expression.
3565 17 Jul 07 nicklas 2101             </para>
3565 17 Jul 07 nicklas 2102             <para>
5633 18 May 11 nicklas 2103               The <classname docapi="net.sf.basedb.plugins">AbstractFlatFileImporter</classname> 
5633 18 May 11 nicklas 2104               can be used for text-based files and implements this method 
3565 17 Jul 07 nicklas 2105               by reading the headers from the input stream and checking if 
3565 17 Jul 07 nicklas 2106               it stopped at an unknown type of line or not:
3838 16 Oct 07 nicklas 2107                 <programlisting language="java">
3565 17 Jul 07 nicklas 2108 public final boolean isImportable(InputStream in)
3565 17 Jul 07 nicklas 2109    throws BaseException
3565 17 Jul 07 nicklas 2110 {
3565 17 Jul 07 nicklas 2111    FlatFileParser ffp = getInitializedFlatFileParser();
3565 17 Jul 07 nicklas 2112    ffp.setInputStream(in);
3565 17 Jul 07 nicklas 2113    try
3565 17 Jul 07 nicklas 2114    {
3637 07 Aug 07 nicklas 2115       ffp.nextSection();
3565 17 Jul 07 nicklas 2116       FlatFileParser.LineType result = ffp.parseHeaders();
3637 07 Aug 07 nicklas 2117       if (result == FlatFileParser.LineType.UNKNOWN)
3637 07 Aug 07 nicklas 2118       {
3637 07 Aug 07 nicklas 2119          return false;
3637 07 Aug 07 nicklas 2120       }
3637 07 Aug 07 nicklas 2121       else
3637 07 Aug 07 nicklas 2122       {
3637 07 Aug 07 nicklas 2123          return isImportable(ffp);
3637 07 Aug 07 nicklas 2124       }
3565 17 Jul 07 nicklas 2125    }
3565 17 Jul 07 nicklas 2126    catch (IOException ex)
3565 17 Jul 07 nicklas 2127    {
3565 17 Jul 07 nicklas 2128       throw new BaseException(ex);
3565 17 Jul 07 nicklas 2129    }
3565 17 Jul 07 nicklas 2130 }
3565 17 Jul 07 nicklas 2131 </programlisting>
5633 18 May 11 nicklas 2132             
5633 18 May 11 nicklas 2133               The <classname>AbstractFlatFileImporter</classname> also has functions
5633 18 May 11 nicklas 2134               for setting the character set and automatic unwrapping of compressed
5633 18 May 11 nicklas 2135               files. See the javadoc for more information.
3565 17 Jul 07 nicklas 2136             </para>
3565 17 Jul 07 nicklas 2137             <para>
5633 18 May 11 nicklas 2138               Note that the input stream doesn't have to be a text file (but you can't use the
5633 18 May 11 nicklas 2139               <classname>AbstractFlatFileImporter</classname> then). 
3565 17 Jul 07 nicklas 2140               It can be any type of file, for example a binary or an XML file. 
3662 14 Aug 07 martin 2141               In the case of an XML file you would need to validate the entire 
3565 17 Jul 07 nicklas 2142               input stream in order to be a 100% sure that it is a valid
3565 17 Jul 07 nicklas 2143               xml file, but we recommend that you only check the first few XML tags, 
3565 17 Jul 07 nicklas 2144               for example, the &lt;!DOCTYPE &gt; declaration and/or the root element 
3565 17 Jul 07 nicklas 2145               tag.
3565 17 Jul 07 nicklas 2146             </para>
5633 18 May 11 nicklas 2147             
5633 18 May 11 nicklas 2148           <tip>
5633 18 May 11 nicklas 2149           <title>Try casting to ImportInputStream</title>
5633 18 May 11 nicklas 2150           <para>
5633 18 May 11 nicklas 2151             In many cases (but not all) the auto-detect functionality uses a
5633 18 May 11 nicklas 2152             <classname docapi="net.sf.basedb.core.plugin">ImportInputStream</classname>
5633 18 May 11 nicklas 2153             as the <varname>in</varname> parameter. This class contains some
5633 18 May 11 nicklas 2154             metadata about the file the input stream is originating from. The most
5633 18 May 11 nicklas 2155             useful feature is the possibility to get information about the
5633 18 May 11 nicklas 2156             character set used in the file. This makes it possible to open text
5633 18 May 11 nicklas 2157             files using the correct character set.
5633 18 May 11 nicklas 2158           </para>
5633 18 May 11 nicklas 2159           <programlisting language="java">
5633 18 May 11 nicklas 2160 String charset = Config.getCharset(); // Default value
5633 18 May 11 nicklas 2161 if (in instanceof ImportInputStream)
5633 18 May 11 nicklas 2162 {
5633 18 May 11 nicklas 2163    ImportInputStream iim = (ImportInputStream)in;
5633 18 May 11 nicklas 2164    if (iim.getCharacterSet() != null) charset = iim.getCharacterSet();
5633 18 May 11 nicklas 2165 }
5633 18 May 11 nicklas 2166 Reader reader = new InputStreamReader(in, Charset.forName(charset)));
5633 18 May 11 nicklas 2167 </programlisting>
5633 18 May 11 nicklas 2168         </tip>        
5633 18 May 11 nicklas 2169             
3565 17 Jul 07 nicklas 2170           </listitem>
3565 17 Jul 07 nicklas 2171         </varlistentry>
3565 17 Jul 07 nicklas 2172         <varlistentry>
3565 17 Jul 07 nicklas 2173           <term>
3565 17 Jul 07 nicklas 2174             <methodsynopsis language="java">
3565 17 Jul 07 nicklas 2175               <modifier>public</modifier>
3565 17 Jul 07 nicklas 2176               <void/>
3565 17 Jul 07 nicklas 2177               <methodname>doImport</methodname>
3565 17 Jul 07 nicklas 2178               <methodparam>
3565 17 Jul 07 nicklas 2179                 <type>InputStream</type>
3565 17 Jul 07 nicklas 2180                 <parameter>in</parameter>
3565 17 Jul 07 nicklas 2181               </methodparam>
3565 17 Jul 07 nicklas 2182               <methodparam>
3565 17 Jul 07 nicklas 2183                 <type>ProgressReporter</type>
3565 17 Jul 07 nicklas 2184                 <parameter>progress</parameter>
3565 17 Jul 07 nicklas 2185               </methodparam>
3565 17 Jul 07 nicklas 2186               <exceptionname>BaseException</exceptionname>
3565 17 Jul 07 nicklas 2187             </methodsynopsis>
3565 17 Jul 07 nicklas 2188           </term>
3565 17 Jul 07 nicklas 2189           <listitem>
3565 17 Jul 07 nicklas 2190             <para>
3565 17 Jul 07 nicklas 2191               Parse the input stream and import all data that is found. 
3565 17 Jul 07 nicklas 2192               This method is of course only called if the 
3565 17 Jul 07 nicklas 2193               <methodname>isImportable()</methodname> has returned true. Note  
3565 17 Jul 07 nicklas 2194               however that the input stream is reopened at the start of the 
3565 17 Jul 07 nicklas 2195               file. It may even be the case that the <methodname>isImportable()</methodname>
3565 17 Jul 07 nicklas 2196               method is called on one instance of the plugin and the 
3565 17 Jul 07 nicklas 2197               <methodname>doImport()</methodname> method is called on another.
3565 17 Jul 07 nicklas 2198               Thus, the <methodname>doImport()</methodname> can't rely on any state set 
3565 17 Jul 07 nicklas 2199               by the <methodname>isImportable()</methodname> method.
3565 17 Jul 07 nicklas 2200             </para>
3565 17 Jul 07 nicklas 2201           </listitem>
3565 17 Jul 07 nicklas 2202         </varlistentry>
3565 17 Jul 07 nicklas 2203         </variablelist>
4525 16 Sep 08 nicklas 2204         
3565 17 Jul 07 nicklas 2205       </sect3>
3565 17 Jul 07 nicklas 2206       
3565 17 Jul 07 nicklas 2207       <sect3 id="plugin_developer.import.autodetect.callsequence">
3565 17 Jul 07 nicklas 2208         <title>Call sequence during autodetection</title>
3565 17 Jul 07 nicklas 2209         
3565 17 Jul 07 nicklas 2210         <para>
3565 17 Jul 07 nicklas 2211           The call sequence for autodetection resembles the call sequence for 
3565 17 Jul 07 nicklas 2212           checking if the plug-in can be used in a given context.
3565 17 Jul 07 nicklas 2213         </para>
3565 17 Jul 07 nicklas 2214
3565 17 Jul 07 nicklas 2215         <orderedlist>
3565 17 Jul 07 nicklas 2216         <listitem>
3565 17 Jul 07 nicklas 2217           <para>
3565 17 Jul 07 nicklas 2218           A new instance of the plug-in class is created. The plug-in must
3565 17 Jul 07 nicklas 2219           have a public no-argument constructor.
3565 17 Jul 07 nicklas 2220           </para>
3565 17 Jul 07 nicklas 2221         </listitem>
3565 17 Jul 07 nicklas 2222         
3565 17 Jul 07 nicklas 2223         <listitem>
3565 17 Jul 07 nicklas 2224           <para>
3565 17 Jul 07 nicklas 2225           The <methodname>Plugin.init()</methodname> method is called.
3565 17 Jul 07 nicklas 2226           The <varname>job</varname> parameter is <constant>null</constant>. 
3565 17 Jul 07 nicklas 2227           The <varname>configuration</varname> parameter is <constant>null</constant>
3565 17 Jul 07 nicklas 2228           if the plug-in does not have any configuration parameters.
3565 17 Jul 07 nicklas 2229           </para>
3565 17 Jul 07 nicklas 2230         </listitem>
3565 17 Jul 07 nicklas 2231         
3565 17 Jul 07 nicklas 2232         <listitem>
3565 17 Jul 07 nicklas 2233           <para>
3565 17 Jul 07 nicklas 2234           If the plug-in is interactive the the <methodname>InteractivePlugin.isInContext()</methodname>
3565 17 Jul 07 nicklas 2235           is called. If the context is a list context, the <varname>item</varname>
3565 17 Jul 07 nicklas 2236           parameter is null, otherwise the current item is passed. The plug-in 
3565 17 Jul 07 nicklas 2237           should return <constant>null</constant> if it can be used under the 
3565 17 Jul 07 nicklas 2238           current circumstances, or a message explaining why not.
3565 17 Jul 07 nicklas 2239           </para>
3565 17 Jul 07 nicklas 2240         </listitem>
3565 17 Jul 07 nicklas 2241         
3565 17 Jul 07 nicklas 2242         <listitem>
3565 17 Jul 07 nicklas 2243           <para>
3565 17 Jul 07 nicklas 2244           If the plug-in can be used the <methodname>AutoDetectingImporter.isImportable()</methodname>
3565 17 Jul 07 nicklas 2245           method is called to check if the selected file is importable or not.
3565 17 Jul 07 nicklas 2246           </para>
3565 17 Jul 07 nicklas 2247         </listitem>
3565 17 Jul 07 nicklas 2248         
3565 17 Jul 07 nicklas 2249         <listitem>
3565 17 Jul 07 nicklas 2250           <para>
3565 17 Jul 07 nicklas 2251           After this, <methodname>Plugin.done()</methodname> is called and 
3565 17 Jul 07 nicklas 2252           the plug-in instance is discarded. If there are
3565 17 Jul 07 nicklas 2253           several configurations for a plug-in, this procedure is repeated
3565 17 Jul 07 nicklas 2254           for each configuration. If the plug-in can be used without 
3565 17 Jul 07 nicklas 2255           a configuration the procedure is also repeated without
3565 17 Jul 07 nicklas 2256           configuration parameters.
3565 17 Jul 07 nicklas 2257           </para>
3565 17 Jul 07 nicklas 2258         </listitem>
3565 17 Jul 07 nicklas 2259         
3565 17 Jul 07 nicklas 2260         <listitem>
3565 17 Jul 07 nicklas 2261           <para>
3565 17 Jul 07 nicklas 2262           If a single plug-in was found the user is taken to the regular
3565 17 Jul 07 nicklas 2263           job configuration wizard. A new plug-in instance is created for
3565 17 Jul 07 nicklas 2264           this. If more than one plug-in was found the user is presented
3565 17 Jul 07 nicklas 2265           with a list of the plug-ins. After selecting one of them the
3565 17 Jul 07 nicklas 2266           regular job configuration wizard is used with a new plug-in instance.
3565 17 Jul 07 nicklas 2267           </para>
3565 17 Jul 07 nicklas 2268         </listitem>
3565 17 Jul 07 nicklas 2269         
3565 17 Jul 07 nicklas 2270         </orderedlist>
3565 17 Jul 07 nicklas 2271         
3565 17 Jul 07 nicklas 2272       </sect3>
3565 17 Jul 07 nicklas 2273
3178 12 Mar 07 enell 2274     </sect2>
3178 12 Mar 07 enell 2275     
3178 12 Mar 07 enell 2276     <sect2 id="plugin_developer.import.abstractflatfileimporter">
3178 12 Mar 07 enell 2277       <title>The AbstractFlatFileImporter superclass</title>
3565 17 Jul 07 nicklas 2278       <para>
3944 09 Nov 07 martin 2279         The <classname docapi="net.sf.basedb.plugins">AbstractFlatFileImporter</classname> is a very useful abstract 
3565 17 Jul 07 nicklas 2280         class to use as a superclass for your own import plug-ins. It can be used
3565 17 Jul 07 nicklas 2281         if your plug-in uses regular text files that can be parsed by an instance of the 
3944 09 Nov 07 martin 2282         <classname docapi="net.sf.basedb.util">net.sf.basedb.util.FlatFileParser</classname> class. This class parses a file
3565 17 Jul 07 nicklas 2283         by checking each line against a few regular expressions. Depending on which regular
3565 17 Jul 07 nicklas 2284         expression matches the line, it is classified as a header line, a section line, 
3565 17 Jul 07 nicklas 2285         a comment, a data line, a footer line or unknown. Header lines are inspected as a group,
3565 17 Jul 07 nicklas 2286         but data lines individually, meaning that it consumes very little memory since only 
3565 17 Jul 07 nicklas 2287         a few lines at a time needs to be loaded.
3565 17 Jul 07 nicklas 2288       </para>
3565 17 Jul 07 nicklas 2289       
3565 17 Jul 07 nicklas 2290       <para>
3944 09 Nov 07 martin 2291         The <classname docapi="net.sf.basedb.plugins">AbstractFlatFileImporter</classname> defines 
3944 09 Nov 07 martin 2292         <classname docapi="net.sf.basedb.core">PluginParameter</classname> objects
3565 17 Jul 07 nicklas 2293         for each of the regular expressions and other parameters used by the parser. It also
3565 17 Jul 07 nicklas 2294         implements the <methodname>Plugin.run()</methodname> method and does most of 
3565 17 Jul 07 nicklas 2295         the ground work for instantiating a <methodname>FlatFileParser</methodname> and 
3565 17 Jul 07 nicklas 2296         parsing the file. What you have to do in your plugin is to put together the 
3944 09 Nov 07 martin 2297         <classname docapi="net.sf.basedb.core">RequestInformation</classname> objects
3565 17 Jul 07 nicklas 2298         for configuring the plugin and creating a job and implement the 
3565 17 Jul 07 nicklas 2299         <methodname>InteractivePlugin.configure()</methodname> method for validating and 
3662 14 Aug 07 martin 2300         storing the parameters. You should also implement or override some methods 
3565 17 Jul 07 nicklas 2301         defined by <classname>AbstractFlatFileImporter</classname>.
3565 17 Jul 07 nicklas 2302       </para>
3565 17 Jul 07 nicklas 2303
3565 17 Jul 07 nicklas 2304       <para>
3565 17 Jul 07 nicklas 2305       Here is what you need to do:
3565 17 Jul 07 nicklas 2306       </para>
3565 17 Jul 07 nicklas 2307
5633 18 May 11 nicklas 2308       <itemizedlist>  
3565 17 Jul 07 nicklas 2309       <listitem>
3565 17 Jul 07 nicklas 2310         <para>
3944 09 Nov 07 martin 2311         Implement the <interfacename docapi="net.sf.basedb.core.plugin">InteractivePlugin</interfacename> methods.
3565 17 Jul 07 nicklas 2312         See <xref linkend="plugin_developer.api.interfaces.interactive" /> for more information. Note that the 
3944 09 Nov 07 martin 2313         <classname docapi="net.sf.basedb.plugins">AbstractFlatFileImporter</classname>
3565 17 Jul 07 nicklas 2314         has defined many parameters for regular expressions used by the parser
3944 09 Nov 07 martin 2315         already. You should just pick them and put in your <classname docapi="net.sf.basedb.core">RequestInformation</classname>
3565 17 Jul 07 nicklas 2316         object.
3565 17 Jul 07 nicklas 2317         </para>
3565 17 Jul 07 nicklas 2318         
3838 16 Oct 07 nicklas 2319         <programlisting language="java">
3565 17 Jul 07 nicklas 2320 // Parameter that maps the items name from a column
3565 17 Jul 07 nicklas 2321 private PluginParameter&lt;String&gt; nameColumnMapping;
3565 17 Jul 07 nicklas 2322
3565 17 Jul 07 nicklas 2323 // Parameter that maps the items description from a column
3565 17 Jul 07 nicklas 2324 private PluginParameter&lt;String&gt; descriptionColumnMapping;
3565 17 Jul 07 nicklas 2325
3565 17 Jul 07 nicklas 2326 private RequestInformation getConfigurePluginParameters(GuiContext context)
3565 17 Jul 07 nicklas 2327 {
3565 17 Jul 07 nicklas 2328    if (configurePlugin == null)
3565 17 Jul 07 nicklas 2329    {
3565 17 Jul 07 nicklas 2330       // To store parameters for CONFIGURE_PLUGIN
3565 17 Jul 07 nicklas 2331       List&lt;PluginParameter&lt;?&gt;&gt; parameters = 
3565 17 Jul 07 nicklas 2332          new ArrayList&lt;PluginParameter&lt;?&gt;&gt;();
3565 17 Jul 07 nicklas 2333
3565 17 Jul 07 nicklas 2334       // Parser regular expressions - from AbstractFlatFileParser
3565 17 Jul 07 nicklas 2335       parameters.add(parserSection);
3565 17 Jul 07 nicklas 2336       parameters.add(headerRegexpParameter);
3565 17 Jul 07 nicklas 2337       parameters.add(dataHeaderRegexpParameter);
3565 17 Jul 07 nicklas 2338       parameters.add(dataSplitterRegexpParameter);
3565 17 Jul 07 nicklas 2339       parameters.add(ignoreRegexpParameter);
3565 17 Jul 07 nicklas 2340       parameters.add(dataFooterRegexpParameter);
3565 17 Jul 07 nicklas 2341       parameters.add(minDataColumnsParameter);
3565 17 Jul 07 nicklas 2342       parameters.add(maxDataColumnsParameter);
3565 17 Jul 07 nicklas 2343
3565 17 Jul 07 nicklas 2344       // Column mappings
3565 17 Jul 07 nicklas 2345       nameColumnMapping = new PluginParameter&lt;String&gt;(
3565 17 Jul 07 nicklas 2346          "nameColumnMapping",
3565 17 Jul 07 nicklas 2347          "Name",
3565 17 Jul 07 nicklas 2348          "Mapping that picks the items name from the data columns",
3565 17 Jul 07 nicklas 2349          new StringParameterType(255, null, true)
3565 17 Jul 07 nicklas 2350       );
3565 17 Jul 07 nicklas 2351     
3565 17 Jul 07 nicklas 2352       descriptionColumnMapping = new PluginParameter&lt;String&gt;(
3565 17 Jul 07 nicklas 2353         "descriptionColumnMapping",
3565 17 Jul 07 nicklas 2354         "Description",
3565 17 Jul 07 nicklas 2355         "Mapping that picks the items description from the data columns",
3565 17 Jul 07 nicklas 2356         new StringParameterType(255, null, false)
3565 17 Jul 07 nicklas 2357       );
3565 17 Jul 07 nicklas 2358
3565 17 Jul 07 nicklas 2359       parameters.add(mappingSection);
3565 17 Jul 07 nicklas 2360       parameters.add(nameColumnMapping);
3565 17 Jul 07 nicklas 2361       parameters.add(descriptionColumnMapping);
3565 17 Jul 07 nicklas 2362       
3565 17 Jul 07 nicklas 2363       configurePlugin = new RequestInformation
3565 17 Jul 07 nicklas 2364       (
3565 17 Jul 07 nicklas 2365          Request.COMMAND_CONFIGURE_PLUGIN,
3565 17 Jul 07 nicklas 2366          "File parser settings",
3565 17 Jul 07 nicklas 2367          "",
3565 17 Jul 07 nicklas 2368          parameters
3565 17 Jul 07 nicklas 2369       );
3565 17 Jul 07 nicklas 2370
3565 17 Jul 07 nicklas 2371    }
3565 17 Jul 07 nicklas 2372    return configurePlugin;
3565 17 Jul 07 nicklas 2373 }
3565 17 Jul 07 nicklas 2374 </programlisting>
3565 17 Jul 07 nicklas 2375       </listitem>
3565 17 Jul 07 nicklas 2376       
3565 17 Jul 07 nicklas 2377       <listitem>
3565 17 Jul 07 nicklas 2378         <para>
3565 17 Jul 07 nicklas 2379         Implement/override some of the methods defined by 
3565 17 Jul 07 nicklas 2380         <classname>AbstractFlatFileParser</classname>. The most important
3565 17 Jul 07 nicklas 2381         methods are listed below.
3565 17 Jul 07 nicklas 2382         </para>
3565 17 Jul 07 nicklas 2383       </listitem>
3565 17 Jul 07 nicklas 2384       
3565 17 Jul 07 nicklas 2385       </itemizedlist>
3565 17 Jul 07 nicklas 2386
3565 17 Jul 07 nicklas 2387       <variablelist>
3565 17 Jul 07 nicklas 2388       <varlistentry>
3565 17 Jul 07 nicklas 2389         <term>
3565 17 Jul 07 nicklas 2390           <methodsynopsis language="java">
3565 17 Jul 07 nicklas 2391             <modifier>protected</modifier>
3565 17 Jul 07 nicklas 2392             <type>FlatFileParser</type>
3565 17 Jul 07 nicklas 2393             <methodname>getInitializedFlatFileParser</methodname>
3565 17 Jul 07 nicklas 2394             <exceptionname>BaseException</exceptionname>
3565 17 Jul 07 nicklas 2395           </methodsynopsis>
3565 17 Jul 07 nicklas 2396         </term>
3565 17 Jul 07 nicklas 2397         <listitem>
3565 17 Jul 07 nicklas 2398           <para>
3944 09 Nov 07 martin 2399           The method is called to create a <classname docapi="net.sf.basedb.util.parser">FlatFileParser</classname>
3565 17 Jul 07 nicklas 2400           and set the regular expressions that should be used for parsing the file.
3565 17 Jul 07 nicklas 2401           The default implementation assumes that your plug-in has used the built-in
3944 09 Nov 07 martin 2402           <classname docapi="net.sf.basedb.core">PluginParameter</classname> objects and has stored the values
3565 17 Jul 07 nicklas 2403           at the configuration level. You should override this method if you need to
3662 14 Aug 07 martin 2404           initialise the parser in a different way. See for example the
3944 09 Nov 07 martin 2405           code for the <classname docapi="net.sf.basedb.plugins">PrintMapFlatFileImporter</classname> plug-in which
3565 17 Jul 07 nicklas 2406           has a fixed format and doesn't use configurations.
3565 17 Jul 07 nicklas 2407           </para>
3838 16 Oct 07 nicklas 2408           <programlisting language="java">
3565 17 Jul 07 nicklas 2409 @Override
3565 17 Jul 07 nicklas 2410 protected FlatFileParser getInitializedFlatFileParser()
3565 17 Jul 07 nicklas 2411    throws BaseException
3565 17 Jul 07 nicklas 2412 {
3565 17 Jul 07 nicklas 2413    FlatFileParser ffp = new FlatFileParser();
3565 17 Jul 07 nicklas 2414    ffp.setSectionRegexp(Pattern.compile("\\[(.+)\\]"));
3565 17 Jul 07 nicklas 2415    ffp.setHeaderRegexp(Pattern.compile("(.+)=,(.*)"));
3565 17 Jul 07 nicklas 2416    ffp.setDataSplitterRegexp(Pattern.compile(","));
3565 17 Jul 07 nicklas 2417    ffp.setDataFooterRegexp(Pattern.compile(""));
3565 17 Jul 07 nicklas 2418    ffp.setMinDataColumns(12);
3565 17 Jul 07 nicklas 2419    return ffp;
3565 17 Jul 07 nicklas 2420 }
3565 17 Jul 07 nicklas 2421 </programlisting>
3565 17 Jul 07 nicklas 2422         </listitem>
3565 17 Jul 07 nicklas 2423       </varlistentry>
3565 17 Jul 07 nicklas 2424       
3565 17 Jul 07 nicklas 2425       <varlistentry>
3565 17 Jul 07 nicklas 2426         <term>
3565 17 Jul 07 nicklas 2427           <methodsynopsis language="java">
3565 17 Jul 07 nicklas 2428             <modifier>protected</modifier>
3637 07 Aug 07 nicklas 2429             <type>boolean</type>
3637 07 Aug 07 nicklas 2430             <methodname>isImportable</methodname>
3637 07 Aug 07 nicklas 2431             <methodparam>
3637 07 Aug 07 nicklas 2432               <type>FlatFileParser</type>
3637 07 Aug 07 nicklas 2433               <parameter>ffp</parameter>
3637 07 Aug 07 nicklas 2434             </methodparam>
3637 07 Aug 07 nicklas 2435             <exceptionname>IOException</exceptionname>
3637 07 Aug 07 nicklas 2436           </methodsynopsis>
3637 07 Aug 07 nicklas 2437         </term>
3637 07 Aug 07 nicklas 2438         <listitem>
3637 07 Aug 07 nicklas 2439           <para>
3637 07 Aug 07 nicklas 2440           This method is called from the <methodname>isImportable(InputStream)</methodname>
3637 07 Aug 07 nicklas 2441           method, AFTER <methodname>FlatFileParser.nextSection()</methodname> and
3637 07 Aug 07 nicklas 2442           <methodname>FlatFileParser.parseHeaders()</methodname> has been called
3637 07 Aug 07 nicklas 2443           a single time and if the <methodname>parseHeaders</methodname> method didn't
3637 07 Aug 07 nicklas 2444           stop on an unknown line. The default implementation of this method always returns
3637 07 Aug 07 nicklas 2445           TRUE, since obviously some data has been found. A subclass may override this method
3637 07 Aug 07 nicklas 2446           if it wants to do more checks, for example, make that a certain header is present
3662 14 Aug 07 martin 2447           with a certain value. It may also continue parsing the file. Here is a code example from
3944 09 Nov 07 martin 2448           the <classname docapi="net.sf.basedb.plugins">PrintMapFlatFileImporter</classname> which checks if a 
3637 07 Aug 07 nicklas 2449           <constant>FormatName</constant> header is present and contains either 
3637 07 Aug 07 nicklas 2450           <constant>TAM</constant> or <constant>MwBr</constant>.
3637 07 Aug 07 nicklas 2451           </para>
3637 07 Aug 07 nicklas 2452           
3838 16 Oct 07 nicklas 2453           <programlisting language="java">
3637 07 Aug 07 nicklas 2454 /**
3637 07 Aug 07 nicklas 2455    Check that the file is a TAM or MwBr file.
3637 07 Aug 07 nicklas 2456    @return TRUE if a FormatName header is present and contains "TAM" or "MwBr", FALSE
3637 07 Aug 07 nicklas 2457       otherwise
3637 07 Aug 07 nicklas 2458 */
3637 07 Aug 07 nicklas 2459 @Override
3637 07 Aug 07 nicklas 2460 protected boolean isImportable(FlatFileParser ffp)
3637 07 Aug 07 nicklas 2461 {
3637 07 Aug 07 nicklas 2462    String formatName = ffp.getHeader("FormatName");
3637 07 Aug 07 nicklas 2463    return formatName != null &amp;&amp; 
3637 07 Aug 07 nicklas 2464       (formatName.contains("TAM") || formatName.contains("MwBr"));
3637 07 Aug 07 nicklas 2465 }
3637 07 Aug 07 nicklas 2466 </programlisting>
3637 07 Aug 07 nicklas 2467         </listitem>
3637 07 Aug 07 nicklas 2468       </varlistentry>
3637 07 Aug 07 nicklas 2469       
3637 07 Aug 07 nicklas 2470       <varlistentry>
3637 07 Aug 07 nicklas 2471         <term>
3637 07 Aug 07 nicklas 2472           <methodsynopsis language="java">
3637 07 Aug 07 nicklas 2473             <modifier>protected</modifier>
3565 17 Jul 07 nicklas 2474             <void/>
3565 17 Jul 07 nicklas 2475             <methodname>begin</methodname>
3565 17 Jul 07 nicklas 2476             <methodparam>
3565 17 Jul 07 nicklas 2477               <type>FlatFileParser</type>
3565 17 Jul 07 nicklas 2478               <parameter>ffp</parameter>
3565 17 Jul 07 nicklas 2479             </methodparam>
3565 17 Jul 07 nicklas 2480             <exceptionname>BaseException</exceptionname>
3565 17 Jul 07 nicklas 2481           </methodsynopsis>
3565 17 Jul 07 nicklas 2482         </term>
3565 17 Jul 07 nicklas 2483         <listitem>
3565 17 Jul 07 nicklas 2484           <para>
3565 17 Jul 07 nicklas 2485           This method is called just before the parsing of the file
3565 17 Jul 07 nicklas 2486           begins. Override this method if you need to initialise some
3565 17 Jul 07 nicklas 2487           internal state. This is, for example, a good place to open 
3944 09 Nov 07 martin 2488           a <classname docapi="net.sf.basedb.core">DbControl</classname> object, read parameters from the 
3565 17 Jul 07 nicklas 2489           job and configuration and put them into more useful variables. The default 
3565 17 Jul 07 nicklas 2490           implementation does nothing, but we recommend that 
3565 17 Jul 07 nicklas 2491           <methodname>super.begin()</methodname> is always called.
3565 17 Jul 07 nicklas 2492           </para>
3838 16 Oct 07 nicklas 2493           <programlisting language="java">
3565 17 Jul 07 nicklas 2494 // Snippets from the RawDataFlatFileImporter class
3565 17 Jul 07 nicklas 2495 private DbControl dc;
3565 17 Jul 07 nicklas 2496 private RawDataBatcher batcher;
3565 17 Jul 07 nicklas 2497 private RawBioAssay rawBioAssay;
3565 17 Jul 07 nicklas 2498 private Map&lt;String, String&gt; columnMappings;
3565 17 Jul 07 nicklas 2499 private int numInserted;
3565 17 Jul 07 nicklas 2500
3565 17 Jul 07 nicklas 2501 @Override
3565 17 Jul 07 nicklas 2502 protected void begin()
3565 17 Jul 07 nicklas 2503    throws BaseException
3565 17 Jul 07 nicklas 2504 {
3565 17 Jul 07 nicklas 2505    super.begin();
3565 17 Jul 07 nicklas 2506
3565 17 Jul 07 nicklas 2507    // Get DbControl
3565 17 Jul 07 nicklas 2508    dc = sc.newDbControl();
3565 17 Jul 07 nicklas 2509    rawBioAssay = (RawBioAssay)job.getValue(rawBioAssayParameter.getName());
3565 17 Jul 07 nicklas 2510
3565 17 Jul 07 nicklas 2511    // Reload raw bioassay using current DbControl
3565 17 Jul 07 nicklas 2512    rawBioAssay = RawBioAssay.getById(dc, rawBioAssay.getId());
3565 17 Jul 07 nicklas 2513    
3565 17 Jul 07 nicklas 2514    // Create a batcher for inserting spots
3565 17 Jul 07 nicklas 2515    batcher = rawBioAssay.getRawDataBatcher();
3565 17 Jul 07 nicklas 2516
3565 17 Jul 07 nicklas 2517    // For progress reporting
3565 17 Jul 07 nicklas 2518    numInserted = 0;
3565 17 Jul 07 nicklas 2519 }          
3565 17 Jul 07 nicklas 2520 </programlisting>
3565 17 Jul 07 nicklas 2521         </listitem>
3565 17 Jul 07 nicklas 2522       </varlistentry>
3565 17 Jul 07 nicklas 2523       <varlistentry>
3565 17 Jul 07 nicklas 2524         <term>
3565 17 Jul 07 nicklas 2525           <methodsynopsis language="java">
3565 17 Jul 07 nicklas 2526             <modifier>protected</modifier>
3565 17 Jul 07 nicklas 2527             <void/>
3565 17 Jul 07 nicklas 2528             <methodname>handleHeader</methodname>
3565 17 Jul 07 nicklas 2529             <methodparam>
3565 17 Jul 07 nicklas 2530               <type>FlatFileParser.Line</type>
3565 17 Jul 07 nicklas 2531               <parameter>line</parameter>
3565 17 Jul 07 nicklas 2532             </methodparam>
3565 17 Jul 07 nicklas 2533             <exceptionname>BaseException</exceptionname>
3565 17 Jul 07 nicklas 2534           </methodsynopsis>
3565 17 Jul 07 nicklas 2535         </term>
3565 17 Jul 07 nicklas 2536         <listitem>
3565 17 Jul 07 nicklas 2537           <para>
3565 17 Jul 07 nicklas 2538           This method is called once for every header line that is found in 
3565 17 Jul 07 nicklas 2539           the file. The <varname>line</varname> parameter contains information
3565 17 Jul 07 nicklas 2540           about the header. The default implementation of this method does
3565 17 Jul 07 nicklas 2541           nothing.
3565 17 Jul 07 nicklas 2542           </para>
3838 16 Oct 07 nicklas 2543           <programlisting language="java">
3565 17 Jul 07 nicklas 2544 @Override
3565 17 Jul 07 nicklas 2545 protected void handleHeader(Line line) 
3565 17 Jul 07 nicklas 2546    throws BaseException
3565 17 Jul 07 nicklas 2547 {
3565 17 Jul 07 nicklas 2548    super.handleHeader(line);
3565 17 Jul 07 nicklas 2549    if (line.name() != null &amp;&amp; line.value() != null)
3565 17 Jul 07 nicklas 2550    {
3565 17 Jul 07 nicklas 2551       rawBioAssay.setHeader(line.name(), line.value());
3565 17 Jul 07 nicklas 2552    }
3565 17 Jul 07 nicklas 2553 }
3565 17 Jul 07 nicklas 2554 </programlisting>
3565 17 Jul 07 nicklas 2555         </listitem>
3565 17 Jul 07 nicklas 2556       </varlistentry>
3565 17 Jul 07 nicklas 2557       <varlistentry>
3565 17 Jul 07 nicklas 2558         <term>
3565 17 Jul 07 nicklas 2559           <methodsynopsis language="java">
3565 17 Jul 07 nicklas 2560             <modifier>protected</modifier>
3565 17 Jul 07 nicklas 2561             <void/>
3565 17 Jul 07 nicklas 2562             <methodname>handleSection</methodname>
3565 17 Jul 07 nicklas 2563             <methodparam>
3565 17 Jul 07 nicklas 2564               <type>FlatFileParser.Line</type>
3565 17 Jul 07 nicklas 2565               <parameter>line</parameter>
3565 17 Jul 07 nicklas 2566             </methodparam>
3565 17 Jul 07 nicklas 2567             <exceptionname>BaseException</exceptionname>
3565 17 Jul 07 nicklas 2568           </methodsynopsis>
3565 17 Jul 07 nicklas 2569         </term>
3565 17 Jul 07 nicklas 2570         <listitem>
3565 17 Jul 07 nicklas 2571           <para>
3565 17 Jul 07 nicklas 2572             This method is called once for each section that is found in the file.
3565 17 Jul 07 nicklas 2573             The <varname>line</varname> parameter contains information
3565 17 Jul 07 nicklas 2574             about the section. The default implementation of this method does
3565 17 Jul 07 nicklas 2575             nothing.
3565 17 Jul 07 nicklas 2576           </para>
3565 17 Jul 07 nicklas 2577         </listitem>
3565 17 Jul 07 nicklas 2578       </varlistentry>
3565 17 Jul 07 nicklas 2579       
3565 17 Jul 07 nicklas 2580       <varlistentry>
3565 17 Jul 07 nicklas 2581         <term>
3565 17 Jul 07 nicklas 2582           <methodsynopsis language="java">
3565 17 Jul 07 nicklas 2583             <modifier>protected abstract</modifier>
3565 17 Jul 07 nicklas 2584             <void/>
3565 17 Jul 07 nicklas 2585             <methodname>beginData</methodname>
3565 17 Jul 07 nicklas 2586             <exceptionname>BaseException</exceptionname>
3565 17 Jul 07 nicklas 2587           </methodsynopsis>
3565 17 Jul 07 nicklas 2588         </term>
3565 17 Jul 07 nicklas 2589         <listitem>
3565 17 Jul 07 nicklas 2590           <para>
3565 17 Jul 07 nicklas 2591           This method is called after the headers has been parsed, but before
3565 17 Jul 07 nicklas 2592           the first line of data. This is a good place to add code that 
3565 17 Jul 07 nicklas 2593           depends on information in the headers, for example, put
3565 17 Jul 07 nicklas 2594           together column mappings.
3565 17 Jul 07 nicklas 2595           </para>
3565 17 Jul 07 nicklas 2596           
3838 16 Oct 07 nicklas 2597           <programlisting language="java">
3565 17 Jul 07 nicklas 2598 private Mapper reporterMapper;
3565 17 Jul 07 nicklas 2599 private Mapper blockMapper;
3565 17 Jul 07 nicklas 2600 private Mapper columnMapper;
3565 17 Jul 07 nicklas 2601 private Mapper rowMapper;
3565 17 Jul 07 nicklas 2602 // ... more mappers
3565 17 Jul 07 nicklas 2603
3565 17 Jul 07 nicklas 2604 @Override
3565 17 Jul 07 nicklas 2605 protected void beginData()
3565 17 Jul 07 nicklas 2606 {
3565 17 Jul 07 nicklas 2607    boolean cropStrings = ("crop".equals(job.getValue("stringTooLongError")));
3565 17 Jul 07 nicklas 2608
3565 17 Jul 07 nicklas 2609    // Mapper that always return null; used if no mapping expression has been entered
3565 17 Jul 07 nicklas 2610    Mapper nullMapper = new ConstantMapper((String)null);
3565 17 Jul 07 nicklas 2611    
3565 17 Jul 07 nicklas 2612    // Column mappers
3565 17 Jul 07 nicklas 2613    reporterMapper = getMapper(ffp, (String)configuration.getValue("reporterIdColumnMapping"), 
3565 17 Jul 07 nicklas 2614       cropStrings ? ReporterData.MAX_EXTERNAL_ID_LENGTH : null, nullMapper);
3838 16 Oct 07 nicklas 2615    blockMapper = getMapper(ffp, (String)configuration.getValue("blockColumnMapping"), 
3838 16 Oct 07 nicklas 2616       null, nullMapper);
3838 16 Oct 07 nicklas 2617    columnMapper = getMapper(ffp, (String)configuration.getValue("columnColumnMapping"), 
3838 16 Oct 07 nicklas 2618       null, nullMapper);
3838 16 Oct 07 nicklas 2619    rowMapper = getMapper(ffp, (String)configuration.getValue("rowColumnMapping"), 
3838 16 Oct 07 nicklas 2620       null, nullMapper);
3565 17 Jul 07 nicklas 2621    // ... more mappers: metaGrid coordinate, X-Y coordinate, extended properties
3565 17 Jul 07 nicklas 2622    // ...
3565 17 Jul 07 nicklas 2623 }
3565 17 Jul 07 nicklas 2624 </programlisting>
3565 17 Jul 07 nicklas 2625           
3565 17 Jul 07 nicklas 2626         </listitem>
3565 17 Jul 07 nicklas 2627       </varlistentry>
3565 17 Jul 07 nicklas 2628         
3565 17 Jul 07 nicklas 2629       <varlistentry>
3565 17 Jul 07 nicklas 2630         <term>
3565 17 Jul 07 nicklas 2631           <methodsynopsis language="java">
3565 17 Jul 07 nicklas 2632             <modifier>protected abstract</modifier>
3565 17 Jul 07 nicklas 2633             <void/>
3565 17 Jul 07 nicklas 2634             <methodname>handleData</methodname>
3565 17 Jul 07 nicklas 2635             <methodparam>
3565 17 Jul 07 nicklas 2636               <type>FlatFileParser.Data</type>
3565 17 Jul 07 nicklas 2637               <parameter>data</parameter>
3565 17 Jul 07 nicklas 2638             </methodparam>
3565 17 Jul 07 nicklas 2639             <exceptionname>BaseException</exceptionname>
3565 17 Jul 07 nicklas 2640           </methodsynopsis>
3565 17 Jul 07 nicklas 2641         </term>
3565 17 Jul 07 nicklas 2642         <listitem>
3565 17 Jul 07 nicklas 2643           <para>
3565 17 Jul 07 nicklas 2644           This method is abstract and must be implemented by all subclasses. 
3565 17 Jul 07 nicklas 2645           It is called once for every data line in the the file.
3565 17 Jul 07 nicklas 2646           </para>
3565 17 Jul 07 nicklas 2647
3838 16 Oct 07 nicklas 2648           <programlisting language="java">
3565 17 Jul 07 nicklas 2649 // Snippets from the RawDataFlatFileImporter class
3565 17 Jul 07 nicklas 2650 @Override
3565 17 Jul 07 nicklas 2651 protected void handleData(Data data)
3565 17 Jul 07 nicklas 2652    throws BaseException
3565 17 Jul 07 nicklas 2653 {
3565 17 Jul 07 nicklas 2654    // Create new RawData object
3565 17 Jul 07 nicklas 2655    RawData raw = batcher.newRawData();
3565 17 Jul 07 nicklas 2656
3565 17 Jul 07 nicklas 2657    // External ID for the reporter
3565 17 Jul 07 nicklas 2658    String externalId = reporterMapper.getValue(data);
3565 17 Jul 07 nicklas 2659    
3565 17 Jul 07 nicklas 2660    // Block, row and column numbers
3565 17 Jul 07 nicklas 2661    raw.setBlock(blockMapper.getInt(data));
3565 17 Jul 07 nicklas 2662    raw.setColumn(columnMapper.getInt(data));
3565 17 Jul 07 nicklas 2663    raw.setRow(rowMapper.getInt(data));
3565 17 Jul 07 nicklas 2664    // ... more: metaGrid coordinate, X-Y coordinate, extended properties
3565 17 Jul 07 nicklas 2665    
3565 17 Jul 07 nicklas 2666    // Insert raw data to the database
3565 17 Jul 07 nicklas 2667    batcher.insert(raw, externalId);
3565 17 Jul 07 nicklas 2668    numInserted++;
3565 17 Jul 07 nicklas 2669 }
3565 17 Jul 07 nicklas 2670 </programlisting> 
3565 17 Jul 07 nicklas 2671           
3565 17 Jul 07 nicklas 2672         </listitem>
3565 17 Jul 07 nicklas 2673       </varlistentry>
3565 17 Jul 07 nicklas 2674       
3565 17 Jul 07 nicklas 2675       <varlistentry>
3565 17 Jul 07 nicklas 2676         <term>
3565 17 Jul 07 nicklas 2677           <methodsynopsis language="java">
3565 17 Jul 07 nicklas 2678             <modifier>protected</modifier>
3565 17 Jul 07 nicklas 2679             <void/>
3565 17 Jul 07 nicklas 2680             <methodname>end</methodname>
3565 17 Jul 07 nicklas 2681             <methodparam>
3565 17 Jul 07 nicklas 2682               <type>boolean</type>
3565 17 Jul 07 nicklas 2683               <parameter>success</parameter>
3565 17 Jul 07 nicklas 2684             </methodparam>
3565 17 Jul 07 nicklas 2685           </methodsynopsis>
3565 17 Jul 07 nicklas 2686         </term>
3565 17 Jul 07 nicklas 2687         <listitem>
3565 17 Jul 07 nicklas 2688           <para>
3565 17 Jul 07 nicklas 2689             Called when the parsing has ended, either because the end of
3565 17 Jul 07 nicklas 2690             file was reached or because an error has occurred. The subclass
3944 09 Nov 07 martin 2691             should close any open resources, ie. the <classname docapi="net.sf.basedb.core">DbControl</classname>
3565 17 Jul 07 nicklas 2692             object. The <varname>success</varname> parameter is <constant>true</constant>
3565 17 Jul 07 nicklas 2693             if the parsing was successful, <constant>false</constant> otherwise.
3565 17 Jul 07 nicklas 2694             The default implementation does nothing.
3565 17 Jul 07 nicklas 2695           </para>
3565 17 Jul 07 nicklas 2696           
3838 16 Oct 07 nicklas 2697           <programlisting language="java">
3565 17 Jul 07 nicklas 2698 @Override
3565 17 Jul 07 nicklas 2699 protected void end(boolean success)
3565 17 Jul 07 nicklas 2700    throws BaseException
3565 17 Jul 07 nicklas 2701 {
3565 17 Jul 07 nicklas 2702    try
3565 17 Jul 07 nicklas 2703    {
3565 17 Jul 07 nicklas 2704       // Commit if the parsing was successful
3565 17 Jul 07 nicklas 2705       if (success)
3565 17 Jul 07 nicklas 2706       {
3565 17 Jul 07 nicklas 2707          batcher.close();
3565 17 Jul 07 nicklas 2708          dc.commit();
3565 17 Jul 07 nicklas 2709       }
3565 17 Jul 07 nicklas 2710    }
3565 17 Jul 07 nicklas 2711    catch (BaseException ex)
3565 17 Jul 07 nicklas 2712    {
3565 17 Jul 07 nicklas 2713       // Well, now we got an exception
3565 17 Jul 07 nicklas 2714       success = false;
3565 17 Jul 07 nicklas 2715       throw ex;
3565 17 Jul 07 nicklas 2716    }
3565 17 Jul 07 nicklas 2717    finally
3565 17 Jul 07 nicklas 2718    {
3565 17 Jul 07 nicklas 2719       // Always close... and call super.end()
3565 17 Jul 07 nicklas 2720       if (dc != null) dc.close();
3565 17 Jul 07 nicklas 2721       super.end(success);
3565 17 Jul 07 nicklas 2722    }
3565 17 Jul 07 nicklas 2723 }      
3565 17 Jul 07 nicklas 2724 </programlisting>          
3565 17 Jul 07 nicklas 2725         </listitem>
3565 17 Jul 07 nicklas 2726       </varlistentry>
3565 17 Jul 07 nicklas 2727       
3565 17 Jul 07 nicklas 2728       <varlistentry>
3565 17 Jul 07 nicklas 2729         <term>
3565 17 Jul 07 nicklas 2730           <methodsynopsis language="java">
3565 17 Jul 07 nicklas 2731             <modifier>protected</modifier>
3565 17 Jul 07 nicklas 2732             <type>String</type>
3565 17 Jul 07 nicklas 2733             <methodname>getSuccessMessage</methodname>
3565 17 Jul 07 nicklas 2734             <void/>
3565 17 Jul 07 nicklas 2735           </methodsynopsis>
3565 17 Jul 07 nicklas 2736         </term>
3565 17 Jul 07 nicklas 2737         <listitem>
3565 17 Jul 07 nicklas 2738           <para>
3565 17 Jul 07 nicklas 2739           This is the last method that is called, and it is only called if
3565 17 Jul 07 nicklas 2740           everything went suceessfully. This method allows a subclass to generate
3565 17 Jul 07 nicklas 2741           a short message that is sent back to the database as a final progress
3565 17 Jul 07 nicklas 2742           report. The default implementation returns null, which means that no
3565 17 Jul 07 nicklas 2743           message will be generated.
3565 17 Jul 07 nicklas 2744           </para>
3838 16 Oct 07 nicklas 2745           <programlisting language="java">
3565 17 Jul 07 nicklas 2746 @Override
3565 17 Jul 07 nicklas 2747 protected String getSuccessMessage()
3565 17 Jul 07 nicklas 2748 {
3565 17 Jul 07 nicklas 2749    return numInserted + " spots inserted";
3565 17 Jul 07 nicklas 2750 }
3565 17 Jul 07 nicklas 2751 </programlisting>
3565 17 Jul 07 nicklas 2752         </listitem>
3565 17 Jul 07 nicklas 2753       </varlistentry>
3565 17 Jul 07 nicklas 2754       </variablelist>
3565 17 Jul 07 nicklas 2755
3565 17 Jul 07 nicklas 2756       <para>
3944 09 Nov 07 martin 2757         The <classname docapi="net.sf.basedb.plugins">AbstractFlatFileImporter</classname> has a lot of
3565 17 Jul 07 nicklas 2758         other methods that you may use and/or override in your own plug-in.
3565 17 Jul 07 nicklas 2759         Check the javadoc for more information. 
3565 17 Jul 07 nicklas 2760       </para>
3565 17 Jul 07 nicklas 2761
5633 18 May 11 nicklas 2762       <sect3 id="plugin_developer.import.configurebyexample">
5633 18 May 11 nicklas 2763         <title>Configure by example</title>
5633 18 May 11 nicklas 2764         
5633 18 May 11 nicklas 2765         <para>
5633 18 May 11 nicklas 2766           The <interfacename docapi="net.sf.basedb.util.parser">ConfigureByExample</interfacename> 
5633 18 May 11 nicklas 2767           is a tagging interface that can be used by plug-ins using the
5633 18 May 11 nicklas 2768           <classname docapi="net.sf.basedb.util.parser">FlatFileParser</classname> class for parsing.
5633 18 May 11 nicklas 2769           The web client detects if a plug-in implements this interface and if the list of
5633 18 May 11 nicklas 2770           parameters includes a section parameter with the name <constant>parserSection</constant>
5633 18 May 11 nicklas 2771           a <guibutton>Test with file</guibutton> buttons is activated. This button will take the
5633 18 May 11 nicklas 2772           user to a form which allows the user to enter values for the parameters defined in
5633 18 May 11 nicklas 2773           the <classname>AbstractFlatFileImporter</classname> class. Parameters for column mappings
5633 18 May 11 nicklas 2774           must have the string "Mapping" in their names.
5633 18 May 11 nicklas 2775         </para>
5633 18 May 11 nicklas 2776       </sect3>
3178 12 Mar 07 enell 2777     </sect2>
5633 18 May 11 nicklas 2778     
3175 08 Mar 07 enell 2779   </sect1>
3175 08 Mar 07 enell 2780
3178 12 Mar 07 enell 2781   <sect1 id="plugin_developer.export">
5782 04 Oct 11 nicklas 2782     <?dbhtml filename="export.html" ?>
3366 23 May 07 nicklas 2783     <title>Export plug-ins</title>
3178 12 Mar 07 enell 2784     
3406 30 May 07 nicklas 2785     <para>
3406 30 May 07 nicklas 2786       Export plug-ins are plug-ins that takes data from BASE, and 
3406 30 May 07 nicklas 2787       prepares it for use with some external entity. Usually this
3406 30 May 07 nicklas 2788       means that data is taken from the database and put into a file
3406 30 May 07 nicklas 2789       with some well-defined file format.
3406 30 May 07 nicklas 2790       An export plug-in should return <constant>MainType.EXPORT</constant> from
3406 30 May 07 nicklas 2791       the <methodname>Plugin.getMainType()</methodname> method. 
3406 30 May 07 nicklas 2792     </para>
3406 30 May 07 nicklas 2793     
3178 12 Mar 07 enell 2794     <sect2 id="plugin_developer.export.download">
3178 12 Mar 07 enell 2795       <title>Immediate download of exported data</title>
3406 30 May 07 nicklas 2796       <para>
3406 30 May 07 nicklas 2797         An export plug-in may want to give the user a choice
3406 30 May 07 nicklas 2798         between saving the exported data in the BASE file system
3406 30 May 07 nicklas 2799         or to download it immediately to the client computer. With the basic 
3406 30 May 07 nicklas 2800         plug-in API the second option is not possible. The 
3944 09 Nov 07 martin 2801         <interfacename docapi="net.sf.basedb.core.plugin">ImmediateDownloadExporter</interfacename> is an
3944 09 Nov 07 martin 2802         interface that extends the <interfacename docapi="net.sf.basedb.core.plugin">Plugin</interfacename>
3406 30 May 07 nicklas 2803         interface to provide this functionality. If your export
3406 30 May 07 nicklas 2804         plug-in wants to provide immediate download functionality it must
3944 09 Nov 07 martin 2805         implement the <interfacename docapi="net.sf.basedb.core.plugin">ImmediateDownloadExporter</interfacename>
3406 30 May 07 nicklas 2806         interface.
3406 30 May 07 nicklas 2807       </para>
3406 30 May 07 nicklas 2808       
3406 30 May 07 nicklas 2809       <sect3 id="plugin_developer.export.immediatedownloadexporter">
3406 30 May 07 nicklas 2810       <title>The ImmediateDownloadExporter interface</title>
3406 30 May 07 nicklas 2811       <variablelist>
3406 30 May 07 nicklas 2812       <varlistentry>
3406 30 May 07 nicklas 2813         <term>
3406 30 May 07 nicklas 2814           <methodsynopsis language="java">
3406 30 May 07 nicklas 2815             <modifier>public</modifier>
3406 30 May 07 nicklas 2816             <void/>
3406 30 May 07 nicklas 2817             <methodname>doExport</methodname>
3406 30 May 07 nicklas 2818             <methodparam>
3406 30 May 07 nicklas 2819               <type>ExportOutputStream</type>
3406 30 May 07 nicklas 2820               <parameter>out</parameter>
3406 30 May 07 nicklas 2821             </methodparam>
3406 30 May 07 nicklas 2822             <methodparam>
3406 30 May 07 nicklas 2823               <type>ProgressReporter</type>
3406 30 May 07 nicklas 2824               <parameter>progress</parameter>
3406 30 May 07 nicklas 2825             </methodparam>
3406 30 May 07 nicklas 2826           </methodsynopsis>
3406 30 May 07 nicklas 2827         </term>
3406 30 May 07 nicklas 2828         <listitem>
3406 30 May 07 nicklas 2829           <para>
3406 30 May 07 nicklas 2830           Perform the export. The plug-in should write the
3406 30 May 07 nicklas 2831           exported data to the <varname>out</varname> stream.
3487 13 Jun 07 peter 2832           If the <varname>progress</varname> parameter is not null, 
3406 30 May 07 nicklas 2833           the progress should be reported at regular interval in the
3406 30 May 07 nicklas 2834           same manner as in the <methodname>Plugin.run()</methodname>
3406 30 May 07 nicklas 2835           method.
3406 30 May 07 nicklas 2836           </para>
3406 30 May 07 nicklas 2837         </listitem>
3406 30 May 07 nicklas 2838       </varlistentry>
3406 30 May 07 nicklas 2839       </variablelist>
3406 30 May 07 nicklas 2840       
3406 30 May 07 nicklas 2841       </sect3>
3406 30 May 07 nicklas 2842       
3406 30 May 07 nicklas 2843       <sect3 id="plugin_developer.export.exportoutputstream">
3406 30 May 07 nicklas 2844       <title>The ExportOutputStream class</title>
3406 30 May 07 nicklas 2845       
3406 30 May 07 nicklas 2846       <para>
4524 15 Sep 08 nicklas 2847         The <classname docapi="net.sf.basedb.core.plugin">ExportOutputStream</classname> is 
4524 15 Sep 08 nicklas 2848         an extension to the
3406 30 May 07 nicklas 2849         <classname>java.io.OutputStream</classname>. Use the regular 
3406 30 May 07 nicklas 2850         <methodname>write()</methodname> methods to write data to it.
4524 15 Sep 08 nicklas 2851         It also has some additional methods, which are used for setting 
4524 15 Sep 08 nicklas 2852         metadata about the generated file. These methods are useful, for
4524 15 Sep 08 nicklas 2853         example, when generating HTTP response headers.
3406 30 May 07 nicklas 2854       </para>
3406 30 May 07 nicklas 2855       
3406 30 May 07 nicklas 2856       <note>
3406 30 May 07 nicklas 2857         <para>
3406 30 May 07 nicklas 2858         These methods must be called before starting to write data to
3406 30 May 07 nicklas 2859         the <varname>out</varname> stream.
3406 30 May 07 nicklas 2860         </para>
3406 30 May 07 nicklas 2861       </note>
3406 30 May 07 nicklas 2862       
3406 30 May 07 nicklas 2863       <variablelist>
3406 30 May 07 nicklas 2864       <varlistentry>
3406 30 May 07 nicklas 2865         <term>
3406 30 May 07 nicklas 2866           <methodsynopsis language="java">
3406 30 May 07 nicklas 2867             <modifier>public</modifier>
3406 30 May 07 nicklas 2868             <void/>
3406 30 May 07 nicklas 2869             <methodname>setContentLength</methodname>
3406 30 May 07 nicklas 2870             <methodparam>
3406 30 May 07 nicklas 2871               <type>long</type>
3406 30 May 07 nicklas 2872               <parameter>contentLength</parameter>
3406 30 May 07 nicklas 2873             </methodparam>
3406 30 May 07 nicklas 2874           </methodsynopsis>
3406 30 May 07 nicklas 2875         </term>
3406 30 May 07 nicklas 2876         <listitem>
3406 30 May 07 nicklas 2877           <para>
3565 17 Jul 07 nicklas 2878           Set the total size of the exported data. Don't call this method if the
3565 17 Jul 07 nicklas 2879           total size is not known.
3406 30 May 07 nicklas 2880           </para>
3406 30 May 07 nicklas 2881         </listitem>
3406 30 May 07 nicklas 2882       </varlistentry>
3406 30 May 07 nicklas 2883       <varlistentry>
3406 30 May 07 nicklas 2884         <term>
3406 30 May 07 nicklas 2885           <methodsynopsis language="java">
3406 30 May 07 nicklas 2886             <modifier>public</modifier>
3406 30 May 07 nicklas 2887             <void/>
3406 30 May 07 nicklas 2888             <methodname>setMimeType</methodname>
3406 30 May 07 nicklas 2889             <methodparam>
3406 30 May 07 nicklas 2890               <type>String</type>
3406 30 May 07 nicklas 2891               <parameter>mimeType</parameter>
3406 30 May 07 nicklas 2892             </methodparam>
3406 30 May 07 nicklas 2893           </methodsynopsis>
3406 30 May 07 nicklas 2894         </term>
3406 30 May 07 nicklas 2895         <listitem>
3406 30 May 07 nicklas 2896           <para>
3605 26 Jul 07 peter 2897           Set the MIME type of the file that is being generated.
3406 30 May 07 nicklas 2898           </para>
3406 30 May 07 nicklas 2899         </listitem>
3406 30 May 07 nicklas 2900       </varlistentry>
3406 30 May 07 nicklas 2901       <varlistentry>
3406 30 May 07 nicklas 2902         <term>
3406 30 May 07 nicklas 2903           <methodsynopsis language="java">
3406 30 May 07 nicklas 2904             <modifier>public</modifier>
3406 30 May 07 nicklas 2905             <void/>
4524 15 Sep 08 nicklas 2906             <methodname>setCharacterSet</methodname>
4524 15 Sep 08 nicklas 2907             <methodparam>
4524 15 Sep 08 nicklas 2908               <type>String</type>
4524 15 Sep 08 nicklas 2909               <parameter>charset</parameter>
4524 15 Sep 08 nicklas 2910             </methodparam>
4524 15 Sep 08 nicklas 2911           </methodsynopsis>
4524 15 Sep 08 nicklas 2912         </term>
4524 15 Sep 08 nicklas 2913         <listitem>
4524 15 Sep 08 nicklas 2914           <para>
4524 15 Sep 08 nicklas 2915           Sets the character set used in text files. For example,
4524 15 Sep 08 nicklas 2916           UTF-8 or ISO-8859-1.
4524 15 Sep 08 nicklas 2917           </para>
4524 15 Sep 08 nicklas 2918         </listitem>
4524 15 Sep 08 nicklas 2919       </varlistentry>
4524 15 Sep 08 nicklas 2920       <varlistentry>
4524 15 Sep 08 nicklas 2921         <term>
4524 15 Sep 08 nicklas 2922           <methodsynopsis language="java">
4524 15 Sep 08 nicklas 2923             <modifier>public</modifier>
4524 15 Sep 08 nicklas 2924             <void/>
3406 30 May 07 nicklas 2925             <methodname>setFilename</methodname>
3406 30 May 07 nicklas 2926             <methodparam>
3406 30 May 07 nicklas 2927               <type>String</type>
3406 30 May 07 nicklas 2928               <parameter>filename</parameter>
3406 30 May 07 nicklas 2929             </methodparam>
3406 30 May 07 nicklas 2930           </methodsynopsis>
3406 30 May 07 nicklas 2931         </term>
3406 30 May 07 nicklas 2932         <listitem>
3406 30 May 07 nicklas 2933           <para>
3605 26 Jul 07 peter 2934           Set a suggested name of the file that is being
3406 30 May 07 nicklas 2935           generated.
3406 30 May 07 nicklas 2936           </para>
3406 30 May 07 nicklas 2937         </listitem>
3406 30 May 07 nicklas 2938       </varlistentry>
3406 30 May 07 nicklas 2939       </variablelist>
3406 30 May 07 nicklas 2940       
3406 30 May 07 nicklas 2941       </sect3>
3406 30 May 07 nicklas 2942       
3406 30 May 07 nicklas 2943       <sect3 id="plugin_developer.export.callsequence">
3406 30 May 07 nicklas 2944         <title>Call sequence during immediate download</title>
3406 30 May 07 nicklas 2945
3406 30 May 07 nicklas 2946       <para>
3406 30 May 07 nicklas 2947         Supporting immediate download also means that the method call
3406 30 May 07 nicklas 2948         sequence is a bit altered from the standard sequence described
3406 30 May 07 nicklas 2949         in <xref linkend="plugin_developer.api.callsequence.execute" />.
3406 30 May 07 nicklas 2950       </para>
3406 30 May 07 nicklas 2951       
3406 30 May 07 nicklas 2952       <itemizedlist>
3406 30 May 07 nicklas 2953       <listitem>
3406 30 May 07 nicklas 2954         <para>
3406 30 May 07 nicklas 2955         The plug-in must call <methodname>Response.setDownloadImmediately()</methodname>
3406 30 May 07 nicklas 2956         instead of <methodname>Response.setDone()</methodname> in <methodname>Plugin.configure()</methodname>
3565 17 Jul 07 nicklas 2957         to end the job configuration wizard. This requests that the core starts 
3406 30 May 07 nicklas 2958         an immediate download.
3406 30 May 07 nicklas 2959         </para>
3406 30 May 07 nicklas 2960         
3406 30 May 07 nicklas 2961         <note>
3406 30 May 07 nicklas 2962           <para>
3406 30 May 07 nicklas 2963           Even if an immediate download is requested by the plug-in this feature
3406 30 May 07 nicklas 2964           may have been disabled by the server administrator. If so, the plug-in
3406 30 May 07 nicklas 2965           can choose if the job should be added to job queue or if this is an
3406 30 May 07 nicklas 2966           error condition.
3406 30 May 07 nicklas 2967           </para>
3406 30 May 07 nicklas 2968         </note>
3406 30 May 07 nicklas 2969       </listitem>
3406 30 May 07 nicklas 2970       
3406 30 May 07 nicklas 2971       <listitem>
3406 30 May 07 nicklas 2972         <para>
3406 30 May 07 nicklas 2973         If immediate download is granted the web client will keep the
3406 30 May 07 nicklas 2974         same plug-in instance and call <methodname>ImmediateDownloadExporter.doExport()</methodname>.
3406 30 May 07 nicklas 2975         In this case, the <methodname>Plugin.run()</methodname> is never called.
3501 15 Jun 07 enell 2976         After the export, <methodname>Plugin.done()</methodname> is called as
3501 15 Jun 07 enell 2977         usual.
3406 30 May 07 nicklas 2978         </para>
3406 30 May 07 nicklas 2979         
3406 30 May 07 nicklas 2980       </listitem>
3406 30 May 07 nicklas 2981
3406 30 May 07 nicklas 2982       <listitem>
3406 30 May 07 nicklas 2983         <para>
3487 13 Jun 07 peter 2984         If immediate download is not granted and the job is added to the job queue
3565 17 Jul 07 nicklas 2985         the regular job execution sequence is used.
3406 30 May 07 nicklas 2986         </para>
3406 30 May 07 nicklas 2987       </listitem>
3406 30 May 07 nicklas 2988       </itemizedlist>
3406 30 May 07 nicklas 2989       
3406 30 May 07 nicklas 2990       </sect3>
3406 30 May 07 nicklas 2991
3178 12 Mar 07 enell 2992     </sect2>
3406 30 May 07 nicklas 2993     
3406 30 May 07 nicklas 2994     <sect2 id="plugin_developer.export.abstractexporter">
3406 30 May 07 nicklas 2995       <title>The AbstractExporterPlugin class</title>
3406 30 May 07 nicklas 2996     
3406 30 May 07 nicklas 2997       <para>
3406 30 May 07 nicklas 2998         This is an abstract superclass that will make it easier
3406 30 May 07 nicklas 2999         to implement export plug-ins that support immediate 
3944 09 Nov 07 martin 3000         download. It defines <classname docapi="net.sf.basedb.core">PluginParameter</classname>
3406 30 May 07 nicklas 3001         objects for asking a user about a path where the exported
3406 30 May 07 nicklas 3002         data should be saved and if existing files should be overwritten or not.
3406 30 May 07 nicklas 3003         If the user leaves the path empty the immediate download functionality
3406 30 May 07 nicklas 3004         should be used. It also contains implementations of both the 
3406 30 May 07 nicklas 3005         <methodname>Plugin.run()</methodname> method and the
3406 30 May 07 nicklas 3006         <methodname>ImmediateDownloadExporter.doExport()</methodname> method.
3406 30 May 07 nicklas 3007         Here is what you need to do in your own plug-in code (code examples are
3944 09 Nov 07 martin 3008         taken from the <classname docapi="net.sf.basedb.plugins">HelpExporter</classname>):
3406 30 May 07 nicklas 3009       </para>
3406 30 May 07 nicklas 3010       
3406 30 May 07 nicklas 3011       <itemizedlist>
3406 30 May 07 nicklas 3012       <listitem>
3406 30 May 07 nicklas 3013         <para>
3944 09 Nov 07 martin 3014           Your plug-in should extend the <classname docapi="net.sf.basedb.core.plugin">AbstractExporterPlugin</classname>
3406 30 May 07 nicklas 3015           class:
3838 16 Oct 07 nicklas 3016           <programlisting language="java">
3406 30 May 07 nicklas 3017 public class HelpExporter
3406 30 May 07 nicklas 3018   extends AbstractExporterPlugin
3406 30 May 07 nicklas 3019   implements InteractivePlugin
3406 30 May 07 nicklas 3020 </programlisting>
3406 30 May 07 nicklas 3021         </para>
3406 30 May 07 nicklas 3022       </listitem>
3406 30 May 07 nicklas 3023       
3406 30 May 07 nicklas 3024       <listitem>
3406 30 May 07 nicklas 3025         <para>
3406 30 May 07 nicklas 3026           You need to implement the 
3406 30 May 07 nicklas 3027           <methodname>InteractivePlugin.getRequestInformation()</methodname>
3406 30 May 07 nicklas 3028           method. Use the <methodname>getSaveAsParameter()</methodname>
3406 30 May 07 nicklas 3029           and <methodname>getOverwriteParameter()</methodname> methods defined in the 
3406 30 May 07 nicklas 3030           superclass to create plug-in parameters that asks for the file name to save
3406 30 May 07 nicklas 3031           to and if existing files can be overwritten or not.
3406 30 May 07 nicklas 3032           You should also check if the administrator has enabled the immediate execution
3406 30 May 07 nicklas 3033           functionality for your plug-in. If not, the only option is to 
3406 30 May 07 nicklas 3034           export to a file in the BASE file system and the filename is a
3406 30 May 07 nicklas 3035           required parameter.
3406 30 May 07 nicklas 3036           
3838 16 Oct 07 nicklas 3037           <programlisting language="java">
3406 30 May 07 nicklas 3038 // Selected parts of the getRequestConfiguration() method
3406 30 May 07 nicklas 3039 ...
3406 30 May 07 nicklas 3040 List&lt;PluginParameter&lt;?&gt;&gt; parameters = 
3406 30 May 07 nicklas 3041    new ArrayList&lt;PluginParameter&lt;?&gt;&gt;();
3406 30 May 07 nicklas 3042 ...
3406 30 May 07 nicklas 3043 PluginDefinition pd = job.getPluginDefinition();
3406 30 May 07 nicklas 3044 boolean requireFile = pd == null ? 
3406 30 May 07 nicklas 3045    false : !pd.getAllowImmediateExecution();
3406 30 May 07 nicklas 3046
3406 30 May 07 nicklas 3047 parameters.add(getSaveAsParameter(null, null, defaultPath, requireFile));
3406 30 May 07 nicklas 3048 parameters.add(getOverwriteParameter(null, null));
3406 30 May 07 nicklas 3049
3406 30 May 07 nicklas 3050 configureJob = new RequestInformation
3406 30 May 07 nicklas 3051 (
3406 30 May 07 nicklas 3052    Request.COMMAND_CONFIGURE_JOB,
3406 30 May 07 nicklas 3053    "Help exporter options",
3406 30 May 07 nicklas 3054    "Set Client that owns the helptexts, " +
3406 30 May 07 nicklas 3055      "the file path where the export file should be saved",
3406 30 May 07 nicklas 3056    parameters
3406 30 May 07 nicklas 3057 );
3406 30 May 07 nicklas 3058 ....
3406 30 May 07 nicklas 3059 return configureJob;
3406 30 May 07 nicklas 3060 </programlisting>
3406 30 May 07 nicklas 3061         </para>
3406 30 May 07 nicklas 3062       </listitem>
3406 30 May 07 nicklas 3063
3406 30 May 07 nicklas 3064       <listitem>
3406 30 May 07 nicklas 3065         <para>
3406 30 May 07 nicklas 3066         You must also implement the <methodname>configure()</methodname>
3406 30 May 07 nicklas 3067         method and check the parameters. If no filename has been given,
3406 30 May 07 nicklas 3068         you should check if immediate exection is allowed and set an
3487 13 Jun 07 peter 3069         error if it is not. If a filename is present, use the 
3406 30 May 07 nicklas 3070         <methodname>pathCanBeUsed()</methodname> method to check if 
3406 30 May 07 nicklas 3071         it is possible to save the data to a file with that name. If the
3406 30 May 07 nicklas 3072         file already exists it can be overwritten if the <varname>OVERWRITE</varname>
3406 30 May 07 nicklas 3073         is <constant>TRUE</constant> or if the file has been flagged for removal.
3487 13 Jun 07 peter 3074         Do not forget to store the parameters with the <methodname>storeValue()</methodname>
3406 30 May 07 nicklas 3075         method.
3406 30 May 07 nicklas 3076
3838 16 Oct 07 nicklas 3077         <programlisting language="java">
3406 30 May 07 nicklas 3078 // Selected parts from the configure() method
3406 30 May 07 nicklas 3079 if (request.getParameterValue(SAVE_AS) == null)
3406 30 May 07 nicklas 3080 {
3406 30 May 07 nicklas 3081    if (!request.isAllowedImmediateExecution())
3406 30 May 07 nicklas 3082    {
3406 30 May 07 nicklas 3083       response.setError("Immediate download is not allowed. " + 
3406 30 May 07 nicklas 3084          "Please specify a filename.", null);
3406 30 May 07 nicklas 3085       return;
3406 30 May 07 nicklas 3086    }
3406 30 May 07 nicklas 3087    Client client = (Client)request.getParameterValue("client");
3406 30 May 07 nicklas 3088    response.setDownloadImmediately("Export help texts for client application " + 
3406 30 May 07 nicklas 3089      client.getName(), ExecutionTime.SHORTEST, true);
3406 30 May 07 nicklas 3090 }
3406 30 May 07 nicklas 3091 else
3406 30 May 07 nicklas 3092 {
3406 30 May 07 nicklas 3093    if (!pathCanBeUsed((String)request.getParameterValue(SAVE_AS), 
3406 30 May 07 nicklas 3094       (Boolean)request.getParameterValue(OVERWRITE)))
3406 30 May 07 nicklas 3095    {
3406 30 May 07 nicklas 3096       response.setError("File exists: " + 
3406 30 May 07 nicklas 3097          (String)request.getParameterValue(SAVE_AS), null);
3406 30 May 07 nicklas 3098       return;
3406 30 May 07 nicklas 3099    }
3406 30 May 07 nicklas 3100    storeValue(job, request, ri.getParameter(SAVE_AS));
3406 30 May 07 nicklas 3101    storeValue(job, request, ri.getParameter(OVERWRITE));
3406 30 May 07 nicklas 3102    response.setDone("The job configuration is complete", ExecutionTime.SHORTEST);
3406 30 May 07 nicklas 3103 }
3406 30 May 07 nicklas 3104 </programlisting>
3406 30 May 07 nicklas 3105         
3406 30 May 07 nicklas 3106         </para>
3406 30 May 07 nicklas 3107       </listitem>
3406 30 May 07 nicklas 3108       
3406 30 May 07 nicklas 3109       <listitem>
3406 30 May 07 nicklas 3110         <para>
3406 30 May 07 nicklas 3111         Implement the <methodname>performExport()</methodname> method.
3944 09 Nov 07 martin 3112         This is defined as abstract in the <classname docapi="net.sf.basedb.core.plugin">AbstractExporterPlugin</classname>
3406 30 May 07 nicklas 3113         class. It has the same parameters as the <methodname>ImmediateDownloadExporter.doExport()</methodname>
3406 30 May 07 nicklas 3114         method and they have the same meaning. The only difference is that the 
3565 17 Jul 07 nicklas 3115         <varname>out</varname> stream can be linked to a file in the BASE filesystem
3565 17 Jul 07 nicklas 3116         and not just to the HTTP response stream.
3406 30 May 07 nicklas 3117         </para>
3406 30 May 07 nicklas 3118       </listitem>
3406 30 May 07 nicklas 3119       
3406 30 May 07 nicklas 3120       <listitem>
3406 30 May 07 nicklas 3121         <para>
3406 30 May 07 nicklas 3122         Optionally, implement the <methodname>begin()</methodname>,
3406 30 May 07 nicklas 3123         <methodname>end()</methodname> and <methodname>getSuccessMessage()</methodname>
3406 30 May 07 nicklas 3124         methods. Theese methods do nothing by default. 
3406 30 May 07 nicklas 3125         </para>
3406 30 May 07 nicklas 3126       </listitem>
3406 30 May 07 nicklas 3127       </itemizedlist>
3406 30 May 07 nicklas 3128       
3406 30 May 07 nicklas 3129       <para>
3944 09 Nov 07 martin 3130         The call sequence for plug-ins extending <classname docapi="net.sf.basedb.core.plugin">AbstractExporterPlugin</classname>
3406 30 May 07 nicklas 3131         is:
3406 30 May 07 nicklas 3132       </para>
3406 30 May 07 nicklas 3133       
3406 30 May 07 nicklas 3134       <orderedlist>
3406 30 May 07 nicklas 3135       <listitem>
3406 30 May 07 nicklas 3136         <para>
3406 30 May 07 nicklas 3137         Call <methodname>begin()</methodname>.
3406 30 May 07 nicklas 3138         </para>
3406 30 May 07 nicklas 3139       </listitem>
3406 30 May 07 nicklas 3140       <listitem>
3406 30 May 07 nicklas 3141         <para>
3406 30 May 07 nicklas 3142         Call <methodname>performExport()</methodname>.
3406 30 May 07 nicklas 3143         </para>
3406 30 May 07 nicklas 3144       </listitem>
3406 30 May 07 nicklas 3145       <listitem>
3406 30 May 07 nicklas 3146         <para>
3406 30 May 07 nicklas 3147         Call <methodname>end()</methodname>.
3406 30 May 07 nicklas 3148         </para>
3406 30 May 07 nicklas 3149       </listitem>
3406 30 May 07 nicklas 3150       <listitem>
3406 30 May 07 nicklas 3151         <para>
3406 30 May 07 nicklas 3152         Call <methodname>getSuccessMessage()</methodname> if running as a regular
3406 30 May 07 nicklas 3153         job. This method is never called when doing an immediate download since there
3406 30 May 07 nicklas 3154         is no place to show the message.
3406 30 May 07 nicklas 3155         </para>
3406 30 May 07 nicklas 3156       </listitem>
3406 30 May 07 nicklas 3157       </orderedlist>
3406 30 May 07 nicklas 3158       
3406 30 May 07 nicklas 3159     </sect2>
3406 30 May 07 nicklas 3160     
3178 12 Mar 07 enell 3161   </sect1>
3178 12 Mar 07 enell 3162   
3178 12 Mar 07 enell 3163   <sect1 id="plugin_developer.analyse">
5782 04 Oct 11 nicklas 3164     <?dbhtml filename="analysis.html" ?>
3366 23 May 07 nicklas 3165     <title>Analysis plug-ins</title>
3182 12 Mar 07 enell 3166     <para>
3366 23 May 07 nicklas 3167       A plug-in becomes an analysis plug-in simply by returning
4680 02 Dec 08 jari 3168       <constant>Plugin.MainType.ANALYZE</constant> from the
3182 12 Mar 07 enell 3169       <methodname>Plugin.getMainType()</methodname> method. The information returned from
3182 12 Mar 07 enell 3170       <methodname>InteractivePlugin.getGuiContexts()</methodname>
5633 18 May 11 nicklas 3171       should include: [<constant>Item.BIOASSAYSET</constant>, <constant>Type.ITEM</constant>] 
5633 18 May 11 nicklas 3172       or [<constant>Item.DERIVEDBIOASSAYSET</constant>, <constant>Type.ITEM</constant>]
5633 18 May 11 nicklas 3173       since web client doesn't look for analysis plug-ins in most other places. If
3570 19 Jul 07 nicklas 3174       the plug-in can work on a subset of the bioassays it may also include
3570 19 Jul 07 nicklas 3175       [<constant>Item.BIOASSAY</constant>, <constant>Type.LIST</constant>]
3570 19 Jul 07 nicklas 3176       among the contexts. This will make it possible for a user to select
5633 18 May 11 nicklas 3177       bioassays from the list and then invoke the plug-in. The following
5633 18 May 11 nicklas 3178       code examples are taken from an analysis plug-in that is used in an experiment
5633 18 May 11 nicklas 3179       context.
3182 12 Mar 07 enell 3180     </para>
3182 12 Mar 07 enell 3181     
3838 16 Oct 07 nicklas 3182 <programlisting language="java">
3570 19 Jul 07 nicklas 3183 private static final Set&lt;GuiContext&gt; guiContexts = 
3182 12 Mar 07 enell 3184    Collections.singleton(new GuiContext(Item.BIOASSAYSET, GuiContext.Type.ITEM));
3182 12 Mar 07 enell 3185
3182 12 Mar 07 enell 3186 public Set&lt;GuiContext&gt; getGuiContexts()
3182 12 Mar 07 enell 3187 {
3182 12 Mar 07 enell 3188    return guiContexts;
3371 24 May 07 martin 3189 }</programlisting>
3315 09 May 07 nicklas 3190
3570 19 Jul 07 nicklas 3191     <para>
5633 18 May 11 nicklas 3192     If the plug-in depends on a specific raw data type or on the number of
3570 19 Jul 07 nicklas 3193     channels, it should check that the current bioassayset is of the
3570 19 Jul 07 nicklas 3194     correct type in the <methodname>InteractivePlugin.isInContext()</methodname> 
3570 19 Jul 07 nicklas 3195     method. It is also a good idea to check if the current user has permission
3570 19 Jul 07 nicklas 3196     to use the current experiment. This permission is needed to create new bioassaysets or
3570 19 Jul 07 nicklas 3197     other data belonging to the experiment.
3570 19 Jul 07 nicklas 3198     </para>
3570 19 Jul 07 nicklas 3199   
3838 16 Oct 07 nicklas 3200     <programlisting language="java">
3570 19 Jul 07 nicklas 3201 public boolean isInContext(GuiContext context, Object item)
3570 19 Jul 07 nicklas 3202 {
3570 19 Jul 07 nicklas 3203    if (item == null)
3570 19 Jul 07 nicklas 3204    {
3570 19 Jul 07 nicklas 3205       message = "The object is null";
3570 19 Jul 07 nicklas 3206    }
3570 19 Jul 07 nicklas 3207    else if (!(item instanceof BioAssaySet))
3570 19 Jul 07 nicklas 3208    {
3570 19 Jul 07 nicklas 3209       message = "The object is not a BioAssaySet: " + item;
3570 19 Jul 07 nicklas 3210    }
3570 19 Jul 07 nicklas 3211    else
3570 19 Jul 07 nicklas 3212    {
3570 19 Jul 07 nicklas 3213       BioAssaySet bas = (BioAssaySet)item;
3570 19 Jul 07 nicklas 3214       int channels = bas.getRawDataType().getChannels();
3570 19 Jul 07 nicklas 3215       if (channels != 2)
3570 19 Jul 07 nicklas 3216       {
3570 19 Jul 07 nicklas 3217          message = "This plug-in requires 2-channel data, not " + channels + "-channel.";
3570 19 Jul 07 nicklas 3218       }
3570 19 Jul 07 nicklas 3219       else
3570 19 Jul 07 nicklas 3220       {
3570 19 Jul 07 nicklas 3221          Experiment e = bas.getExperiment();
3570 19 Jul 07 nicklas 3222          e.checkPermission(Permission.USE);
3570 19 Jul 07 nicklas 3223       }
3570 19 Jul 07 nicklas 3224    }
3570 19 Jul 07 nicklas 3225 }
3570 19 Jul 07 nicklas 3226 </programlisting>
3570 19 Jul 07 nicklas 3227
3570 19 Jul 07 nicklas 3228     <para>
5633 18 May 11 nicklas 3229     The plug-in should always include a parameter asking for the current 
3570 19 Jul 07 nicklas 3230     bioassay set when the <methodname>InteractivePlugin.getRequestInformation()</methodname>
3570 19 Jul 07 nicklas 3231     is called with <literal>command = Request.COMMAND_CONFIGURE_JOB</literal>.
3570 19 Jul 07 nicklas 3232     </para>  
3570 19 Jul 07 nicklas 3233
3838 16 Oct 07 nicklas 3234     <programlisting language="java">
3570 19 Jul 07 nicklas 3235 private static final RequestInformation configurePlugin;
3570 19 Jul 07 nicklas 3236 private RequestInformation configureJob;
3570 19 Jul 07 nicklas 3237 private PluginParameter&lt;BioAssaySet&gt; bioAssaySetParameter;
3570 19 Jul 07 nicklas 3238
3570 19 Jul 07 nicklas 3239 public RequestInformation getRequestInformation(GuiContext context, String command) 
3570 19 Jul 07 nicklas 3240    throws BaseException
3570 19 Jul 07 nicklas 3241 {
3570 19 Jul 07 nicklas 3242    RequestInformation requestInformation = null;
3570 19 Jul 07 nicklas 3243    if (command.equals(Request.COMMAND_CONFIGURE_PLUGIN))
3570 19 Jul 07 nicklas 3244    {
3570 19 Jul 07 nicklas 3245       requestInformation = getConfigurePlugin(context);
3570 19 Jul 07 nicklas 3246    }
3570 19 Jul 07 nicklas 3247    else if (command.equals(Request.COMMAND_CONFIGURE_JOB))
3570 19 Jul 07 nicklas 3248    {
3570 19 Jul 07 nicklas 3249       requestInformation = getConfigureJob(context);
3570 19 Jul 07 nicklas 3250    }
3570 19 Jul 07 nicklas 3251    return requestInformation;
3570 19 Jul 07 nicklas 3252 }
3570 19 Jul 07 nicklas 3253
3570 19 Jul 07 nicklas 3254 private RequestInformation getConfigureJob(GuiContext context)
3570 19 Jul 07 nicklas 3255 {
3570 19 Jul 07 nicklas 3256    if (configureJob == null)
3570 19 Jul 07 nicklas 3257    {
3570 19 Jul 07 nicklas 3258       bioAssaySetParameter; = new PluginParameter&lt;BioAssaySet&gt;(
3570 19 Jul 07 nicklas 3259          "bioAssaySet",
3570 19 Jul 07 nicklas 3260          "Bioassay set",
3570 19 Jul 07 nicklas 3261          "The bioassay set used as the source for this analysis plugin",
3570 19 Jul 07 nicklas 3262          new ItemParameterType&lt;BioAssaySet&gt;(BioAssaySet.class, null, true, 1, null)
3570 19 Jul 07 nicklas 3263       );
3570 19 Jul 07 nicklas 3264
3570 19 Jul 07 nicklas 3265       List&lt;PluginParameter&lt;?&gt;&gt; parameters = new ArrayList&lt;PluginParameter&lt;?&gt;&gt;();
3570 19 Jul 07 nicklas 3266       parameters.add(bioAssaySetParameter);
3570 19 Jul 07 nicklas 3267       // Add more plug-in-specific parameters here...
3570 19 Jul 07 nicklas 3268     
3570 19 Jul 07 nicklas 3269       configureJob = new RequestInformation(
3570 19 Jul 07 nicklas 3270          Request.COMMAND_CONFIGURE_JOB,
3570 19 Jul 07 nicklas 3271          "Configure job",
3570 19 Jul 07 nicklas 3272          "Set parameter for plug-in execution",
3570 19 Jul 07 nicklas 3273          parameters
3570 19 Jul 07 nicklas 3274       );
3570 19 Jul 07 nicklas 3275    }
3570 19 Jul 07 nicklas 3276    return configureJob;
3570 19 Jul 07 nicklas 3277 }
3570 19 Jul 07 nicklas 3278 </programlisting>
3570 19 Jul 07 nicklas 3279
3570 19 Jul 07 nicklas 3280     <para>
3570 19 Jul 07 nicklas 3281     Of course, the <methodname>InteractivePlugin.configure()</methodname> method needs 
3570 19 Jul 07 nicklas 3282     to validate and store the bioassay set parameter as well:
3570 19 Jul 07 nicklas 3283     </para>
3570 19 Jul 07 nicklas 3284   
3838 16 Oct 07 nicklas 3285     <programlisting language="java">
3570 19 Jul 07 nicklas 3286 public void configure(GuiContext context, Request request, Response response)
3570 19 Jul 07 nicklas 3287 {
3570 19 Jul 07 nicklas 3288    String command = request.getCommand();
3570 19 Jul 07 nicklas 3289    try
3570 19 Jul 07 nicklas 3290    {
3570 19 Jul 07 nicklas 3291       if (command.equals(Request.COMMAND_CONFIGURE_PLUGIN))
3570 19 Jul 07 nicklas 3292       {
3570 19 Jul 07 nicklas 3293          // Validate and store configuration parameters
3570 19 Jul 07 nicklas 3294          response.setDone("Plugin configuration complete");
3570 19 Jul 07 nicklas 3295       }
3570 19 Jul 07 nicklas 3296       else if (command.equals(Request.COMMAND_CONFIGURE_JOB))
3570 19 Jul 07 nicklas 3297       {
3570 19 Jul 07 nicklas 3298          List&lt;Throwable&gt; errors = 
3570 19 Jul 07 nicklas 3299             validateRequestParameters(configureJob.getParameters(), request);
3570 19 Jul 07 nicklas 3300          if (errors != null)
3570 19 Jul 07 nicklas 3301          {
3570 19 Jul 07 nicklas 3302             response.setError(errors.size() +
3570 19 Jul 07 nicklas 3303                " invalid parameter(s) were found in the request", errors);
3570 19 Jul 07 nicklas 3304             return;
3570 19 Jul 07 nicklas 3305          }
3570 19 Jul 07 nicklas 3306          storeValue(job, request, bioAssaySetParameter);
3570 19 Jul 07 nicklas 3307          // Store other plugin-specific parameters
3570 19 Jul 07 nicklas 3308       
3570 19 Jul 07 nicklas 3309          response.setDone("Job configuration complete", Job.ExecutionTime.SHORT);
3570 19 Jul 07 nicklas 3310       }
3570 19 Jul 07 nicklas 3311    }
3570 19 Jul 07 nicklas 3312    catch (Throwable ex)
3570 19 Jul 07 nicklas 3313    {
3570 19 Jul 07 nicklas 3314       // Never throw exception, always set response!
3570 19 Jul 07 nicklas 3315       response.setError(ex.getMessage(), Arrays.asList(ex));
3570 19 Jul 07 nicklas 3316    }
3570 19 Jul 07 nicklas 3317 }
3570 19 Jul 07 nicklas 3318 </programlisting>
3570 19 Jul 07 nicklas 3319
3570 19 Jul 07 nicklas 3320     <para>
3570 19 Jul 07 nicklas 3321     Now, the typical <methodname>Plugin.run()</methodname> method loads the specfied bioassay set
3609 27 Jul 07 peter 3322     and its spot data. It may do some filtering and recalculation of the spot
3570 19 Jul 07 nicklas 3323     intensity value(s). In most cases it will store the result as a child bioassay
3570 19 Jul 07 nicklas 3324     set with one bioassay for each bioassay in the parent bioassay set.
3570 19 Jul 07 nicklas 3325     Here is an example, which just copies the intensity values, while
3570 19 Jul 07 nicklas 3326     removing those with a negative value in either channel.
3570 19 Jul 07 nicklas 3327     </para>
3570 19 Jul 07 nicklas 3328   
3838 16 Oct 07 nicklas 3329     <programlisting language="java">
3570 19 Jul 07 nicklas 3330 public void run(Request request, Response response, ProgressReporter progress)
3570 19 Jul 07 nicklas 3331 {
3570 19 Jul 07 nicklas 3332    DbControl dc = sc.newDbControl();
3570 19 Jul 07 nicklas 3333    try
3570 19 Jul 07 nicklas 3334    {
3570 19 Jul 07 nicklas 3335       BioAssaySet source = (BioAssaySet)job.getParameter("bioAssaySet");
3570 19 Jul 07 nicklas 3336       // Reload with current DbControl
3570 19 Jul 07 nicklas 3337       source = BioAssaySet.getById(dc, source.getId());
3570 19 Jul 07 nicklas 3338       int channels = source.getRawDataType().getChannels();
3570 19 Jul 07 nicklas 3339       
3570 19 Jul 07 nicklas 3340       // Create transformation and new bioassay set
3570 19 Jul 07 nicklas 3341       Job j = Job.getById(dc, job.getId());
3570 19 Jul 07 nicklas 3342       Transformation t = source.newTransformation(j);
3570 19 Jul 07 nicklas 3343       t.setName("Copy spot intensities &gt;= 0");
3570 19 Jul 07 nicklas 3344       dc.saveItem(t);
3570 19 Jul 07 nicklas 3345
3570 19 Jul 07 nicklas 3346       BioAssaySet result = t.newProduct(null, "new", true);
3570 19 Jul 07 nicklas 3347       result.setName("After: Copying spot intensities");
3570 19 Jul 07 nicklas 3348       dc.saveItem(result);
3570 19 Jul 07 nicklas 3349
3570 19 Jul 07 nicklas 3350       // Get query for source data
3570 19 Jul 07 nicklas 3351       DynamicSpotQuery query = source.getSpotData();
3570 19 Jul 07 nicklas 3352       
3570 19 Jul 07 nicklas 3353       // Do not return spots with intensities &lt; 0
3570 19 Jul 07 nicklas 3354       for (int ch = 1; ch &lt;= channels; ++ch)
3570 19 Jul 07 nicklas 3355       {
3570 19 Jul 07 nicklas 3356          query.restrict(
3570 19 Jul 07 nicklas 3357             Restrictions.gteq(
3570 19 Jul 07 nicklas 3358                Dynamic.column(VirtualColumn.channel(ch)),
3570 19 Jul 07 nicklas 3359                Expressions.integer(0)
3570 19 Jul 07 nicklas 3360             )
3570 19 Jul 07 nicklas 3361          );
3570 19 Jul 07 nicklas 3362       }
3570 19 Jul 07 nicklas 3363       
3570 19 Jul 07 nicklas 3364       // Create batcher and copy data
3570 19 Jul 07 nicklas 3365       SpotBatcher batcher = result.getSpotBatcher();
3570 19 Jul 07 nicklas 3366       int spotsCopied = batcher.insert(query);
3570 19 Jul 07 nicklas 3367       batcher.close();
3570 19 Jul 07 nicklas 3368       
3570 19 Jul 07 nicklas 3369       // Commit and return
3570 19 Jul 07 nicklas 3370       dc.commit();
3570 19 Jul 07 nicklas 3371       response.setDone("Copied " + spotsCopied + " spots.");
3570 19 Jul 07 nicklas 3372    }
3570 19 Jul 07 nicklas 3373    catch (Throwable t)
3570 19 Jul 07 nicklas 3374    {
3570 19 Jul 07 nicklas 3375       response.setError(t.getMessage(), Arrays.asList(t));
3570 19 Jul 07 nicklas 3376    }
3570 19 Jul 07 nicklas 3377    finally
3570 19 Jul 07 nicklas 3378    {
3570 19 Jul 07 nicklas 3379       if (dc != null) dc.close();
3570 19 Jul 07 nicklas 3380    }
3570 19 Jul 07 nicklas 3381 }
3570 19 Jul 07 nicklas 3382 </programlisting>
3570 19 Jul 07 nicklas 3383
3570 19 Jul 07 nicklas 3384     <para>
5781 04 Oct 11 nicklas 3385     See <xref linkend="core_api.dynamic" />
3570 19 Jul 07 nicklas 3386     for more examples of using the analysis API.
3570 19 Jul 07 nicklas 3387     </para>
3570 19 Jul 07 nicklas 3388
3570 19 Jul 07 nicklas 3389     <sect2 id="plugin_developer.analyse.abstractanalysis">
3570 19 Jul 07 nicklas 3390       <title>The AbstractAnalysisPlugin class</title>
3570 19 Jul 07 nicklas 3391       
3315 09 May 07 nicklas 3392       <para>
3570 19 Jul 07 nicklas 3393         This class is an abstract base class. It is a useful
5633 18 May 11 nicklas 3394         class for most analysis plug-ins used in an experiment context 
5633 18 May 11 nicklas 3395         to inherit from. Its main 
3944 09 Nov 07 martin 3396         purpose is to define <classname docapi="net.sf.basedb.core">PluginParameter</classname>
3570 19 Jul 07 nicklas 3397         objects that are commonly used in analysis plug-ins. This includes:
3315 09 May 07 nicklas 3398       </para>
3570 19 Jul 07 nicklas 3399       
3570 19 Jul 07 nicklas 3400       <itemizedlist>
3570 19 Jul 07 nicklas 3401       <listitem>
3570 19 Jul 07 nicklas 3402         <para>
3570 19 Jul 07 nicklas 3403         The source bioassay set: 
3570 19 Jul 07 nicklas 3404           <methodname>getSourceBioAssaySetParameter()</methodname>,
3570 19 Jul 07 nicklas 3405           <methodname>getCurrentBioAssaySet()</methodname>,
3570 19 Jul 07 nicklas 3406           <methodname>getSourceBioAssaySet()</methodname>
3570 19 Jul 07 nicklas 3407         </para>
3570 19 Jul 07 nicklas 3408       </listitem>
3570 19 Jul 07 nicklas 3409       <listitem>
3570 19 Jul 07 nicklas 3410         <para>
3585 20 Jul 07 martin 3411         The optional restriction of which bioassays to use. 
3585 20 Jul 07 martin 3412         All bioassays in a bioassay set will be used if this 
3585 20 Jul 07 martin 3413         parameter is empty. This is useful when the plugin only 
3585 20 Jul 07 martin 3414         should run on a subset of bioassays in a bioassay set: 
3585 20 Jul 07 martin 3415           <methodname>getSourceBioAssaysParameter()</methodname>,
3585 20 Jul 07 martin 3416           <methodname>getSourceBioAssays()</methodname>
3585 20 Jul 07 martin 3417         </para>
3585 20 Jul 07 martin 3418       </listitem>
3585 20 Jul 07 martin 3419       <listitem>
3585 20 Jul 07 martin 3420         <para>
3570 19 Jul 07 nicklas 3421         The name and description of the child bioassay set that
3570 19 Jul 07 nicklas 3422         is going to be created by the plug-in:
3570 19 Jul 07 nicklas 3423         <methodname>getChildNameParameter()</methodname>,
3570 19 Jul 07 nicklas 3424         <methodname>getChildDescriptionParameter()</methodname>
3570 19 Jul 07 nicklas 3425         </para>
3570 19 Jul 07 nicklas 3426       </listitem>
3570 19 Jul 07 nicklas 3427       <listitem>
3570 19 Jul 07 nicklas 3428         <para>
3570 19 Jul 07 nicklas 3429         The name and description of the transformation that
3570 19 Jul 07 nicklas 3430         represents the execution of the plug-in:
3570 19 Jul 07 nicklas 3431         <methodname>getTransformationNameParameter()</methodname>,
3570 19 Jul 07 nicklas 3432         <methodname>getTransformationName()</methodname>
3570 19 Jul 07 nicklas 3433         </para>
3570 19 Jul 07 nicklas 3434       </listitem>
3570 19 Jul 07 nicklas 3435       </itemizedlist>
3570 19 Jul 07 nicklas 3436       
3570 19 Jul 07 nicklas 3437     </sect2>
3592 23 Jul 07 nicklas 3438     
3592 23 Jul 07 nicklas 3439     <sect2 id="plugin_developer.analyse.filterplugin">
3592 23 Jul 07 nicklas 3440       <title>The AnalysisFilterPlugin interface</title>
3592 23 Jul 07 nicklas 3441       
3592 23 Jul 07 nicklas 3442       <para>
3944 09 Nov 07 martin 3443         The <interfacename docapi="net.sf.basedb.core.plugin">net.sf.basedb.core.plugin.AnalysisFilterPlugin</interfacename> 
3662 14 Aug 07 martin 3444         is a tagging interface, with no methods, that all analysis plug-ins that only filters
3592 23 Jul 07 nicklas 3445         data should implement. The benefit is that they will be linked from the
3592 23 Jul 07 nicklas 3446         <guibutton>Filter bioassay set</guibutton> button and not just
3592 23 Jul 07 nicklas 3447         the <guibutton>Run analysis</guibutton> button. They will also get
3592 23 Jul 07 nicklas 3448         a different icon in the experiment outline to make filtering 
3592 23 Jul 07 nicklas 3449         transformations appear different from other transformations.
3592 23 Jul 07 nicklas 3450       </para>
3592 23 Jul 07 nicklas 3451       
3592 23 Jul 07 nicklas 3452       <para>
3592 23 Jul 07 nicklas 3453         The interface exists purely for making the user interaction better. There is
3592 23 Jul 07 nicklas 3454         no harm in not implementing it since the plug-in will always appear in
3592 23 Jul 07 nicklas 3455         from the <guibutton>Run analysis</guibutton> button. On the other hand,
3592 23 Jul 07 nicklas 3456         it doesn't cost anything to implement the interface since it doesn't
3592 23 Jul 07 nicklas 3457         have any methods.
3592 23 Jul 07 nicklas 3458       </para>
3592 23 Jul 07 nicklas 3459     
3592 23 Jul 07 nicklas 3460     </sect2>
3315 09 May 07 nicklas 3461
3178 12 Mar 07 enell 3462   </sect1>
3178 12 Mar 07 enell 3463   
3178 12 Mar 07 enell 3464   <sect1 id="plugin_developer.other">
5782 04 Oct 11 nicklas 3465     <?dbhtml filename="other.html" ?>
3366 23 May 07 nicklas 3466     <title>Other plug-ins</title>
3178 12 Mar 07 enell 3467     
3178 12 Mar 07 enell 3468     <sect2 id="plugin_developer.other.unpacker">
3366 23 May 07 nicklas 3469       <title>File unpacker plug-ins</title>
5816 20 Oct 11 nicklas 3470     
3315 09 May 07 nicklas 3471       <para>
3383 25 May 07 nicklas 3472         The BASE web client has integrated support for unpacking of 
3383 25 May 07 nicklas 3473         compressed files. See <xref linkend="file_system.handling.upload" />.
3383 25 May 07 nicklas 3474         Behind the scenes, this support is provided by plug-ins. The standard 
3383 25 May 07 nicklas 3475         BASE distribution comes with support for ZIP files 
3944 09 Nov 07 martin 3476         (<classname docapi="net.sf.basedb.plugins">net.sf.basedb.plugins.ZipFileUnpacker</classname>)
3944 09 Nov 07 martin 3477         and TAR files (<classname docapi="net.sf.basedb.plugins">net.sf.basedb.plugins.TarFileUnpacker</classname>).
3315 09 May 07 nicklas 3478       </para>
3383 25 May 07 nicklas 3479       <para>
3383 25 May 07 nicklas 3480         To add support for additional compressed formats you have to create a plug-in that
3944 09 Nov 07 martin 3481         implements the <interfacename docapi="net.sf.basedb.util.zip">net.sf.basedb.util.zip.FileUnpacker</interfacename>
3383 25 May 07 nicklas 3482         interface. The best way to do this is to extend the 
3944 09 Nov 07 martin 3483         <classname docapi="net.sf.basedb.util.zip">net.sf.basedb.util.zip.AbstractFileUnpacker</classname> which 
3944 09 Nov 07 martin 3484         implements all methods in the <interfacename docapi="net.sf.basedb.core.plugin">Plugin</interfacename>
3944 09 Nov 07 martin 3485         and <interfacename docapi="net.sf.basedb.core.plugin">InteractivePlugin</interfacename>
5816 20 Oct 11 nicklas 3486         interfaces. This leaves
3383 25 May 07 nicklas 3487         you with the actual unpacking of the files as the only thing to implement.
3383 25 May 07 nicklas 3488       </para>
3383 25 May 07 nicklas 3489       
3383 25 May 07 nicklas 3490       <note>
3383 25 May 07 nicklas 3491         <title>No support for configurations</title>
3383 25 May 07 nicklas 3492         The integrated upload in the web interface only works with plug-ins that
3487 13 Jun 07 peter 3493         does not require a configuration to run.
3383 25 May 07 nicklas 3494       </note>
3383 25 May 07 nicklas 3495       
3383 25 May 07 nicklas 3496       <variablelist>
3944 09 Nov 07 martin 3497         <title>Methods in the <interfacename docapi="net.sf.basedb.util.zip">FileUnpacker</interfacename> interface</title>
3383 25 May 07 nicklas 3498         <varlistentry>
3383 25 May 07 nicklas 3499           <term>
3383 25 May 07 nicklas 3500             <methodsynopsis language="java">
3383 25 May 07 nicklas 3501               <modifier>public</modifier>
3383 25 May 07 nicklas 3502               <type>String</type>
3383 25 May 07 nicklas 3503               <methodname>getFormatName</methodname>
3383 25 May 07 nicklas 3504             </methodsynopsis>
3383 25 May 07 nicklas 3505           </term>
3383 25 May 07 nicklas 3506           <listitem>
3383 25 May 07 nicklas 3507             <para>
3383 25 May 07 nicklas 3508             Return a short string naming the file format. For example:
3383 25 May 07 nicklas 3509             <constant>ZIP files</constant> or <constant>TAR files</constant>.
3383 25 May 07 nicklas 3510             </para>
3383 25 May 07 nicklas 3511           </listitem>
3383 25 May 07 nicklas 3512         </varlistentry>
3383 25 May 07 nicklas 3513             
3383 25 May 07 nicklas 3514         <varlistentry>
3383 25 May 07 nicklas 3515           <term>
3383 25 May 07 nicklas 3516             <methodsynopsis language="java">
3383 25 May 07 nicklas 3517               <modifier>public</modifier>
3383 25 May 07 nicklas 3518               <type>Set&lt;String&gt;</type>
3383 25 May 07 nicklas 3519               <methodname>getExtensions</methodname>
3383 25 May 07 nicklas 3520             </methodsynopsis>
3383 25 May 07 nicklas 3521           </term>
3383 25 May 07 nicklas 3522           <listitem>
3383 25 May 07 nicklas 3523             <para>
3383 25 May 07 nicklas 3524             Return a set of strings with the file extensions that
3383 25 May 07 nicklas 3525             are most commonly used with the compressed file format.
3383 25 May 07 nicklas 3526             For example: <constant>[zip, jar]</constant>. Do not include
3383 25 May 07 nicklas 3527             the dot in the extensions. The web client and the 
3383 25 May 07 nicklas 3528             <methodname>AbstractFlatFileUnpacker.isInContext()</methodname> method
3383 25 May 07 nicklas 3529             will use this information to automatically guess which plug-in to 
3383 25 May 07 nicklas 3530             use for unpacking the files.
3383 25 May 07 nicklas 3531             </para>
3383 25 May 07 nicklas 3532           </listitem>
3383 25 May 07 nicklas 3533         </varlistentry>
3383 25 May 07 nicklas 3534         
3383 25 May 07 nicklas 3535         <varlistentry>
3383 25 May 07 nicklas 3536           <term>
3383 25 May 07 nicklas 3537             <methodsynopsis language="java">
3383 25 May 07 nicklas 3538               <modifier>public</modifier>
3383 25 May 07 nicklas 3539               <type>Set&lt;String&gt;</type>
3383 25 May 07 nicklas 3540               <methodname>getMimeTypes</methodname>
3383 25 May 07 nicklas 3541             </methodsynopsis>
3383 25 May 07 nicklas 3542           </term>
3383 25 May 07 nicklas 3543           <listitem>
3383 25 May 07 nicklas 3544             <para>
3383 25 May 07 nicklas 3545             Return a set of string with the MIME types that commonly used with 
3383 25 May 07 nicklas 3546             the compressed file format. For example: 
3383 25 May 07 nicklas 3547             <constant>[application/zip, application/java-archive]</constant>. 
3383 25 May 07 nicklas 3548             This information is used by the 
3383 25 May 07 nicklas 3549             <methodname>AbstractFlatFileUnpacker.isInContext()</methodname> 
3383 25 May 07 nicklas 3550             method to automatically guess which plug-in to use for unpacking 
3383 25 May 07 nicklas 3551             the files.
3383 25 May 07 nicklas 3552             </para>
3383 25 May 07 nicklas 3553           </listitem>
3383 25 May 07 nicklas 3554         </varlistentry>
3383 25 May 07 nicklas 3555         
3383 25 May 07 nicklas 3556         <varlistentry>
3383 25 May 07 nicklas 3557           <term>
3383 25 May 07 nicklas 3558             <methodsynopsis language="java">
3383 25 May 07 nicklas 3559               <modifier>public</modifier>
3383 25 May 07 nicklas 3560               <type>int</type>
3383 25 May 07 nicklas 3561               <methodname>unpack</methodname>
3383 25 May 07 nicklas 3562               <methodparam>
3383 25 May 07 nicklas 3563                 <type>DbControl</type>
3383 25 May 07 nicklas 3564                 <parameter>dc</parameter>
3383 25 May 07 nicklas 3565               </methodparam>
3383 25 May 07 nicklas 3566               <methodparam>
3383 25 May 07 nicklas 3567                 <type>Directory</type>
3383 25 May 07 nicklas 3568                 <parameter>dir</parameter>
3383 25 May 07 nicklas 3569               </methodparam>
3383 25 May 07 nicklas 3570               <methodparam>
3383 25 May 07 nicklas 3571                 <type>InputStream</type>
3383 25 May 07 nicklas 3572                 <parameter>in</parameter>
3383 25 May 07 nicklas 3573               </methodparam>
3383 25 May 07 nicklas 3574               <methodparam>
5816 20 Oct 11 nicklas 3575                 <type>File</type>
5816 20 Oct 11 nicklas 3576                 <parameter>sourceFile</parameter>
5816 20 Oct 11 nicklas 3577               </methodparam>
5816 20 Oct 11 nicklas 3578               <methodparam>
3383 25 May 07 nicklas 3579                 <type>boolean</type>
3383 25 May 07 nicklas 3580                 <parameter>overwrite</parameter>
3383 25 May 07 nicklas 3581               </methodparam>
3383 25 May 07 nicklas 3582               <methodparam>
3383 25 May 07 nicklas 3583                 <type>AbsoluteProgressReporter</type>
3383 25 May 07 nicklas 3584                 <parameter>progress</parameter>
3383 25 May 07 nicklas 3585               </methodparam>
3383 25 May 07 nicklas 3586               <exceptionname>IOException</exceptionname>
3383 25 May 07 nicklas 3587               <exceptionname>BaseException</exceptionname>
3383 25 May 07 nicklas 3588             </methodsynopsis>
3383 25 May 07 nicklas 3589           </term>
3383 25 May 07 nicklas 3590           <listitem>
3383 25 May 07 nicklas 3591             <para>
3383 25 May 07 nicklas 3592             Unpack the files and store them in the BASE file system. 
3383 25 May 07 nicklas 3593             
3383 25 May 07 nicklas 3594             <itemizedlist>
3383 25 May 07 nicklas 3595             <listitem>
3383 25 May 07 nicklas 3596               <para>
3383 25 May 07 nicklas 3597               Do not <methodname>close()</methodname> or 
3383 25 May 07 nicklas 3598               <methodname>commit()</methodname> the 
3944 09 Nov 07 martin 3599               <classname docapi="net.sf.basedb.core">DbControl</classname> passed to this method.
3383 25 May 07 nicklas 3600               This is done automatically by the 
3944 09 Nov 07 martin 3601               <classname docapi="net.sf.basedb.util.zip">AbstractFileUnpacker</classname> or by the web client.
3383 25 May 07 nicklas 3602               </para>
3383 25 May 07 nicklas 3603             </listitem>
3383 25 May 07 nicklas 3604             
3383 25 May 07 nicklas 3605             <listitem>
3383 25 May 07 nicklas 3606               <para>
3383 25 May 07 nicklas 3607               The <varname>dir</varname> parameter is the root directory where
3383 25 May 07 nicklas 3608               the unpacked files should be placed. If the compressed file
3565 17 Jul 07 nicklas 3609               contains subdirectories the plug-in must create those subdirectories
3383 25 May 07 nicklas 3610               unless they already exists.
3383 25 May 07 nicklas 3611               </para>
3383 25 May 07 nicklas 3612             </listitem>
3383 25 May 07 nicklas 3613             
3383 25 May 07 nicklas 3614             <listitem>
3383 25 May 07 nicklas 3615               <para>
3383 25 May 07 nicklas 3616               If the <varname>overwrite</varname> parameter is 
3383 25 May 07 nicklas 3617               <constant>FALSE</constant> no existing file should be overwritten
5816 20 Oct 11 nicklas 3618               unless the file is <systemitem>OFFLINE</systemitem> or marked as
5816 20 Oct 11 nicklas 3619               removed (do not forget to clear the removed attribute).
3383 25 May 07 nicklas 3620               </para>
3383 25 May 07 nicklas 3621             </listitem>
3383 25 May 07 nicklas 3622             
3383 25 May 07 nicklas 3623             <listitem>
3383 25 May 07 nicklas 3624               <para>
3383 25 May 07 nicklas 3625               The <varname>in</varname> parameter is the stream
3383 25 May 07 nicklas 3626               containing the compressed data. The stream may come
3383 25 May 07 nicklas 3627               directly from the web upload or from an existing
3383 25 May 07 nicklas 3628               file in the BASE file system.
3383 25 May 07 nicklas 3629               </para>
3383 25 May 07 nicklas 3630             </listitem>
3383 25 May 07 nicklas 3631             
3383 25 May 07 nicklas 3632             <listitem>
3383 25 May 07 nicklas 3633               <para>
5816 20 Oct 11 nicklas 3634               The <varname>sourceFile</varname> parameter is the file
5816 20 Oct 11 nicklas 3635               item representing the compressed file. This item may already be in
5816 20 Oct 11 nicklas 3636               the database, or a new item that may or may not be saved in the database
5816 20 Oct 11 nicklas 3637               at the end of the transaction. The information in this parameter
5816 20 Oct 11 nicklas 3638               can be used to discover the options for file type, character set, MIME
5816 20 Oct 11 nicklas 3639               type, etc. that was selected by the user in the upload dialog.
5816 20 Oct 11 nicklas 3640               The <classname docapi="net.sf.basedb.util.zip">PackUtil</classname> 
5816 20 Oct 11 nicklas 3641               has a useful method that can be used for copying information.
5816 20 Oct 11 nicklas 3642               </para>
5816 20 Oct 11 nicklas 3643             </listitem>
5816 20 Oct 11 nicklas 3644             
5816 20 Oct 11 nicklas 3645             <listitem>
5816 20 Oct 11 nicklas 3646               <para>
3383 25 May 07 nicklas 3647               The <varname>progress</varname> parameter, if not 
3662 14 Aug 07 martin 3648               <constant>null</constant>, should be used to report the
3383 25 May 07 nicklas 3649               progress back to the calling code. The plug-in should count
3383 25 May 07 nicklas 3650               the number of bytes read from the <varname>in</varname>
3565 17 Jul 07 nicklas 3651               stream. If it is not possible by other means the stream can
3944 09 Nov 07 martin 3652               be wrapped by a <classname docapi="net.sf.basedb.util">net.sf.basedb.util.InputStreamTracker</classname>
3565 17 Jul 07 nicklas 3653               object which has a <methodname>getNumRead()</methodname> method.
3383 25 May 07 nicklas 3654               </para>
3383 25 May 07 nicklas 3655             </listitem>
3383 25 May 07 nicklas 3656             </itemizedlist>
3383 25 May 07 nicklas 3657             
3383 25 May 07 nicklas 3658             </para>
3383 25 May 07 nicklas 3659           </listitem>
3383 25 May 07 nicklas 3660         </varlistentry>
3383 25 May 07 nicklas 3661       </variablelist>
3383 25 May 07 nicklas 3662       
3383 25 May 07 nicklas 3663       <para>
3383 25 May 07 nicklas 3664         When the compressed file is uncompressed during the file upload
3383 25 May 07 nicklas 3665         from the web interface, the call sequence to the plug-in is slightly
3383 25 May 07 nicklas 3666         altered from the standard call sequence described in 
3383 25 May 07 nicklas 3667         <xref linkend="plugin_developer.api.callsequence.execute" />.
3383 25 May 07 nicklas 3668         
3383 25 May 07 nicklas 3669         <itemizedlist>
3383 25 May 07 nicklas 3670         <listitem>
3383 25 May 07 nicklas 3671           <para>
3383 25 May 07 nicklas 3672           After the plug-in instance has been created, the 
3383 25 May 07 nicklas 3673           <methodname>Plugin.init()</methodname> method is called with <constant>null</constant>
3383 25 May 07 nicklas 3674           values for both the <varname>configuration</varname> and <varname>job</varname>
3383 25 May 07 nicklas 3675           parameters.
3383 25 May 07 nicklas 3676           </para>
3383 25 May 07 nicklas 3677         </listitem>
3383 25 May 07 nicklas 3678         
3383 25 May 07 nicklas 3679         <listitem>
3383 25 May 07 nicklas 3680           <para>
3383 25 May 07 nicklas 3681           Then, the <methodname>unpack()</methodname> method is called. The
3383 25 May 07 nicklas 3682           <methodname>Plugin.run()</methodname> method is never called in this case.
3383 25 May 07 nicklas 3683           </para>
3383 25 May 07 nicklas 3684         </listitem>
3383 25 May 07 nicklas 3685         
3383 25 May 07 nicklas 3686         </itemizedlist>
3383 25 May 07 nicklas 3687         
3383 25 May 07 nicklas 3688       </para>
3383 25 May 07 nicklas 3689       
3178 12 Mar 07 enell 3690     </sect2>
3643 08 Aug 07 nicklas 3691     
3643 08 Aug 07 nicklas 3692     <sect2 id="plugin_developer.other.packer">
3643 08 Aug 07 nicklas 3693       <title>File packer plug-ins</title>
3643 08 Aug 07 nicklas 3694     
3643 08 Aug 07 nicklas 3695       <para>
3643 08 Aug 07 nicklas 3696         BASE has support for compressing and downloading a set of selected files and/or
3643 08 Aug 07 nicklas 3697         directories. This functionality is provided by a plug-in, the 
3944 09 Nov 07 martin 3698         <classname docapi="net.sf.basedb.plugins">PackedFileExporter</classname>. This plug-in doesn't do the actual
3643 08 Aug 07 nicklas 3699         packing itself. This is delegated to classes implementing the 
3944 09 Nov 07 martin 3700         <interfacename docapi="net.sf.basedb.util.zip">net.sf.basedb.util.zip.FilePacker</interfacename> interface.
3643 08 Aug 07 nicklas 3701       </para>
3643 08 Aug 07 nicklas 3702       
3643 08 Aug 07 nicklas 3703       <para>
3643 08 Aug 07 nicklas 3704         BASE ships with a number of packing methods, including ZIP and TAR. To
3643 08 Aug 07 nicklas 3705         add support for other methods you have to provide an implementation
3944 09 Nov 07 martin 3706         of the <interfacename docapi="net.sf.basedb.util.zip">FilePacker</interfacename>
3944 09 Nov 07 martin 3707         interface. Then, create a new configuration for the <classname docapi="net.sf.basedb.plugins">PackedFileExporter</classname>
3643 08 Aug 07 nicklas 3708         and enter the name of your class in the configuration wizard.
3643 08 Aug 07 nicklas 3709       </para>
3643 08 Aug 07 nicklas 3710       
3643 08 Aug 07 nicklas 3711       <para>
3944 09 Nov 07 martin 3712         The <interfacename docapi="net.sf.basedb.util.zip">FilePacker</interfacename> interface is not a regular
3643 08 Aug 07 nicklas 3713         plug-in interface (ie. it is not a subinterface to 
3944 09 Nov 07 martin 3714         <interfacename docapi="net.sf.basedb.core.plugin">Plugin</interfacename>). This means that you don't have to
3643 08 Aug 07 nicklas 3715         mess with configuration or job parameters. Another difference is that your
3643 08 Aug 07 nicklas 3716         class must be installed in Tomcat's classpath (ie. in one of the 
3643 08 Aug 07 nicklas 3717         <filename>WEB-INF/classes</filename> or <filename>WEB-INF/lib</filename>
3643 08 Aug 07 nicklas 3718         folders).
3643 08 Aug 07 nicklas 3719       </para>
3643 08 Aug 07 nicklas 3720       
5816 20 Oct 11 nicklas 3721       <important>
5816 20 Oct 11 nicklas 3722         <title>This may be converted to an extension point in the future</title>
5816 20 Oct 11 nicklas 3723         
5816 20 Oct 11 nicklas 3724         <para>
5816 20 Oct 11 nicklas 3725         There are certain plans to convert the packing mechanism to an 
5816 20 Oct 11 nicklas 3726         extension point in the future. The main reason is easier installation 
5816 20 Oct 11 nicklas 3727         since code doesn't have to be installed in the 
5816 20 Oct 11 nicklas 3728         WEB-INF/lib or WEB-INF/classes directory. See <ulink 
7982 14 Jun 21 nicklas 3729         url="https://base.thep.lu.se/ticket/1600">ticket #1600: Convert file 
5816 20 Oct 11 nicklas 3730         packing plug-in system to an extension point</ulink> for more information.
5816 20 Oct 11 nicklas 3731         </para>
5816 20 Oct 11 nicklas 3732       
5816 20 Oct 11 nicklas 3733       </important>
5816 20 Oct 11 nicklas 3734       
3643 08 Aug 07 nicklas 3735       <variablelist>
3944 09 Nov 07 martin 3736         <title>Methods in the <interfacename docapi="net.sf.basedb.util.zip">FilePacker</interfacename> interface</title>
3643 08 Aug 07 nicklas 3737         <varlistentry>
3643 08 Aug 07 nicklas 3738           <term>
3643 08 Aug 07 nicklas 3739             <methodsynopsis language="java">
3643 08 Aug 07 nicklas 3740               <modifier>public</modifier>
3643 08 Aug 07 nicklas 3741               <type>String</type>
3643 08 Aug 07 nicklas 3742               <methodname>getDescription</methodname>
3643 08 Aug 07 nicklas 3743             </methodsynopsis>
3643 08 Aug 07 nicklas 3744           </term>
3643 08 Aug 07 nicklas 3745           <listitem>
3643 08 Aug 07 nicklas 3746             <para>
3643 08 Aug 07 nicklas 3747             Return a short description the file format that is suitable for use
3643 08 Aug 07 nicklas 3748             in dropdown lists in client applications. For example:
3643 08 Aug 07 nicklas 3749             <constant>Zip-archive (.zip)</constant> or <constant>TAR-archive (.tar)</constant>.
3643 08 Aug 07 nicklas 3750             </para>
3643 08 Aug 07 nicklas 3751           </listitem>
3643 08 Aug 07 nicklas 3752         </varlistentry>
3643 08 Aug 07 nicklas 3753         <varlistentry>
3643 08 Aug 07 nicklas 3754           <term>
3643 08 Aug 07 nicklas 3755             <methodsynopsis language="java">
3643 08 Aug 07 nicklas 3756               <modifier>public</modifier>
3643 08 Aug 07 nicklas 3757               <type>String</type>
3643 08 Aug 07 nicklas 3758               <methodname>getFileExtension</methodname>
3643 08 Aug 07 nicklas 3759             </methodsynopsis>
3643 08 Aug 07 nicklas 3760           </term>
3643 08 Aug 07 nicklas 3761           <listitem>
3643 08 Aug 07 nicklas 3762             <para>
3643 08 Aug 07 nicklas 3763             Return the default file extension of the packed format. The returned
3643 08 Aug 07 nicklas 3764             value should not include the dot. For example:
3643 08 Aug 07 nicklas 3765             <constant>zip</constant> or <constant>tar</constant>.
3643 08 Aug 07 nicklas 3766             </para>
3643 08 Aug 07 nicklas 3767           </listitem>
3643 08 Aug 07 nicklas 3768         </varlistentry>
3643 08 Aug 07 nicklas 3769         <varlistentry>
3643 08 Aug 07 nicklas 3770           <term>
3643 08 Aug 07 nicklas 3771             <methodsynopsis language="java">
3643 08 Aug 07 nicklas 3772               <modifier>public</modifier>
3643 08 Aug 07 nicklas 3773               <type>String</type>
3643 08 Aug 07 nicklas 3774               <methodname>getMimeType</methodname>
3643 08 Aug 07 nicklas 3775             </methodsynopsis>
3643 08 Aug 07 nicklas 3776           </term>
3643 08 Aug 07 nicklas 3777           <listitem>
3643 08 Aug 07 nicklas 3778             <para>
3643 08 Aug 07 nicklas 3779             Return the standard MIME type of the packed file format.
3643 08 Aug 07 nicklas 3780             For example: 
3643 08 Aug 07 nicklas 3781             <constant>application/zip</constant> or <constant>application/x-tar</constant>.
3643 08 Aug 07 nicklas 3782             </para>
3643 08 Aug 07 nicklas 3783           </listitem>
3643 08 Aug 07 nicklas 3784         </varlistentry>
3643 08 Aug 07 nicklas 3785         <varlistentry>
3643 08 Aug 07 nicklas 3786           <term>
3643 08 Aug 07 nicklas 3787             <methodsynopsis language="java">
3643 08 Aug 07 nicklas 3788               <modifier>public</modifier>
3643 08 Aug 07 nicklas 3789               <void />
3643 08 Aug 07 nicklas 3790               <methodname>setOutputStream</methodname>
3643 08 Aug 07 nicklas 3791               <methodparam>
3643 08 Aug 07 nicklas 3792                 <type>OutputStream</type>
3643 08 Aug 07 nicklas 3793                 <parameter>out</parameter>
3643 08 Aug 07 nicklas 3794               </methodparam>
3643 08 Aug 07 nicklas 3795               <exceptionname>IOException</exceptionname>
3643 08 Aug 07 nicklas 3796             </methodsynopsis>
3643 08 Aug 07 nicklas 3797           </term>
3643 08 Aug 07 nicklas 3798           <listitem>
3643 08 Aug 07 nicklas 3799             <para>
3643 08 Aug 07 nicklas 3800             Sets the outputstream that the packer should write the packed
3643 08 Aug 07 nicklas 3801             files to.
3643 08 Aug 07 nicklas 3802             </para>
3643 08 Aug 07 nicklas 3803           </listitem>
3643 08 Aug 07 nicklas 3804         </varlistentry>
3643 08 Aug 07 nicklas 3805         <varlistentry>
3643 08 Aug 07 nicklas 3806           <term>
3643 08 Aug 07 nicklas 3807             <methodsynopsis language="java">
3643 08 Aug 07 nicklas 3808               <modifier>public</modifier>
3643 08 Aug 07 nicklas 3809               <void />
3643 08 Aug 07 nicklas 3810               <methodname>pack</methodname>
3643 08 Aug 07 nicklas 3811               <methodparam>
3643 08 Aug 07 nicklas 3812                 <type>String</type>
3643 08 Aug 07 nicklas 3813                 <parameter>entryName</parameter>
3643 08 Aug 07 nicklas 3814               </methodparam>
3643 08 Aug 07 nicklas 3815               <methodparam>
3643 08 Aug 07 nicklas 3816                 <type>InputStream</type>
3643 08 Aug 07 nicklas 3817                 <parameter>in</parameter>
3643 08 Aug 07 nicklas 3818               </methodparam>
3643 08 Aug 07 nicklas 3819               <methodparam>
3643 08 Aug 07 nicklas 3820                 <type>long</type>
3643 08 Aug 07 nicklas 3821                 <parameter>size</parameter>
3643 08 Aug 07 nicklas 3822               </methodparam>
3643 08 Aug 07 nicklas 3823               <methodparam>
3643 08 Aug 07 nicklas 3824                 <type>long</type>
3643 08 Aug 07 nicklas 3825                 <parameter>lastModified</parameter>
3643 08 Aug 07 nicklas 3826               </methodparam>
3643 08 Aug 07 nicklas 3827               <exceptionname>IOException</exceptionname>
3643 08 Aug 07 nicklas 3828             </methodsynopsis>
3643 08 Aug 07 nicklas 3829           </term>
3643 08 Aug 07 nicklas 3830           <listitem>
3643 08 Aug 07 nicklas 3831             <para>
3643 08 Aug 07 nicklas 3832             Add another file or directory to the packed file. The 
3643 08 Aug 07 nicklas 3833             <parameter>entryName</parameter> is the name of the new entry, including
3643 08 Aug 07 nicklas 3834             path information. The <parameter>in</parameter> is the stream to read
3643 08 Aug 07 nicklas 3835             the file data from. If <parameter>in</parameter> is <constant>null</constant>
3643 08 Aug 07 nicklas 3836             then the entry denotes a directory. The <parameter>size</parameter> parameter
3643 08 Aug 07 nicklas 3837             gives the size in bytes of the file (zero for empty files or directories). 
3643 08 Aug 07 nicklas 3838             The <parameter>lastModified</parameter>
3643 08 Aug 07 nicklas 3839             is that time the file was last modified or 0 if not known.
3643 08 Aug 07 nicklas 3840             </para>
3643 08 Aug 07 nicklas 3841           </listitem>
3643 08 Aug 07 nicklas 3842         </varlistentry>
3643 08 Aug 07 nicklas 3843         <varlistentry>
3643 08 Aug 07 nicklas 3844           <term>
3643 08 Aug 07 nicklas 3845             <methodsynopsis language="java">
3643 08 Aug 07 nicklas 3846               <modifier>public</modifier>
3643 08 Aug 07 nicklas 3847               <void />
3643 08 Aug 07 nicklas 3848               <methodname>close</methodname>
3643 08 Aug 07 nicklas 3849               <exceptionname>IOException</exceptionname>
3643 08 Aug 07 nicklas 3850             </methodsynopsis>
3643 08 Aug 07 nicklas 3851           </term>
3643 08 Aug 07 nicklas 3852           <listitem>
3643 08 Aug 07 nicklas 3853             <para>
3643 08 Aug 07 nicklas 3854             Finish the packing. The packer should release any resources, flush
3646 09 Aug 07 nicklas 3855             all data and close all output streams, including the <varname>out</varname> stream
3646 09 Aug 07 nicklas 3856             set in the <methodname>setOutputStream</methodname> method.
3643 08 Aug 07 nicklas 3857             </para>
3643 08 Aug 07 nicklas 3858           </listitem>
3643 08 Aug 07 nicklas 3859         </varlistentry>
3643 08 Aug 07 nicklas 3860         
3643 08 Aug 07 nicklas 3861       </variablelist>
3643 08 Aug 07 nicklas 3862       
3643 08 Aug 07 nicklas 3863     </sect2>
5071 21 Aug 09 nicklas 3864
3178 12 Mar 07 enell 3865   </sect1>
3178 12 Mar 07 enell 3866   
3870 19 Oct 07 nicklas 3867   <sect1 id="plugin_developer.classload">
5782 04 Oct 11 nicklas 3868     <?dbhtml filename="classloading.html" ?>
3870 19 Oct 07 nicklas 3869     <title>How BASE load plug-in classes</title>
3870 19 Oct 07 nicklas 3870     
3870 19 Oct 07 nicklas 3871     <para>
5640 24 May 11 nicklas 3872       All plug-ins should be installed in the location specified by the 
5640 24 May 11 nicklas 3873       <varname>plugins.dir</varname> setting in <filename>base.config</filename>.
5640 24 May 11 nicklas 3874       While it is possible to also install them in a location that is on the
5640 24 May 11 nicklas 3875       classpath, for example <filename>&lt;base-dir&gt;/www/WEB-INF/lib</filename>,
5640 24 May 11 nicklas 3876       it is nothing that we recommend. The rest of the information in this section 
5640 24 May 11 nicklas 3877       only applies to plug-ins that have been installed in the <varname>plugins.dir</varname>
5640 24 May 11 nicklas 3878       location.
3870 19 Oct 07 nicklas 3879     </para>
3870 19 Oct 07 nicklas 3880     
3870 19 Oct 07 nicklas 3881     <para>
3870 19 Oct 07 nicklas 3882       If the above recommendation has been followed BASE will use it's
3870 19 Oct 07 nicklas 3883       own classloader to load the plug-in classes. This have several
3870 19 Oct 07 nicklas 3884       benefits:
3870 19 Oct 07 nicklas 3885     </para>
3870 19 Oct 07 nicklas 3886     
3870 19 Oct 07 nicklas 3887     <itemizedlist>
3870 19 Oct 07 nicklas 3888     <listitem>
3870 19 Oct 07 nicklas 3889       <para>
3870 19 Oct 07 nicklas 3890       New plug-ins can be installed and existing plug-ins can be updated
3870 19 Oct 07 nicklas 3891       without restarting the web server. If the <property>plugins.autounload</property>
5013 25 Jun 09 nicklas 3892       setting in <filename>base.config</filename> has been enabled all you have to
3870 19 Oct 07 nicklas 3893       do to update a plug-in is to replace the JAR file with a new version.
3870 19 Oct 07 nicklas 3894       BASE will automatically load the new classes the next time the plug-in
3870 19 Oct 07 nicklas 3895       is used. If the option isn't enabled, the server admin has to manually
5816 20 Oct 11 nicklas 3896       update the plug-in from the web interface first.
3870 19 Oct 07 nicklas 3897       </para>
3870 19 Oct 07 nicklas 3898     </listitem>
3870 19 Oct 07 nicklas 3899     
3870 19 Oct 07 nicklas 3900     <listitem>
3870 19 Oct 07 nicklas 3901       <para>
3870 19 Oct 07 nicklas 3902       Plug-ins may use it's own 3-rd party libraries without interfering
3870 19 Oct 07 nicklas 3903       with other plug-ins. This may be important because a plug-in may depend on
3870 19 Oct 07 nicklas 3904       a certain version of a library while another plug-in may depend on
3870 19 Oct 07 nicklas 3905       a different version. Since BASE is using different class-loaders
3870 19 Oct 07 nicklas 3906       for different plug-ins this is not a problem.
3870 19 Oct 07 nicklas 3907       </para>
3870 19 Oct 07 nicklas 3908     </listitem>
3870 19 Oct 07 nicklas 3909       
3870 19 Oct 07 nicklas 3910     </itemizedlist>
3870 19 Oct 07 nicklas 3911     
3870 19 Oct 07 nicklas 3912     <para>
3870 19 Oct 07 nicklas 3913       The classloading scheme used by BASE also means plug-in
3870 19 Oct 07 nicklas 3914       developers must pay attention to a few things:
3870 19 Oct 07 nicklas 3915     </para>
3870 19 Oct 07 nicklas 3916     
3870 19 Oct 07 nicklas 3917     <itemizedlist>
3870 19 Oct 07 nicklas 3918     <listitem>
3870 19 Oct 07 nicklas 3919       <para>
3870 19 Oct 07 nicklas 3920       A plug-in can only access/use classes from it's own JAR file, BASE core
3870 19 Oct 07 nicklas 3921       classes, Java system classes and from JAR files listed in the plug-in's
3870 19 Oct 07 nicklas 3922       <filename>MANIFEST.MF</filename> file. See <xref linkend="plugin_developer.organize" />.
3870 19 Oct 07 nicklas 3923       </para>
3870 19 Oct 07 nicklas 3924     </listitem>
3870 19 Oct 07 nicklas 3925     
3870 19 Oct 07 nicklas 3926     <listitem>
3870 19 Oct 07 nicklas 3927       <para>
3870 19 Oct 07 nicklas 3928       A plug-in can also access other plug-ins, but only via the methods and
3870 19 Oct 07 nicklas 3929       interfaces defined in BASE. In the following example we assume that 
3870 19 Oct 07 nicklas 3930       there are two plug-ins, <classname>ex.MyPlugin</classname> 
3870 19 Oct 07 nicklas 3931       and <classname>ex.MyOtherPlugin</classname>,
3870 19 Oct 07 nicklas 3932       located in two different JAR files. The code below is executing
3870 19 Oct 07 nicklas 3933       in the <classname>ex.MyPlugin</classname>:
3870 19 Oct 07 nicklas 3934       </para>
3870 19 Oct 07 nicklas 3935       
3870 19 Oct 07 nicklas 3936       <programlisting language="java">
3870 19 Oct 07 nicklas 3937 // Prepare to load MyOtherPlugin
3870 19 Oct 07 nicklas 3938 SessionControl sc = ...
3870 19 Oct 07 nicklas 3939 DbControl dc = ...
3870 19 Oct 07 nicklas 3940 PluginDefinition def = PluginDefinition.getByClassName(dc, "ex.MyOtherPlugin");
3870 19 Oct 07 nicklas 3941
3870 19 Oct 07 nicklas 3942 // Ok
5640 24 May 11 nicklas 3943 Plugin other = def.newInstance();
3870 19 Oct 07 nicklas 3944
3870 19 Oct 07 nicklas 3945 // Not ok; fails with ClassCastException
5640 24 May 11 nicklas 3946 MyOtherPlugin other = (MyOtherPlugin)def.newInstance();
5640 24 May 11 nicklas 3947
5640 24 May 11 nicklas 3948 // Ok; since now we are using the correct class loader
5640 24 May 11 nicklas 3949 MyOtherPlugin other = def.newInstance(MyOtherPlugin.class);
3870 19 Oct 07 nicklas 3950 </programlisting>
3870 19 Oct 07 nicklas 3951       
3870 19 Oct 07 nicklas 3952       <para>
5640 24 May 11 nicklas 3953       The first call succeeds because it uses the <interfacename 
5640 24 May 11 nicklas 3954       docapi="net.sf.basedb.core.plugin">Plugin</interfacename>
5640 24 May 11 nicklas 3955       interface which is defined by BASE. This class is loaded by the web servers 
5640 24 May 11 nicklas 3956       class loader and is the same for all plug-ins.
5640 24 May 11 nicklas 3957       </para>
5640 24 May 11 nicklas 3958       
5640 24 May 11 nicklas 3959       <para>
5640 24 May 11 nicklas 3960       The second call fails because BASE uses a different classloader to load the 
5640 24 May 11 nicklas 3961       <classname>ex.MyOtherPlugin</classname> class. This 
3870 19 Oct 07 nicklas 3962       class is not (in Java terms) the same as the <classname>ex.MyOtherPlugin</classname> 
3870 19 Oct 07 nicklas 3963       class loaded by the classloader that loaded the <classname>ex.MyPlugin</classname>
3870 19 Oct 07 nicklas 3964       class. If, on the other hand, both plug-ins are located in the same
3870 19 Oct 07 nicklas 3965       JAR file BASE uses the same classloader and the second call will succeed.
3870 19 Oct 07 nicklas 3966       </para>
3870 19 Oct 07 nicklas 3967       
3870 19 Oct 07 nicklas 3968       <para>
5640 24 May 11 nicklas 3969       The third call succeeds because now that we specify the class as an argument,
5640 24 May 11 nicklas 3970       BASE uses that classloader instead.
3870 19 Oct 07 nicklas 3971       </para>
3870 19 Oct 07 nicklas 3972       
3870 19 Oct 07 nicklas 3973       <para>
5640 24 May 11 nicklas 3974       Another option is that the <classname>ex.MyPlugin</classname>
3870 19 Oct 07 nicklas 3975       lists the JAR file where <classname>ex.MyOtherPlugin</classname> is
3870 19 Oct 07 nicklas 3976       located in it's <filename>MANIFEST.MF</filename> file. Then, the following
3870 19 Oct 07 nicklas 3977       code can be used: <code>MyOtherPlugin other = new MyOtherPlugin();</code>
3870 19 Oct 07 nicklas 3978       </para>
3870 19 Oct 07 nicklas 3979       
3870 19 Oct 07 nicklas 3980     </listitem>
3870 19 Oct 07 nicklas 3981     </itemizedlist>
3870 19 Oct 07 nicklas 3982     
3870 19 Oct 07 nicklas 3983     <para>
3870 19 Oct 07 nicklas 3984       Tomcat includes a good document describing how classloading is implemented
6863 15 Apr 15 nicklas 3985       in Tomcat: <ulink url="http://tomcat.apache.org/tomcat-8.0-doc/class-loader-howto.html" />.
3870 19 Oct 07 nicklas 3986       
3870 19 Oct 07 nicklas 3987       BASE's classloading scheme isn't as complex as Tomcat's, but it
3870 19 Oct 07 nicklas 3988       very similar to how Tomcat loads different web applications. 
3870 19 Oct 07 nicklas 3989       The figure on the linked document could be extended with another level
3870 19 Oct 07 nicklas 3990       with separate classloaders for each plug-in as child
3870 19 Oct 07 nicklas 3991       classloaders to the web application classloaders.  
3870 19 Oct 07 nicklas 3992     </para>
5013 25 Jun 09 nicklas 3993     
5013 25 Jun 09 nicklas 3994     <para>
5013 25 Jun 09 nicklas 3995       As of BASE 2.13 the default search order for classes has been changed. The
5013 25 Jun 09 nicklas 3996       default is now to first look in the plug-ins class path (eg. in the same
5013 25 Jun 09 nicklas 3997       JAR file and in files listed in the <filename>MANIFEST.MF</filename> file).
5013 25 Jun 09 nicklas 3998       Only if the class is not found the search is delegated to the parent class
5013 25 Jun 09 nicklas 3999       loader. This behaviour can be changed by setting <code>X-Delegate-First: true</code>
5013 25 Jun 09 nicklas 4000       in the <filename>MANIFEST.MF</filename> file. If this property is set the
5013 25 Jun 09 nicklas 4001       parent class loader is search first. This is the same as in BASE 2.12 and
5013 25 Jun 09 nicklas 4002       earlier.
5013 25 Jun 09 nicklas 4003     </para>
5013 25 Jun 09 nicklas 4004     
5013 25 Jun 09 nicklas 4005     <note>
5013 25 Jun 09 nicklas 4006       The benefit with the new search order is that plug-ins may use
5013 25 Jun 09 nicklas 4007       a specific version of any external package even if the same
5013 25 Jun 09 nicklas 4008       package is part of the BASE distribution. This was not possible before
5013 25 Jun 09 nicklas 4009       since the package in the BASE distribution was loaded first.
5013 25 Jun 09 nicklas 4010     </note>
3870 19 Oct 07 nicklas 4011   </sect1>
3870 19 Oct 07 nicklas 4012   
3178 12 Mar 07 enell 4013   <sect1 id="plugin_developer.example">
5782 04 Oct 11 nicklas 4014     <?dbhtml filename="examples.html" ?>
3366 23 May 07 nicklas 4015     <title>Example plug-ins (with download)</title>
3315 09 May 07 nicklas 4016     <para>
3607 27 Jul 07 nicklas 4017       We have created some example plug-ins which demonstrates how to
3607 27 Jul 07 nicklas 4018       use the plug-in system and how to create an interactive plug-in that
3607 27 Jul 07 nicklas 4019       can ask a user for one or more parameters.
3607 27 Jul 07 nicklas 4020     
5816 20 Oct 11 nicklas 4021       You can download a tar file with the source and compiled plug-in code from 
5816 20 Oct 11 nicklas 4022       the BASE plug-ins website:
7982 14 Jun 21 nicklas 4023       <ulink url="https://baseplugins.thep.lu.se/wiki/net.sf.basedb.examplecode"
7982 14 Jun 21 nicklas 4024       >https://baseplugins.thep.lu.se/wiki/net.sf.basedb.examplecode</ulink>
3315 09 May 07 nicklas 4025     </para>
3607 27 Jul 07 nicklas 4026     
3178 12 Mar 07 enell 4027   </sect1>
3675 16 Aug 07 jari 4028 </chapter>