doc/src/docbook/developer/core_ref.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 <!--
3192 13 Mar 07 martin 6   $Id$
3160 05 Mar 07 martin 7
3675 16 Aug 07 jari 8   Copyright (C) 2007 Peter Johansson, Nicklas Nordborg, Martin Svensson
3160 05 Mar 07 martin 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/
3160 05 Mar 07 martin 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.
3160 05 Mar 07 martin 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.
3160 05 Mar 07 martin 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
3415 31 May 07 nicklas 27 <chapter id="core_ref">
3160 05 Mar 07 martin 28   <title>Core developer reference</title>
3315 09 May 07 nicklas 29
3315 09 May 07 nicklas 30   <sect1 id="core_ref.release">
3315 09 May 07 nicklas 31     <title>Publishing a new release</title>
3315 09 May 07 nicklas 32     <para>
7982 14 Jun 21 nicklas 33       This documentation is available on the <ulink url="https://base.thep.lu.se/wiki/ReleaseProcedure">BASE wiki</ulink>.
3315 09 May 07 nicklas 34     </para>
3315 09 May 07 nicklas 35   </sect1>
3315 09 May 07 nicklas 36   
3315 09 May 07 nicklas 37   <sect1 id="core_ref.build">
3315 09 May 07 nicklas 38     <title>Subversion / building BASE</title>
3315 09 May 07 nicklas 39     <para>
7982 14 Jun 21 nicklas 40       This documentation is available on the <ulink url="https://base.thep.lu.se/wiki/BuildingBase">BASE wiki</ulink>.
3315 09 May 07 nicklas 41     </para>
3315 09 May 07 nicklas 42   </sect1>
3315 09 May 07 nicklas 43
3415 31 May 07 nicklas 44   <sect1 id="core_ref.rules" chunked="1">
3315 09 May 07 nicklas 45     <title>Coding rules and guidelines</title>
3315 09 May 07 nicklas 46     
3315 09 May 07 nicklas 47     <sect2 id="core_ref.rules.devprocess">
3415 31 May 07 nicklas 48       <title>Development process and other important procedures</title>
3315 09 May 07 nicklas 49       <para>
3415 31 May 07 nicklas 50          This section describes the development process we try to use in the BASE project. 
3415 31 May 07 nicklas 51          It is not carved in stone and deviations may occur. For every new feature
3415 31 May 07 nicklas 52          or enhancement the procure below should be followed.
3415 31 May 07 nicklas 53          If you encounter any problems, arrange a group meeting. Someone else 
3415 31 May 07 nicklas 54          may have the solution! The text is biased towards adding new
3415 31 May 07 nicklas 55          items to BASE, but it should be possible to use the general outline
3415 31 May 07 nicklas 56          even for other types of features.
3315 09 May 07 nicklas 57       </para>
3415 31 May 07 nicklas 58       
3415 31 May 07 nicklas 59       <bridgehead>1. Group meeting</bridgehead>
3415 31 May 07 nicklas 60       <itemizedlist>
3415 31 May 07 nicklas 61       <listitem>
3415 31 May 07 nicklas 62         <para>
3415 31 May 07 nicklas 63         The group should have a short meeting and discuss the new or changed 
3415 31 May 07 nicklas 64         feature. Problem areas should be identified, not solved!
3415 31 May 07 nicklas 65         </para>
3415 31 May 07 nicklas 66       </listitem>
3415 31 May 07 nicklas 67       <listitem>
3415 31 May 07 nicklas 68         <para>
3415 31 May 07 nicklas 69         The person who is going to make the analysis, design and development is 
3415 31 May 07 nicklas 70         responsible for taking notes. They should be kept until the analysis 
3415 31 May 07 nicklas 71         and design phase has been finished.      
3415 31 May 07 nicklas 72         </para>
3415 31 May 07 nicklas 73       </listitem>
3415 31 May 07 nicklas 74       <listitem>
3415 31 May 07 nicklas 75         <para>
3415 31 May 07 nicklas 76         A follow-up meeting should be held at the end of the analysis phase.  
3415 31 May 07 nicklas 77         </para>
3415 31 May 07 nicklas 78       </listitem>
3415 31 May 07 nicklas 79       <listitem>
3415 31 May 07 nicklas 80         <para>
3415 31 May 07 nicklas 81         A single meeting may of course discuss more than one feature.
3415 31 May 07 nicklas 82         </para>
3415 31 May 07 nicklas 83       </listitem>
3415 31 May 07 nicklas 84       </itemizedlist>
3415 31 May 07 nicklas 85       
3415 31 May 07 nicklas 86       <bridgehead>2. Analysis and design</bridgehead>
3415 31 May 07 nicklas 87       <itemizedlist>
3415 31 May 07 nicklas 88       <listitem>
3415 31 May 07 nicklas 89         <para>
3415 31 May 07 nicklas 90         Create an diagram of the classes including their properties, links and associations. 
3415 31 May 07 nicklas 91         Use the already existing diagrams and code as a template.
3415 31 May 07 nicklas 92         The diagram should have information about cache and proxy settings.
3415 31 May 07 nicklas 93         </para>
3415 31 May 07 nicklas 94       </listitem>
3415 31 May 07 nicklas 95       <listitem>
3415 31 May 07 nicklas 96         <para>
3415 31 May 07 nicklas 97         Write a short document about the diagram, especially things that are not obvious 
3415 31 May 07 nicklas 98         and explain any deviations from the recommendations in the coding guidelines.
3415 31 May 07 nicklas 99         </para>
3415 31 May 07 nicklas 100       </listitem>
3415 31 May 07 nicklas 101       <listitem>
3415 31 May 07 nicklas 102         <para>
3415 31 May 07 nicklas 103         Identify things that may affect backwards compatibility. For more 
5780 04 Oct 11 nicklas 104         information about such things read <xref linkend="base_api.public" />
3415 31 May 07 nicklas 105         and <xref linkend="core_ref.rules.compatibility" />.
3415 31 May 07 nicklas 106         </para>
3415 31 May 07 nicklas 107       </listitem>
3415 31 May 07 nicklas 108       <listitem>
3415 31 May 07 nicklas 109         <para>
3415 31 May 07 nicklas 110         Identify what parts of the documentation that needs to changed or added
3415 31 May 07 nicklas 111         to describe the new feature. This includes, but is not limited to:
3415 31 May 07 nicklas 112         <itemizedlist>
3415 31 May 07 nicklas 113         <listitem>
3415 31 May 07 nicklas 114           <para>
3415 31 May 07 nicklas 115           User and administrator documentation, how to use the feature, screenshots, 
3415 31 May 07 nicklas 116           etc.
3415 31 May 07 nicklas 117           </para>  
3415 31 May 07 nicklas 118         </listitem>
3415 31 May 07 nicklas 119         <listitem>
3415 31 May 07 nicklas 120           <para>
3415 31 May 07 nicklas 121           Plug-in and core developer documentation, code examples, database schema changes,
3415 31 May 07 nicklas 122           etc.
3415 31 May 07 nicklas 123           </para>  
3415 31 May 07 nicklas 124         </listitem>
3415 31 May 07 nicklas 125         </itemizedlist>
3415 31 May 07 nicklas 126         </para>
3415 31 May 07 nicklas 127       </listitem>
3415 31 May 07 nicklas 128       <listitem>
3415 31 May 07 nicklas 129         <para>
3415 31 May 07 nicklas 130         If there are any problems with the existing code, these should be solved at 
3415 31 May 07 nicklas 131         this stage. Write some prototype code for testing if necessary.
3415 31 May 07 nicklas 132         </para>
3415 31 May 07 nicklas 133       </listitem>
3415 31 May 07 nicklas 134       <listitem>
3415 31 May 07 nicklas 135         <para>
3415 31 May 07 nicklas 136         Group meeting to verify that the specified solution is ok, and to make sure 
3415 31 May 07 nicklas 137         everybody has enough knowledge of the solution.
3415 31 May 07 nicklas 138         </para>
3415 31 May 07 nicklas 139       </listitem>
3415 31 May 07 nicklas 140       </itemizedlist>
3415 31 May 07 nicklas 141       
3415 31 May 07 nicklas 142       <bridgehead>3. Create the classes for the data layer</bridgehead>
3415 31 May 07 nicklas 143       <itemizedlist>
3415 31 May 07 nicklas 144       <listitem>
3415 31 May 07 nicklas 145         <para>
3415 31 May 07 nicklas 146         If step 2 is properly done, this should not take long.
3415 31 May 07 nicklas 147         </para>
3415 31 May 07 nicklas 148       </listitem>
3415 31 May 07 nicklas 149       <listitem>
3415 31 May 07 nicklas 150         <para>
3415 31 May 07 nicklas 151         Follow the coding guidelines in <xref linkend="core_ref.rules.datalayer" />.
3415 31 May 07 nicklas 152         </para>
3415 31 May 07 nicklas 153       </listitem>
3415 31 May 07 nicklas 154       <listitem>
3415 31 May 07 nicklas 155         <para>
3415 31 May 07 nicklas 156         At the end of this step, go back and have a lock at the diagram/documentation 
3415 31 May 07 nicklas 157         from the analysis and design phase and make sure everything is still correct.
3415 31 May 07 nicklas 158         </para>
3415 31 May 07 nicklas 159       </listitem>
3415 31 May 07 nicklas 160       </itemizedlist>
3415 31 May 07 nicklas 161       
3415 31 May 07 nicklas 162       <bridgehead>4. Create the corresponding classes in the core layer</bridgehead>
3415 31 May 07 nicklas 163       <itemizedlist>
3415 31 May 07 nicklas 164       <listitem>
3415 31 May 07 nicklas 165         <para>
3415 31 May 07 nicklas 166         For simple cases this is also easy. Other cases may require more effort.
3415 31 May 07 nicklas 167         </para>
3415 31 May 07 nicklas 168       </listitem>
3415 31 May 07 nicklas 169       <listitem>
3415 31 May 07 nicklas 170         <para>
3415 31 May 07 nicklas 171         If needed, go back to the analysis and design phase and do some more investigations. 
3415 31 May 07 nicklas 172         Make sure the documentation is updated if there are changes.
3415 31 May 07 nicklas 173         </para>
3415 31 May 07 nicklas 174       </listitem>
3415 31 May 07 nicklas 175       </itemizedlist>
3415 31 May 07 nicklas 176       
3415 31 May 07 nicklas 177       <bridgehead>5. Create test code</bridgehead>
3415 31 May 07 nicklas 178       <itemizedlist>
3415 31 May 07 nicklas 179       <listitem>
3415 31 May 07 nicklas 180         <para>
3415 31 May 07 nicklas 181         Build on and use the existing test as much as possible.
3415 31 May 07 nicklas 182         </para>
3415 31 May 07 nicklas 183       </listitem>
3415 31 May 07 nicklas 184       </itemizedlist>
3415 31 May 07 nicklas 185       
3415 31 May 07 nicklas 186       <bridgehead>6. Write code to update existing installations</bridgehead>
3415 31 May 07 nicklas 187       <important>
3415 31 May 07 nicklas 188       <itemizedlist>
3415 31 May 07 nicklas 189       <listitem>
3415 31 May 07 nicklas 190         <para>
3415 31 May 07 nicklas 191         If the database schema is changed or if there for some reason is need to update
3415 31 May 07 nicklas 192         existing data in the database, the <constant>Install.SCHEMA_VERSION</constant>
3415 31 May 07 nicklas 193         counter must be increased.
3415 31 May 07 nicklas 194         </para>
3415 31 May 07 nicklas 195       </listitem>
3415 31 May 07 nicklas 196       <listitem>
3415 31 May 07 nicklas 197         <para>
3944 09 Nov 07 martin 198         Add code to the <classname docapi="net.sf.basedb.core">net.sf.basedb.core.Update</classname> class
3415 31 May 07 nicklas 199         to increase the schema version and modify data in existing installations.
3415 31 May 07 nicklas 200         </para>
3415 31 May 07 nicklas 201       </listitem>
3415 31 May 07 nicklas 202       </itemizedlist>
3415 31 May 07 nicklas 203       </important>
3415 31 May 07 nicklas 204       
3415 31 May 07 nicklas 205       <bridgehead>7. Write new and update existing user documentation</bridgehead>
3415 31 May 07 nicklas 206       <itemizedlist>
3415 31 May 07 nicklas 207       <listitem>
3415 31 May 07 nicklas 208         <para>
3415 31 May 07 nicklas 209         Most likely, users and plug-in developers wants to know about the feature.
3415 31 May 07 nicklas 210         </para>
3415 31 May 07 nicklas 211       </listitem>
3415 31 May 07 nicklas 212       </itemizedlist>
3415 31 May 07 nicklas 213
3415 31 May 07 nicklas 214       <important>
3415 31 May 07 nicklas 215       <para>
3487 13 Jun 07 peter 216       Do not forget to update the <xref linkend="appendix.incompatible" /> document
3415 31 May 07 nicklas 217       if you have introduced any incomaptible changes.
3415 31 May 07 nicklas 218       </para>
3415 31 May 07 nicklas 219       </important>
3415 31 May 07 nicklas 220       
3315 09 May 07 nicklas 221     </sect2>
3315 09 May 07 nicklas 222     <sect2 id="core_ref.rules.style">
3315 09 May 07 nicklas 223       <title>General coding style guidelines</title>
5673 27 Jun 11 nicklas 224       
5673 27 Jun 11 nicklas 225       <sect3 id="core_ref.rules.naming">
5673 27 Jun 11 nicklas 226         <title>Naming</title>
5673 27 Jun 11 nicklas 227         
5673 27 Jun 11 nicklas 228         <variablelist>
5673 27 Jun 11 nicklas 229         <varlistentry>
5673 27 Jun 11 nicklas 230           <term>General</term>
5673 27 Jun 11 nicklas 231           <listitem>
5673 27 Jun 11 nicklas 232             <para>
5673 27 Jun 11 nicklas 233               All names should be in English. Names should be descriptive and derived from the the
5673 27 Jun 11 nicklas 234               domain the code is intended for. Try to avoid names longer than twenty characters. 
5673 27 Jun 11 nicklas 235             </para>
5673 27 Jun 11 nicklas 236           </listitem>
5673 27 Jun 11 nicklas 237         </varlistentry>
5673 27 Jun 11 nicklas 238         
5673 27 Jun 11 nicklas 239         <varlistentry>
5673 27 Jun 11 nicklas 240           <term>Packages</term>
5673 27 Jun 11 nicklas 241           <listitem>
5673 27 Jun 11 nicklas 242             <para>
5673 27 Jun 11 nicklas 243               Package names must be in all lower case letters. The top-level package of
5673 27 Jun 11 nicklas 244               BASE is <code>net.sf.basedb</code>.
5673 27 Jun 11 nicklas 245             </para>
5673 27 Jun 11 nicklas 246           </listitem>
5673 27 Jun 11 nicklas 247         </varlistentry>
5673 27 Jun 11 nicklas 248         
5673 27 Jun 11 nicklas 249         <varlistentry>
5673 27 Jun 11 nicklas 250           <term>Classes and Interfaces</term>
5673 27 Jun 11 nicklas 251           <listitem>
5673 27 Jun 11 nicklas 252             <para>
5673 27 Jun 11 nicklas 253             Names of classes and interfaces should be a concatenation of one or more words. 
5673 27 Jun 11 nicklas 254             The initial letter of all words in the name, including the first word, should be upper case 
5673 27 Jun 11 nicklas 255             letters. The rest of the characters should be lower case. Example: 
5673 27 Jun 11 nicklas 256             </para>
5673 27 Jun 11 nicklas 257             <programlisting language="java">
5673 27 Jun 11 nicklas 258 public class SoftwareType
5673 27 Jun 11 nicklas 259 {
5673 27 Jun 11 nicklas 260    ...
5673 27 Jun 11 nicklas 261 }
5673 27 Jun 11 nicklas 262 </programlisting>
5673 27 Jun 11 nicklas 263             
5673 27 Jun 11 nicklas 264           </listitem>
5673 27 Jun 11 nicklas 265         </varlistentry>
5673 27 Jun 11 nicklas 266         
5673 27 Jun 11 nicklas 267         <varlistentry>
5673 27 Jun 11 nicklas 268           <term>Constant member variables</term>
5673 27 Jun 11 nicklas 269           <listitem>
5673 27 Jun 11 nicklas 270             <para>
5673 27 Jun 11 nicklas 271             Constant member variables, usually defined <emphasis>static final</emphasis>, should be named 
5673 27 Jun 11 nicklas 272             using all upper case characters. Words in the name should be separated by underscore characters. 
5673 27 Jun 11 nicklas 273             Example: 
5673 27 Jun 11 nicklas 274             </para>
5673 27 Jun 11 nicklas 275             <programlisting language="java">
5673 27 Jun 11 nicklas 276 public static final int VERSION_NUMBER = 3;
5673 27 Jun 11 nicklas 277 </programlisting>
5673 27 Jun 11 nicklas 278           </listitem>
5673 27 Jun 11 nicklas 279         </varlistentry>
5673 27 Jun 11 nicklas 280         
5673 27 Jun 11 nicklas 281         <varlistentry>
5673 27 Jun 11 nicklas 282           <term>Private member variables</term>
5673 27 Jun 11 nicklas 283           <listitem>
5673 27 Jun 11 nicklas 284             <para>
5673 27 Jun 11 nicklas 285             Private member variables should be a concatenation of one or more descriptive words. 
5673 27 Jun 11 nicklas 286             The initial letter of all words in the name, except the first word, should be upper 
5673 27 Jun 11 nicklas 287             case letters. The rest of the characters should be lower case. Example: 
5673 27 Jun 11 nicklas 288             </para>
5673 27 Jun 11 nicklas 289             <programlisting language="java">
5673 27 Jun 11 nicklas 290 private String loginComment;
5673 27 Jun 11 nicklas 291 </programlisting>
5673 27 Jun 11 nicklas 292           </listitem>
5673 27 Jun 11 nicklas 293         </varlistentry>
5673 27 Jun 11 nicklas 294         
5673 27 Jun 11 nicklas 295         <varlistentry>
5673 27 Jun 11 nicklas 296           <term>Methods</term>
5673 27 Jun 11 nicklas 297           <listitem>
5673 27 Jun 11 nicklas 298             <para>
5673 27 Jun 11 nicklas 299             Methods should be named using a descriptive statement, usually made up by several words. 
5673 27 Jun 11 nicklas 300             Typically the first word is a verb, stating the action and the others stating the target 
5673 27 Jun 11 nicklas 301             and attributes. Lower and upper case letters should then be mixed, with all words in the 
5673 27 Jun 11 nicklas 302             name except the first one starting with an upper case letter and the rest being in 
5673 27 Jun 11 nicklas 303             lower case letters. Example: 
5673 27 Jun 11 nicklas 304             </para>
5673 27 Jun 11 nicklas 305             <programlisting language="java">
5673 27 Jun 11 nicklas 306 <![CDATA[
6912 20 May 15 nicklas 307 public ItemQuery<Annotation> getInheritedAnnotations()
5673 27 Jun 11 nicklas 308 {
5673 27 Jun 11 nicklas 309    ...
5673 27 Jun 11 nicklas 310 }
5673 27 Jun 11 nicklas 311 ]]>
5673 27 Jun 11 nicklas 312 </programlisting>
5673 27 Jun 11 nicklas 313           </listitem>
5673 27 Jun 11 nicklas 314         </varlistentry>
5673 27 Jun 11 nicklas 315         
5673 27 Jun 11 nicklas 316         <varlistentry>
5673 27 Jun 11 nicklas 317           <term>Mutator (get/set) methods</term>
5673 27 Jun 11 nicklas 318           <listitem>
5673 27 Jun 11 nicklas 319             <para>
5673 27 Jun 11 nicklas 320             Avoid direct access to attributes (member variables) from outside of a class. 
5673 27 Jun 11 nicklas 321             Instead make attributes private and use mutator methods to access them. Prefix 
5673 27 Jun 11 nicklas 322             the mutator methods with get and set respectively to fetch or change an attribute. 
5673 27 Jun 11 nicklas 323             If the getter returns a boolean value prefix the mutator method with (typically) 
5673 27 Jun 11 nicklas 324             is, has or can. Examples: 
5673 27 Jun 11 nicklas 325             </para>
5673 27 Jun 11 nicklas 326             <programlisting language="java">
5673 27 Jun 11 nicklas 327 private String name;
5673 27 Jun 11 nicklas 328 public String getName()
5673 27 Jun 11 nicklas 329 {
5673 27 Jun 11 nicklas 330    return name;
5673 27 Jun 11 nicklas 331 }
5673 27 Jun 11 nicklas 332 public void setName(String name)
5673 27 Jun 11 nicklas 333 {
5673 27 Jun 11 nicklas 334   this.name = name;
5673 27 Jun 11 nicklas 335 }
5673 27 Jun 11 nicklas 336
5673 27 Jun 11 nicklas 337 private boolean activated;
5673 27 Jun 11 nicklas 338 public boolean isActivated()
5673 27 Jun 11 nicklas 339 {
5673 27 Jun 11 nicklas 340    return activated;
5673 27 Jun 11 nicklas 341 }
5673 27 Jun 11 nicklas 342 </programlisting>
5673 27 Jun 11 nicklas 343             
5673 27 Jun 11 nicklas 344           </listitem>
5673 27 Jun 11 nicklas 345         </varlistentry>
5673 27 Jun 11 nicklas 346
5673 27 Jun 11 nicklas 347         <varlistentry>
5673 27 Jun 11 nicklas 348           <term>Exceptions</term>
5673 27 Jun 11 nicklas 349           <listitem>
5673 27 Jun 11 nicklas 350             <para>
5673 27 Jun 11 nicklas 351             The names of Exceptions must end with the word <emphasis>Exception</emphasis>. 
5673 27 Jun 11 nicklas 352             Example: 
5673 27 Jun 11 nicklas 353             </para>
5673 27 Jun 11 nicklas 354             <programlisting language="java">
5673 27 Jun 11 nicklas 355 public class NoMoreNumbersException
5673 27 Jun 11 nicklas 356    extends Exception
5673 27 Jun 11 nicklas 357 {
5673 27 Jun 11 nicklas 358    ...
5673 27 Jun 11 nicklas 359 }
5673 27 Jun 11 nicklas 360 </programlisting>
5673 27 Jun 11 nicklas 361           </listitem>
5673 27 Jun 11 nicklas 362         </varlistentry>
5673 27 Jun 11 nicklas 363       </variablelist>
5673 27 Jun 11 nicklas 364       
5673 27 Jun 11 nicklas 365     </sect3>
5673 27 Jun 11 nicklas 366     
5673 27 Jun 11 nicklas 367     <sect3 id="core_ref.rules.layout">
5673 27 Jun 11 nicklas 368       <title>Layout and comments</title>
5673 27 Jun 11 nicklas 369     
5673 27 Jun 11 nicklas 370       <variablelist>
5673 27 Jun 11 nicklas 371         <varlistentry>
5673 27 Jun 11 nicklas 372           <term>Interface layout</term>
5673 27 Jun 11 nicklas 373           <listitem>
5673 27 Jun 11 nicklas 374             <para>
5673 27 Jun 11 nicklas 375             Interfaces should only have public members, i.e. static attributes and method prototypes. 
5673 27 Jun 11 nicklas 376             </para>
5673 27 Jun 11 nicklas 377           </listitem>
5673 27 Jun 11 nicklas 378         </varlistentry>
5673 27 Jun 11 nicklas 379         
5673 27 Jun 11 nicklas 380         <varlistentry>
5673 27 Jun 11 nicklas 381           <term>White space</term>
5673 27 Jun 11 nicklas 382           <listitem>
5673 27 Jun 11 nicklas 383             <para>
5673 27 Jun 11 nicklas 384             All code must be properly indented. In general each new block starts a 
5673 27 Jun 11 nicklas 385             new indentation level. Use <emphasis>tab</emphasis> when indenting. 
5673 27 Jun 11 nicklas 386             </para>
5673 27 Jun 11 nicklas 387           </listitem>
5673 27 Jun 11 nicklas 388         </varlistentry>
5673 27 Jun 11 nicklas 389         
5673 27 Jun 11 nicklas 390         <varlistentry>
5673 27 Jun 11 nicklas 391           <term>Code blocks</term>
5673 27 Jun 11 nicklas 392           <listitem>
5673 27 Jun 11 nicklas 393             <para>
5673 27 Jun 11 nicklas 394             The starting brace "{" of a code block should be placed on a line by itself at 
5673 27 Jun 11 nicklas 395             the same indentation level as the preceeding line of code. The first line in 
5673 27 Jun 11 nicklas 396             the new block should be indented one tab-stop more. The ending brace "}" 
5673 27 Jun 11 nicklas 397             should be placed at the same indentation level as the matching starting brace. 
5673 27 Jun 11 nicklas 398             Use braces even if the code block is only one line. Example: 
5673 27 Jun 11 nicklas 399             </para>
5673 27 Jun 11 nicklas 400             <programlisting language="java">
5673 27 Jun 11 nicklas 401 public String getName()
5673 27 Jun 11 nicklas 402 {
5673 27 Jun 11 nicklas 403    if (name == null)
5673 27 Jun 11 nicklas 404    {
5673 27 Jun 11 nicklas 405       return "unknown";
5673 27 Jun 11 nicklas 406    }
5673 27 Jun 11 nicklas 407    else
5673 27 Jun 11 nicklas 408    {
5673 27 Jun 11 nicklas 409       return name;
5673 27 Jun 11 nicklas 410    }
5673 27 Jun 11 nicklas 411 }
5673 27 Jun 11 nicklas 412 </programlisting>
5673 27 Jun 11 nicklas 413           </listitem>
5673 27 Jun 11 nicklas 414         </varlistentry>
5673 27 Jun 11 nicklas 415         
5673 27 Jun 11 nicklas 416         <varlistentry>
5673 27 Jun 11 nicklas 417           <term>Javadoc</term>
5673 27 Jun 11 nicklas 418           <listitem>
5673 27 Jun 11 nicklas 419             <para>
5673 27 Jun 11 nicklas 420             Packages, classes, public methods and public attributes should be commented in Javadoc style. 
5673 27 Jun 11 nicklas 421             It is recommended that private and protected methods also has some comments, but maybe not 
5673 27 Jun 11 nicklas 422             as detailed as the public ones.
5673 27 Jun 11 nicklas 423             </para>
5673 27 Jun 11 nicklas 424             
5673 27 Jun 11 nicklas 425             <itemizedlist>
5673 27 Jun 11 nicklas 426               <listitem>All comments should be in English.</listitem>
5673 27 Jun 11 nicklas 427               <listitem>Do not start each line of a comment with a star.</listitem>
5673 27 Jun 11 nicklas 428             </itemizedlist>
5673 27 Jun 11 nicklas 429             
5673 27 Jun 11 nicklas 430             <para>
5673 27 Jun 11 nicklas 431               More info about Javadoc can be found at: <ulink 
5673 27 Jun 11 nicklas 432                 url="http://www.oracle.com/technetwork/java/javase/documentation/index-137868.html"
5673 27 Jun 11 nicklas 433                 >http://www.oracle.com/technetwork/java/javase/documentation/index-137868.html</ulink>
5673 27 Jun 11 nicklas 434             </para>
5673 27 Jun 11 nicklas 435           </listitem>
5673 27 Jun 11 nicklas 436         </varlistentry>
5673 27 Jun 11 nicklas 437         
5673 27 Jun 11 nicklas 438         <varlistentry>
5673 27 Jun 11 nicklas 439           <term>Package comments</term>
5673 27 Jun 11 nicklas 440           <listitem>
5673 27 Jun 11 nicklas 441             <para>
5673 27 Jun 11 nicklas 442             Place package comments in a file named <filename>package.html</filename> in the 
5673 27 Jun 11 nicklas 443             source code directory.
5673 27 Jun 11 nicklas 444             </para>
5673 27 Jun 11 nicklas 445           </listitem>
5673 27 Jun 11 nicklas 446         </varlistentry>
5673 27 Jun 11 nicklas 447         
5673 27 Jun 11 nicklas 448         <varlistentry>
5673 27 Jun 11 nicklas 449           <term>Class comments</term>
5673 27 Jun 11 nicklas 450           <listitem>
5673 27 Jun 11 nicklas 451             <para>
5673 27 Jun 11 nicklas 452             A class comment should start with a general description of the class and what it does. 
5673 27 Jun 11 nicklas 453             Use the <code>@author</code> tag to specify the names of the programmers that was involved
5673 27 Jun 11 nicklas 454             in coding the file and the <code>@since</code> tag to specify the version of BASE when the
5673 27 Jun 11 nicklas 455             class first appeared. Example:
5673 27 Jun 11 nicklas 456             </para>
5673 27 Jun 11 nicklas 457             <programlisting language="java">
5673 27 Jun 11 nicklas 458 /**
5673 27 Jun 11 nicklas 459    ...
5673 27 Jun 11 nicklas 460    @author Nicklas, Martin
5673 27 Jun 11 nicklas 461    @since 2.0
5673 27 Jun 11 nicklas 462 */
5673 27 Jun 11 nicklas 463 public class BasicItem
5673 27 Jun 11 nicklas 464 {
5673 27 Jun 11 nicklas 465   ...
5673 27 Jun 11 nicklas 466 }
5673 27 Jun 11 nicklas 467 </programlisting>
5673 27 Jun 11 nicklas 468           </listitem>
5673 27 Jun 11 nicklas 469         </varlistentry>
5673 27 Jun 11 nicklas 470         
5673 27 Jun 11 nicklas 471         <varlistentry>
5673 27 Jun 11 nicklas 472           <term>Method comments</term>
5673 27 Jun 11 nicklas 473           <listitem>
5673 27 Jun 11 nicklas 474             <para>
5673 27 Jun 11 nicklas 475             A method comment should start with a general description of the method and what it does. 
5673 27 Jun 11 nicklas 476             Use <code>@param</code> to describe each parameter and <code>@return</code> to describe
5673 27 Jun 11 nicklas 477             what the method returns. Use <code>@throws</code> to describe all checked exceptions
5673 27 Jun 11 nicklas 478             including when and why they can be thrown. Use <code>@see</code> to link to other related 
5673 27 Jun 11 nicklas 479             method and information.
5673 27 Jun 11 nicklas 480             </para>
5673 27 Jun 11 nicklas 481           </listitem>
5673 27 Jun 11 nicklas 482         </varlistentry>
5673 27 Jun 11 nicklas 483         
5673 27 Jun 11 nicklas 484         <varlistentry>
5673 27 Jun 11 nicklas 485           <term>Attribute comments</term>
5673 27 Jun 11 nicklas 486           <listitem>
5673 27 Jun 11 nicklas 487             <para>
5673 27 Jun 11 nicklas 488             If it is a static final attribute, describe what the attribute is for and where it is typically used. 
5673 27 Jun 11 nicklas 489             </para>
5673 27 Jun 11 nicklas 490           </listitem>
5673 27 Jun 11 nicklas 491         </varlistentry>
5673 27 Jun 11 nicklas 492         
5673 27 Jun 11 nicklas 493         <varlistentry>
5673 27 Jun 11 nicklas 494           <term>@base.developer</term>
5673 27 Jun 11 nicklas 495           <listitem>
5673 27 Jun 11 nicklas 496             <para>
5673 27 Jun 11 nicklas 497             The <code>@base.developer</code> tag can be used anywhere to add comments that are
5673 27 Jun 11 nicklas 498             mainly targeted to the developers of BASE.
5673 27 Jun 11 nicklas 499             </para>
5673 27 Jun 11 nicklas 500           </listitem>
5673 27 Jun 11 nicklas 501         </varlistentry>
5673 27 Jun 11 nicklas 502
5673 27 Jun 11 nicklas 503         <varlistentry>
5673 27 Jun 11 nicklas 504           <term>@base.internal</term>
5673 27 Jun 11 nicklas 505           <listitem>
5673 27 Jun 11 nicklas 506             <para>
5673 27 Jun 11 nicklas 507             The <code>@base.internal</code> tag can be used at package and class-level
5673 27 Jun 11 nicklas 508             documentation to mark that part of the code as an internal API that should
5673 27 Jun 11 nicklas 509             not be used by plug-ins and other client code. See
5780 04 Oct 11 nicklas 510             <xref linkend="base_api.public" />.
5673 27 Jun 11 nicklas 511             </para>
5673 27 Jun 11 nicklas 512           </listitem>
5673 27 Jun 11 nicklas 513         </varlistentry>
5673 27 Jun 11 nicklas 514         
5673 27 Jun 11 nicklas 515         <varlistentry>
5673 27 Jun 11 nicklas 516           <term>Inline comments</term>
5673 27 Jun 11 nicklas 517           <listitem>
5673 27 Jun 11 nicklas 518             <itemizedlist>
5673 27 Jun 11 nicklas 519               <listitem>All comments should be in English.</listitem>
5673 27 Jun 11 nicklas 520               <listitem>
5673 27 Jun 11 nicklas 521                 Comment on why instead of what. Your code should be 
5673 27 Jun 11 nicklas 522                 clear enough to answer questions on what it does. It is more 
5673 27 Jun 11 nicklas 523                 important to document why it does it.
5673 27 Jun 11 nicklas 524               </listitem>
5673 27 Jun 11 nicklas 525               <listitem>Do not place end line comments at the end of statements.</listitem>
5673 27 Jun 11 nicklas 526                <listitem>
5673 27 Jun 11 nicklas 527                 Do not use decorated banner like comments, as these are hard to maintain. 
5673 27 Jun 11 nicklas 528                  If more extensive commenting is needed - use Javadoc.
5673 27 Jun 11 nicklas 529               </listitem>
5689 11 Aug 11 nicklas 530               <listitem>
5689 11 Aug 11 nicklas 531                 Avoid using semicolon (;) as part of inline comments. Searching for all
5689 11 Aug 11 nicklas 532                 comments containing a semicolon is used to find commented out code blocks.
5689 11 Aug 11 nicklas 533               </listitem>
5673 27 Jun 11 nicklas 534             </itemizedlist>
5673 27 Jun 11 nicklas 535           
5673 27 Jun 11 nicklas 536           </listitem>
5673 27 Jun 11 nicklas 537         </varlistentry>
5673 27 Jun 11 nicklas 538         
5673 27 Jun 11 nicklas 539         <varlistentry>
5689 11 Aug 11 nicklas 540           <term>Commented out code</term>
5689 11 Aug 11 nicklas 541           <listitem>
5689 11 Aug 11 nicklas 542             <para>
5689 11 Aug 11 nicklas 543             Avoid leaving code that is commented out. It is a distraction when
5689 11 Aug 11 nicklas 544             maintaining the code. Sometimes, for example during a big refactoring,
5689 11 Aug 11 nicklas 545             it is not possible to fix everything at once. In this case it is allowed
5689 11 Aug 11 nicklas 546             to comment out code, but it is recommended that a <emphasis>TODO</emphasis>
5689 11 Aug 11 nicklas 547             marker (see below) is added to make it easier to find places that 
5689 11 Aug 11 nicklas 548             need to be fixed later.
5689 11 Aug 11 nicklas 549             </para>
5689 11 Aug 11 nicklas 550           </listitem>
5689 11 Aug 11 nicklas 551         </varlistentry>
5689 11 Aug 11 nicklas 552         
5689 11 Aug 11 nicklas 553         <varlistentry>
5673 27 Jun 11 nicklas 554           <term>Todo comments</term>
5673 27 Jun 11 nicklas 555           <listitem>
5673 27 Jun 11 nicklas 556             <para>
5673 27 Jun 11 nicklas 557             If there are parts of the code that cannot be completed at the time the majority of the code 
5673 27 Jun 11 nicklas 558             is written, place a comment starting with TODO (in capital letters), followed with a 
5689 11 Aug 11 nicklas 559             description of what needs to be done. If there is a ticket in the Trac server, use the
5689 11 Aug 11 nicklas 560             ticket number in the comment. Example: 
5673 27 Jun 11 nicklas 561             </para>
5673 27 Jun 11 nicklas 562             <programlisting language="java">
5673 27 Jun 11 nicklas 563 public static Date copy(Date value)
5673 27 Jun 11 nicklas 564 {
5673 27 Jun 11 nicklas 565    return value == null ? null : new Date(value.getTime());
5689 11 Aug 11 nicklas 566    // TODO (#1234): check if there is a better way to copy
5673 27 Jun 11 nicklas 567 }
5673 27 Jun 11 nicklas 568 </programlisting>
5673 27 Jun 11 nicklas 569           </listitem>
5673 27 Jun 11 nicklas 570         </varlistentry>
5673 27 Jun 11 nicklas 571         
5673 27 Jun 11 nicklas 572         <varlistentry>
5673 27 Jun 11 nicklas 573           <term>Subversion comment and GNU licence message</term>
5673 27 Jun 11 nicklas 574           <listitem>
5673 27 Jun 11 nicklas 575             <para>
5673 27 Jun 11 nicklas 576             Each file should start with a subversion comment and the GNU licence and copyright message. 
5673 27 Jun 11 nicklas 577             Non-java files should also include this information, in a format appropriate for the 
5673 27 Jun 11 nicklas 578             specific file. 
5673 27 Jun 11 nicklas 579             </para>
5673 27 Jun 11 nicklas 580             <programlisting language="java">
5673 27 Jun 11 nicklas 581 <![CDATA[
5673 27 Jun 11 nicklas 582 /*
5673 27 Jun 11 nicklas 583    $Id$
5673 27 Jun 11 nicklas 584
5673 27 Jun 11 nicklas 585    Copyright (C) Authors contributing to this file.
5673 27 Jun 11 nicklas 586
5673 27 Jun 11 nicklas 587    This file is part of BASE - BioArray Software Environment.
7982 14 Jun 21 nicklas 588    Available at https://base.thep.lu.se/
5673 27 Jun 11 nicklas 589
5673 27 Jun 11 nicklas 590    BASE is free software; you can redistribute it and/or
5673 27 Jun 11 nicklas 591    modify it under the terms of the GNU General Public License
5673 27 Jun 11 nicklas 592    as published by the Free Software Foundation; either version 3
5673 27 Jun 11 nicklas 593    of the License, or (at your option) any later version.
5673 27 Jun 11 nicklas 594
5673 27 Jun 11 nicklas 595    BASE is distributed in the hope that it will be useful,
5673 27 Jun 11 nicklas 596    but WITHOUT ANY WARRANTY; without even the implied warranty of
5673 27 Jun 11 nicklas 597    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5673 27 Jun 11 nicklas 598    GNU General Public License for more details.
5673 27 Jun 11 nicklas 599
5673 27 Jun 11 nicklas 600    You should have received a copy of the GNU General Public License
5673 27 Jun 11 nicklas 601    along with BASE. If not, see <http://www.gnu.org/licenses/>.
5673 27 Jun 11 nicklas 602 */
5673 27 Jun 11 nicklas 603 ]]>
5673 27 Jun 11 nicklas 604 </programlisting>
5673 27 Jun 11 nicklas 605           </listitem>
5673 27 Jun 11 nicklas 606         </varlistentry>
5673 27 Jun 11 nicklas 607         </variablelist>
5673 27 Jun 11 nicklas 608         
5673 27 Jun 11 nicklas 609       </sect3>
5673 27 Jun 11 nicklas 610
5673 27 Jun 11 nicklas 611     <sect3 id="core_ref.rules.statements">
5673 27 Jun 11 nicklas 612       <title>Statements</title>
5673 27 Jun 11 nicklas 613
5673 27 Jun 11 nicklas 614         <variablelist>        
5673 27 Jun 11 nicklas 615         <varlistentry>
5673 27 Jun 11 nicklas 616           <term>Package and import statements</term>
5673 27 Jun 11 nicklas 617           <listitem>
5673 27 Jun 11 nicklas 618             <para>
5673 27 Jun 11 nicklas 619             The package statement is the first statement to appear in the source file. All declared classes 
5673 27 Jun 11 nicklas 620             must belong to a named package. It is not allowed for classes to belong to the "default" package, 
5673 27 Jun 11 nicklas 621             i.e. to omit the package statement in the source file. Exception: Test code may belong to the 
5673 27 Jun 11 nicklas 622             default package.
5673 27 Jun 11 nicklas 623             </para>
5673 27 Jun 11 nicklas 624             
5673 27 Jun 11 nicklas 625             <para>
5673 27 Jun 11 nicklas 626             Import statements should follow directly after the package statement. Try to avoid 
5673 27 Jun 11 nicklas 627             preceeding class names in code with package names. Instead use import statements.
5673 27 Jun 11 nicklas 628             </para>
5673 27 Jun 11 nicklas 629             
5673 27 Jun 11 nicklas 630             <para>
5673 27 Jun 11 nicklas 631             Wildcards in import statements make it difficult to see dependencies, 
5673 27 Jun 11 nicklas 632             other than those to packages. Therefore import classes/interfaces explicitely. 
5673 27 Jun 11 nicklas 633             The only exception is when classes in subpackages to the current package are accessed. 
5673 27 Jun 11 nicklas 634             Such items are either imported explicitely or the whole subpackage may be imported with 
5673 27 Jun 11 nicklas 635             wildcard. However, avoid wildcard imports when subpackages are large - more than approximately 
5673 27 Jun 11 nicklas 636             4 items.
5673 27 Jun 11 nicklas 637             </para>
5673 27 Jun 11 nicklas 638             
5673 27 Jun 11 nicklas 639             <para>
5673 27 Jun 11 nicklas 640             Do not explicitely import packages or classes not used in your program code.
5673 27 Jun 11 nicklas 641             Try to maintain an alphabetical order among the imported classes. Group 
5673 27 Jun 11 nicklas 642             classes from the same package. Most IDE:s have functionality for maintaining
5673 27 Jun 11 nicklas 643             import statements. Use it.
5673 27 Jun 11 nicklas 644             </para>
5673 27 Jun 11 nicklas 645             
5673 27 Jun 11 nicklas 646           </listitem>
5673 27 Jun 11 nicklas 647         </varlistentry>
5673 27 Jun 11 nicklas 648         
5673 27 Jun 11 nicklas 649         <varlistentry>
5673 27 Jun 11 nicklas 650           <term>Inside a class, attributes and methods should be organised in the following order:</term>
5673 27 Jun 11 nicklas 651           <listitem>
5673 27 Jun 11 nicklas 652             <itemizedlist>
5673 27 Jun 11 nicklas 653               <listitem>public static final attributes</listitem>
5673 27 Jun 11 nicklas 654               <listitem>other static attributes</listitem>
5673 27 Jun 11 nicklas 655               <listitem>public static methods</listitem>
5673 27 Jun 11 nicklas 656               <listitem>other static methods</listitem>
5673 27 Jun 11 nicklas 657               <listitem>private attributes</listitem>
5673 27 Jun 11 nicklas 658               <listitem>constructors</listitem>
5673 27 Jun 11 nicklas 659               <listitem>Methods defined by interfaces, grouped by the interface in which they are defined</listitem>
5673 27 Jun 11 nicklas 660               <listitem>Methods that override a method from a superclass, with methods from the topmost superclass first</listitem>
5673 27 Jun 11 nicklas 661               <listitem>Additional methods for the specific class</listitem>
5673 27 Jun 11 nicklas 662             </itemizedlist>
5673 27 Jun 11 nicklas 663           </listitem>
5673 27 Jun 11 nicklas 664         </varlistentry>
5673 27 Jun 11 nicklas 665         
5673 27 Jun 11 nicklas 666         <varlistentry>
5673 27 Jun 11 nicklas 667           <term>Classes and interfaces</term>
5673 27 Jun 11 nicklas 668           <listitem>
5673 27 Jun 11 nicklas 669             <para>
5673 27 Jun 11 nicklas 670             Class and interface statements should be organized in the following manner:
5673 27 Jun 11 nicklas 671             </para>
5673 27 Jun 11 nicklas 672             
5673 27 Jun 11 nicklas 673             <itemizedlist>
5673 27 Jun 11 nicklas 674               <listitem>class or interface statement</listitem>
5673 27 Jun 11 nicklas 675               <listitem>extends statement indented on a separate row</listitem>
5673 27 Jun 11 nicklas 676               <listitem>implements statement indented on one or more rows</listitem>
5673 27 Jun 11 nicklas 677               <listitem>class body</listitem>
5673 27 Jun 11 nicklas 678             </itemizedlist>
5673 27 Jun 11 nicklas 679             <programlisting language="java">
5673 27 Jun 11 nicklas 680 public class SomeClass
5673 27 Jun 11 nicklas 681    extends SomeBase
5673 27 Jun 11 nicklas 682    implements Clonable, SomeInterface
5673 27 Jun 11 nicklas 683 {
5673 27 Jun 11 nicklas 684    ...
5673 27 Jun 11 nicklas 685 }
5673 27 Jun 11 nicklas 686
5673 27 Jun 11 nicklas 687 public interface Testable
5673 27 Jun 11 nicklas 688    extends Clonable
5673 27 Jun 11 nicklas 689 {
5673 27 Jun 11 nicklas 690    ...
5673 27 Jun 11 nicklas 691 }
5673 27 Jun 11 nicklas 692 </programlisting>
5673 27 Jun 11 nicklas 693
5673 27 Jun 11 nicklas 694           </listitem>
5673 27 Jun 11 nicklas 695         </varlistentry>
5673 27 Jun 11 nicklas 696         
5673 27 Jun 11 nicklas 697         <varlistentry>
5673 27 Jun 11 nicklas 698           <term>Methods</term>
5673 27 Jun 11 nicklas 699           <listitem>
5673 27 Jun 11 nicklas 700             <para>
5673 27 Jun 11 nicklas 701             If a method throws checked exceptions, these should be declared indented on a separate row directly 
5673 27 Jun 11 nicklas 702             after the method declaration. Example: 
5673 27 Jun 11 nicklas 703             </para>
5673 27 Jun 11 nicklas 704             <programlisting language="java">
5673 27 Jun 11 nicklas 705 public int getNextValue(int previousValue)
5673 27 Jun 11 nicklas 706    throws NoMoreValuesException
5673 27 Jun 11 nicklas 707 {
5673 27 Jun 11 nicklas 708    ...
5673 27 Jun 11 nicklas 709 }
5673 27 Jun 11 nicklas 710 </programlisting>
5673 27 Jun 11 nicklas 711           </listitem>
5673 27 Jun 11 nicklas 712         </varlistentry>
5673 27 Jun 11 nicklas 713         
5673 27 Jun 11 nicklas 714         <varlistentry>
5673 27 Jun 11 nicklas 715           <term>Local variables</term>
5673 27 Jun 11 nicklas 716           <listitem>
5673 27 Jun 11 nicklas 717             <para>
5673 27 Jun 11 nicklas 718             Local variables should be declared and initialized where they are used. 
5673 27 Jun 11 nicklas 719             They should be declared in the smallest possible scope. Avoid overloading 
5673 27 Jun 11 nicklas 720             variable names in inner blocks. 
5673 27 Jun 11 nicklas 721             </para>
5673 27 Jun 11 nicklas 722           </listitem>
5673 27 Jun 11 nicklas 723         </varlistentry>
5673 27 Jun 11 nicklas 724         
5673 27 Jun 11 nicklas 725         <varlistentry>
5673 27 Jun 11 nicklas 726           <term>Array declarations</term>
5673 27 Jun 11 nicklas 727           <listitem>
5673 27 Jun 11 nicklas 728             <para>
5673 27 Jun 11 nicklas 729             The square brackets indicating an array of something should be immediately to 
5673 27 Jun 11 nicklas 730             the right of whatever class or datatype the array consists of 
5673 27 Jun 11 nicklas 731             (e.g. <code>String[] args</code>) do not use C-style array declarations 
5673 27 Jun 11 nicklas 732             (<code>String args[]</code>). 
5673 27 Jun 11 nicklas 733             </para>
5673 27 Jun 11 nicklas 734           </listitem>
5673 27 Jun 11 nicklas 735         </varlistentry>
5673 27 Jun 11 nicklas 736         
5673 27 Jun 11 nicklas 737         <varlistentry>
5673 27 Jun 11 nicklas 738           <term>Conditional statements</term>
5673 27 Jun 11 nicklas 739           <listitem>
5673 27 Jun 11 nicklas 740             <itemizedlist>
5673 27 Jun 11 nicklas 741               <listitem>
5673 27 Jun 11 nicklas 742               There must always be braces around the block following the condition control structure, even if it's 
5673 27 Jun 11 nicklas 743               just a single statement block. This doesn't apply to the cases when the single statement is on 
5673 27 Jun 11 nicklas 744               the same line as the condition.
5673 27 Jun 11 nicklas 745               </listitem>
5673 27 Jun 11 nicklas 746               <listitem>Avoid placing statements resulting in side effects (e.g. function calls) in the condition construct.</listitem>
5673 27 Jun 11 nicklas 747               <listitem>Do not jump out of conditional blocks with break, return or exit. The exception is the usage of break in switch-statements.</listitem>
5673 27 Jun 11 nicklas 748               <listitem>Use continue-statements in for- and while- loops with caution. It's recommended to mark the statement with a clear comment.</listitem>
5673 27 Jun 11 nicklas 749             </itemizedlist>
5673 27 Jun 11 nicklas 750             
5673 27 Jun 11 nicklas 751             <programlisting language="java">
5673 27 Jun 11 nicklas 752 // IF-statements:
5673 27 Jun 11 nicklas 753 if (...)
5673 27 Jun 11 nicklas 754 {
5673 27 Jun 11 nicklas 755    ...
5673 27 Jun 11 nicklas 756 }
5673 27 Jun 11 nicklas 757 else
5673 27 Jun 11 nicklas 758 {
5673 27 Jun 11 nicklas 759    ...
5673 27 Jun 11 nicklas 760 }
5673 27 Jun 11 nicklas 761
5673 27 Jun 11 nicklas 762 if (...) ...;
5673 27 Jun 11 nicklas 763
5673 27 Jun 11 nicklas 764
5673 27 Jun 11 nicklas 765 // FOR-statements:
5673 27 Jun 11 nicklas 766 for (init; condition; update)
5673 27 Jun 11 nicklas 767 {
5673 27 Jun 11 nicklas 768    ...
5673 27 Jun 11 nicklas 769    /* #### CONTINUE-STATEMENT #### */
5673 27 Jun 11 nicklas 770    if (...) continue;
5673 27 Jun 11 nicklas 771    ...
5673 27 Jun 11 nicklas 772 }
5673 27 Jun 11 nicklas 773
5673 27 Jun 11 nicklas 774 // WHILE-statement:
5673 27 Jun 11 nicklas 775 while (condition)
5673 27 Jun 11 nicklas 776 {
5673 27 Jun 11 nicklas 777    ...
5673 27 Jun 11 nicklas 778 }
5673 27 Jun 11 nicklas 779
5673 27 Jun 11 nicklas 780 // DO-WHILE-statement:
5673 27 Jun 11 nicklas 781 do
5673 27 Jun 11 nicklas 782 {
5673 27 Jun 11 nicklas 783    ...
5673 27 Jun 11 nicklas 784 }
5673 27 Jun 11 nicklas 785 while (condition);
5673 27 Jun 11 nicklas 786
5673 27 Jun 11 nicklas 787 // SWITCH-statement:
5673 27 Jun 11 nicklas 788 switch (operand)
5673 27 Jun 11 nicklas 789 {
5673 27 Jun 11 nicklas 790    case: ...
5673 27 Jun 11 nicklas 791    {
5673 27 Jun 11 nicklas 792       ...
5673 27 Jun 11 nicklas 793       break;
5673 27 Jun 11 nicklas 794    }
5673 27 Jun 11 nicklas 795    default:
5673 27 Jun 11 nicklas 796    {
5673 27 Jun 11 nicklas 797       ...
5673 27 Jun 11 nicklas 798    }
5673 27 Jun 11 nicklas 799 }
5673 27 Jun 11 nicklas 800
5673 27 Jun 11 nicklas 801
5673 27 Jun 11 nicklas 802 // Exception blocks:
5673 27 Jun 11 nicklas 803 try
5673 27 Jun 11 nicklas 804 {
5673 27 Jun 11 nicklas 805    ...
5673 27 Jun 11 nicklas 806 }
5673 27 Jun 11 nicklas 807 catch (SpecialException se)
5673 27 Jun 11 nicklas 808 {
5673 27 Jun 11 nicklas 809    ...
5673 27 Jun 11 nicklas 810 }
5673 27 Jun 11 nicklas 811 catch (Exception e)
5673 27 Jun 11 nicklas 812 {
5673 27 Jun 11 nicklas 813    ...
5673 27 Jun 11 nicklas 814 }
5673 27 Jun 11 nicklas 815 finally
5673 27 Jun 11 nicklas 816 {
5673 27 Jun 11 nicklas 817    ...
5673 27 Jun 11 nicklas 818 }
5673 27 Jun 11 nicklas 819 </programlisting>
5673 27 Jun 11 nicklas 820           </listitem>
5673 27 Jun 11 nicklas 821         </varlistentry>      
5673 27 Jun 11 nicklas 822         </variablelist>        
5673 27 Jun 11 nicklas 823       </sect3>
5673 27 Jun 11 nicklas 824
3409 30 May 07 nicklas 825     </sect2>
3409 30 May 07 nicklas 826   
3315 09 May 07 nicklas 827     <sect2 id="core_ref.rules.compatibility">
3315 09 May 07 nicklas 828       <title>API changes and backwards compatibility</title>
3315 09 May 07 nicklas 829       <para>
3487 13 Jun 07 peter 830         The main rule is to do not introduce any changes that are
3409 30 May 07 nicklas 831         backwards incompatible. That is, existing client applications 
3409 30 May 07 nicklas 832         and plug-ins should continue to run in the next release of BASE,
3409 30 May 07 nicklas 833         without the need to change them. It may sound easy but there are
5673 27 Jun 11 nicklas 834         many things to watch out for. There is a great article about this subject on <ulink 
3409 30 May 07 nicklas 835         url="http://wiki.eclipse.org/index.php/Evolving_Java-based_APIs"
3409 30 May 07 nicklas 836           >http://wiki.eclipse.org/index.php/Evolving_Java-based_APIs</ulink>.
3409 30 May 07 nicklas 837       </para>
3409 30 May 07 nicklas 838       
3409 30 May 07 nicklas 839       
5673 27 Jun 11 nicklas 840       <variablelist>
5673 27 Jun 11 nicklas 841         <varlistentry>
5673 27 Jun 11 nicklas 842           <term>The Public API</term>
5673 27 Jun 11 nicklas 843           <listitem>
5673 27 Jun 11 nicklas 844             <para>
5673 27 Jun 11 nicklas 845             Not all code in BASE is considered to be part of the public
5780 04 Oct 11 nicklas 846             API. See <xref linkend="base_api.public" /> and
5673 27 Jun 11 nicklas 847             <ulink url="../../../api/index.html">the javadoc</ulink> 
5673 27 Jun 11 nicklas 848             for information about the public API. Changes made to
5673 27 Jun 11 nicklas 849             the internal API does not have to follow the same rules.
5673 27 Jun 11 nicklas 850             </para>
5673 27 Jun 11 nicklas 851           </listitem>
5673 27 Jun 11 nicklas 852         </varlistentry>
3409 30 May 07 nicklas 853         
5673 27 Jun 11 nicklas 854         <varlistentry>
5673 27 Jun 11 nicklas 855           <term>Binary compatibility</term>
5673 27 Jun 11 nicklas 856           <listitem>
5673 27 Jun 11 nicklas 857             <para>
5673 27 Jun 11 nicklas 858             This is hardest requirement and means that existing binaries must run
5673 27 Jun 11 nicklas 859             with the updated BASE version. The Eclipse document discusses this 
5673 27 Jun 11 nicklas 860             type of compatibility in great detail.
5673 27 Jun 11 nicklas 861             </para>
5673 27 Jun 11 nicklas 862           </listitem>
5673 27 Jun 11 nicklas 863         </varlistentry>
5673 27 Jun 11 nicklas 864
5673 27 Jun 11 nicklas 865         <varlistentry>
5673 27 Jun 11 nicklas 866           <term>Contract compatibility</term>
5673 27 Jun 11 nicklas 867           <listitem>
5673 27 Jun 11 nicklas 868             <para>
5673 27 Jun 11 nicklas 869             Methods should continue to do things in the same ways as before. Avoid
5673 27 Jun 11 nicklas 870             introducing side-effects and expanding/contracting the allowed range
5673 27 Jun 11 nicklas 871             of return or parameter values. This may not always be easy to keep this
5673 27 Jun 11 nicklas 872             type of compatibility. For example, adding a new option to an enumeration
5673 27 Jun 11 nicklas 873             may break code that is not prepared for it.
5673 27 Jun 11 nicklas 874             </para>
5673 27 Jun 11 nicklas 875           </listitem>
5673 27 Jun 11 nicklas 876         </varlistentry>
5673 27 Jun 11 nicklas 877
5673 27 Jun 11 nicklas 878         <varlistentry>
5673 27 Jun 11 nicklas 879           <term>Internal data structure compatibility</term>
5673 27 Jun 11 nicklas 880           <listitem>
5673 27 Jun 11 nicklas 881             <para>
5673 27 Jun 11 nicklas 882             It may not be possible to keep the internal data structures. If they change the
5673 27 Jun 11 nicklas 883             update script should convert the old data to the new format. Avoid exposing
5673 27 Jun 11 nicklas 884             the internal data structure to client applications. Use wrapper classes, etc,
5673 27 Jun 11 nicklas 885             to hide as much as possible. 
5673 27 Jun 11 nicklas 886             </para>
5673 27 Jun 11 nicklas 887           </listitem>
5673 27 Jun 11 nicklas 888         </varlistentry>
5673 27 Jun 11 nicklas 889
5673 27 Jun 11 nicklas 890         <varlistentry>
5673 27 Jun 11 nicklas 891           <term>Source code compatibility</term>
5673 27 Jun 11 nicklas 892           <listitem>
5673 27 Jun 11 nicklas 893             <para>
5673 27 Jun 11 nicklas 894             This is not an important issue and in most cases the problems are easy to fix. 
5673 27 Jun 11 nicklas 895             </para>
5673 27 Jun 11 nicklas 896           </listitem>
5673 27 Jun 11 nicklas 897         </varlistentry>
3409 30 May 07 nicklas 898       
5673 27 Jun 11 nicklas 899       </variablelist>
3409 30 May 07 nicklas 900       
5673 27 Jun 11 nicklas 901       <important>
5673 27 Jun 11 nicklas 902         <title>Do not forget to log changes!</title>
3409 30 May 07 nicklas 903         <para>
5673 27 Jun 11 nicklas 904         Any change that may affect backwards compatibility must be logged in
5673 27 Jun 11 nicklas 905         <xref linkend="appendix.incompatible" />.
3409 30 May 07 nicklas 906         </para>
5673 27 Jun 11 nicklas 907       </important>
5673 27 Jun 11 nicklas 908   
3409 30 May 07 nicklas 909     </sect2>
3409 30 May 07 nicklas 910     
3315 09 May 07 nicklas 911     <sect2 id="core_ref.rules.datalayer">
3315 09 May 07 nicklas 912       <title>Data-layer rules</title>
3715 11 Sep 07 nicklas 913
3315 09 May 07 nicklas 914       <para>
3715 11 Sep 07 nicklas 915         The coding guidelines for this package has been slightly modified from the 
3715 11 Sep 07 nicklas 916         the general coding guidelines. Here is a short list with the changes.
3315 09 May 07 nicklas 917       </para>
3715 11 Sep 07 nicklas 918       
5673 27 Jun 11 nicklas 919       <variablelist>
5673 27 Jun 11 nicklas 920         <varlistentry>
5673 27 Jun 11 nicklas 921           <term>Class and interface names</term>
5673 27 Jun 11 nicklas 922           <listitem>
5673 27 Jun 11 nicklas 923             <para>
5673 27 Jun 11 nicklas 924               Class names should follow the general guidelines, but should in most
5673 27 Jun 11 nicklas 925               cases end with <classname>Data</classname>.
5673 27 Jun 11 nicklas 926             </para>
5673 27 Jun 11 nicklas 927             <programlisting language="java">
5673 27 Jun 11 nicklas 928 public class SampleData
5673 27 Jun 11 nicklas 929    extends CommonData
5673 27 Jun 11 nicklas 930    implements DiskConsumableData
5673 27 Jun 11 nicklas 931 {
5673 27 Jun 11 nicklas 932    ...
5673 27 Jun 11 nicklas 933 }
5673 27 Jun 11 nicklas 934 </programlisting>
5673 27 Jun 11 nicklas 935           </listitem>
5673 27 Jun 11 nicklas 936         </varlistentry>
5673 27 Jun 11 nicklas 937
5673 27 Jun 11 nicklas 938         <varlistentry>
5673 27 Jun 11 nicklas 939           <term>Attributes and methods order</term>
5673 27 Jun 11 nicklas 940           <listitem>
5673 27 Jun 11 nicklas 941             <para>
5673 27 Jun 11 nicklas 942               Inside a class, attributes and methods should be organised in related groups, 
5673 27 Jun 11 nicklas 943               ie. the private attribute is together with the getter and setter methods that uses 
5673 27 Jun 11 nicklas 944               that attribute. This makes it easy to re-use existing code with copy-and-paste
5673 27 Jun 11 nicklas 945               operations.
5673 27 Jun 11 nicklas 946             </para>
5673 27 Jun 11 nicklas 947             <programlisting language="java">
3715 11 Sep 07 nicklas 948 public static int long MAX_ADDRESS_LENGTH = 255;
3715 11 Sep 07 nicklas 949 private String address;
3715 11 Sep 07 nicklas 950 /**
3715 11 Sep 07 nicklas 951    @hibernate.property column="`address`" type="string" length="255" not-null="false"
3715 11 Sep 07 nicklas 952 */
3715 11 Sep 07 nicklas 953 public String getAddress()
3715 11 Sep 07 nicklas 954 {
3715 11 Sep 07 nicklas 955    return address;
3715 11 Sep 07 nicklas 956 }
3715 11 Sep 07 nicklas 957 public void setAddress(String address)
3715 11 Sep 07 nicklas 958 {
3715 11 Sep 07 nicklas 959    this.address = address;
3715 11 Sep 07 nicklas 960 }
3715 11 Sep 07 nicklas 961
3715 11 Sep 07 nicklas 962 private int row;
3715 11 Sep 07 nicklas 963 /**
3715 11 Sep 07 nicklas 964    @hibernate.property column="`row`" type="int"
3715 11 Sep 07 nicklas 965 */
3715 11 Sep 07 nicklas 966 public int getRow()
3715 11 Sep 07 nicklas 967 {
3715 11 Sep 07 nicklas 968    return row;
3715 11 Sep 07 nicklas 969 }
3715 11 Sep 07 nicklas 970 public void setRow(int row)
3715 11 Sep 07 nicklas 971 {
3715 11 Sep 07 nicklas 972    this.row = row;
3715 11 Sep 07 nicklas 973 }        
3715 11 Sep 07 nicklas 974 </programlisting>
5673 27 Jun 11 nicklas 975           </listitem>
5673 27 Jun 11 nicklas 976         </varlistentry>
3715 11 Sep 07 nicklas 977
5673 27 Jun 11 nicklas 978         <varlistentry>
5673 27 Jun 11 nicklas 979           <term>Extend/implement the basic classes and interfaces</term>
5673 27 Jun 11 nicklas 980           <listitem>
5673 27 Jun 11 nicklas 981             <para>
5673 27 Jun 11 nicklas 982             Each data-class must inherit from one of the already existing abstract base classes. 
5673 27 Jun 11 nicklas 983             They contain code that is common to all classes, for example implementations of 
5673 27 Jun 11 nicklas 984             the <methodname>equals()</methodname> and <methodname>hashCode()</methodname>
5673 27 Jun 11 nicklas 985             methods or how to link with the owner of an item. For information about
5673 27 Jun 11 nicklas 986             which classes/interfaces that can be used see <xref linkend="data_api.basic" />.
5673 27 Jun 11 nicklas 987             </para>
5673 27 Jun 11 nicklas 988           </listitem>
5673 27 Jun 11 nicklas 989         </varlistentry>
3715 11 Sep 07 nicklas 990
5673 27 Jun 11 nicklas 991         <varlistentry>
5673 27 Jun 11 nicklas 992           <term>Define a public no-argument constructor</term>
5673 27 Jun 11 nicklas 993           <listitem>
5673 27 Jun 11 nicklas 994             <para>
5673 27 Jun 11 nicklas 995             Always define a public no-argument constructor. No other constructors are needed. 
5673 27 Jun 11 nicklas 996             If we want to use other persistence mechanisms or serializability in the future 
5673 27 Jun 11 nicklas 997             this type of constructor is probably the most compatible. The constructor should 
5673 27 Jun 11 nicklas 998             be empty and not contain any code. Do not initialise properties or create new objects 
5673 27 Jun 11 nicklas 999             for internal use. Most of the time the object is loaded by 
5673 27 Jun 11 nicklas 1000             Hibernate and Hibernate will ensure that it is properly initialised by calling 
5673 27 Jun 11 nicklas 1001             all setter methods.
5673 27 Jun 11 nicklas 1002             </para>
5673 27 Jun 11 nicklas 1003             <para>
5673 27 Jun 11 nicklas 1004               For example, a many-to-many relation usually has a <interfacename>Set</interfacename>
5673 27 Jun 11 nicklas 1005               or a <interfacename>Map</interfacename> to hold the links to the other objects. Do not 
5673 27 Jun 11 nicklas 1006               create a new <classname>HashSet</classname> or <classname>HashMap</classname>
5673 27 Jun 11 nicklas 1007               in the constructor. Wait until the getter method is called and only create a new 
5673 27 Jun 11 nicklas 1008               object if Hibernate hasn't already called the setter method with it's own object. 
5673 27 Jun 11 nicklas 1009               See the code example below. There is also more information about this in 
5673 27 Jun 11 nicklas 1010               <xref linkend="core_ref.rules.datalayer.manytomany" />.
5673 27 Jun 11 nicklas 1011             </para>
5673 27 Jun 11 nicklas 1012             <programlisting language="java">
5673 27 Jun 11 nicklas 1013 <![CDATA[
3715 11 Sep 07 nicklas 1014 // From GroupData.java
3715 11 Sep 07 nicklas 1015 public GroupData() 
3715 11 Sep 07 nicklas 1016 {}
3715 11 Sep 07 nicklas 1017
5673 27 Jun 11 nicklas 1018 private Set<UserData> users;
5673 27 Jun 11 nicklas 1019 public Set<UserData> getUsers()
3715 11 Sep 07 nicklas 1020 {
5673 27 Jun 11 nicklas 1021    if (users == null) users = new HashSet<UserData>();
3715 11 Sep 07 nicklas 1022    return users;
3715 11 Sep 07 nicklas 1023 }
5673 27 Jun 11 nicklas 1024 ]]>
3715 11 Sep 07 nicklas 1025 </programlisting>
3715 11 Sep 07 nicklas 1026
5673 27 Jun 11 nicklas 1027             <para>
5673 27 Jun 11 nicklas 1028             See also:
5673 27 Jun 11 nicklas 1029             </para>
5673 27 Jun 11 nicklas 1030             
5673 27 Jun 11 nicklas 1031             <itemizedlist>
5673 27 Jun 11 nicklas 1032             <listitem>
5673 27 Jun 11 nicklas 1033               <para>
5673 27 Jun 11 nicklas 1034               "Hibernate in action", chapter 3.2.3 "Writing POJOs", page 67-69
5673 27 Jun 11 nicklas 1035               </para>
5673 27 Jun 11 nicklas 1036             </listitem>
5673 27 Jun 11 nicklas 1037             <listitem>
5673 27 Jun 11 nicklas 1038               <para>
5673 27 Jun 11 nicklas 1039               Hibernate reference documentation: <ulink 
5673 27 Jun 11 nicklas 1040                 url="http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/persistent-classes.html#persistent-classes-pojo-constructor">4.1.1. 
5673 27 Jun 11 nicklas 1041                 Implement a no-argument constructor</ulink>
5673 27 Jun 11 nicklas 1042               </para>
5673 27 Jun 11 nicklas 1043             </listitem>
5673 27 Jun 11 nicklas 1044             </itemizedlist>
3715 11 Sep 07 nicklas 1045
5673 27 Jun 11 nicklas 1046           </listitem>
5673 27 Jun 11 nicklas 1047         </varlistentry>
3715 11 Sep 07 nicklas 1048
5673 27 Jun 11 nicklas 1049         <varlistentry>
5673 27 Jun 11 nicklas 1050           <term>Object identity</term>
3715 11 Sep 07 nicklas 1051           <listitem>
3715 11 Sep 07 nicklas 1052             <para>
5673 27 Jun 11 nicklas 1053               We use database identity to compare objects, ie. two objects are considered 
5673 27 Jun 11 nicklas 1054               equal if they are of the same class and have the same id, thus representing the 
5673 27 Jun 11 nicklas 1055               same database row. All this stuff is implemented by the <classname 
5673 27 Jun 11 nicklas 1056               docapi="net.sf.basedb.core.data">BasicData</classname> class. Therefore 
5673 27 Jun 11 nicklas 1057               it is required that all classes are subclasses of this class. It is recommended 
5673 27 Jun 11 nicklas 1058               that the <methodname>equals()</methodname> or <methodname>hashCode()</methodname>
5673 27 Jun 11 nicklas 1059               methods are not overridden by any of the subclasses. We would have liked to make 
5673 27 Jun 11 nicklas 1060               them final, but then the proxy feature of Hibernate would not work.
3715 11 Sep 07 nicklas 1061             </para>
5673 27 Jun 11 nicklas 1062             
5673 27 Jun 11 nicklas 1063             <warning>
5673 27 Jun 11 nicklas 1064               <title>Avoid mixing saved and unsaved objects</title>
5673 27 Jun 11 nicklas 1065               <para>
5673 27 Jun 11 nicklas 1066                 The approch used for object identity may give us a problem if we mix objects
5673 27 Jun 11 nicklas 1067                 which hasn't been saved to the database, with objects loaded from the database. 
5673 27 Jun 11 nicklas 1068                 Our recommendation is to avoid that, and save any objects to the database before 
5673 27 Jun 11 nicklas 1069                 adding them to sets, maps or any other structure that uses the 
5673 27 Jun 11 nicklas 1070                 <methodname>equals()</methodname> and <methodname>hashCode()</methodname> methods.
5673 27 Jun 11 nicklas 1071               </para>
5673 27 Jun 11 nicklas 1072               <para>
5673 27 Jun 11 nicklas 1073                 To be more specific, the problem arises because the following two rules for 
5673 27 Jun 11 nicklas 1074                 hash codes are contradicting when the hash code is based on the database id:
5673 27 Jun 11 nicklas 1075               </para>
5673 27 Jun 11 nicklas 1076               <orderedlist>
5673 27 Jun 11 nicklas 1077               <listitem>
5673 27 Jun 11 nicklas 1078                 <para>
5673 27 Jun 11 nicklas 1079                 The hash code of an object mustn't change.
5673 27 Jun 11 nicklas 1080                 </para>
5673 27 Jun 11 nicklas 1081               </listitem>
5673 27 Jun 11 nicklas 1082               <listitem>
5673 27 Jun 11 nicklas 1083                 <para>
5673 27 Jun 11 nicklas 1084                 Equal objects must have equal hash code.
5673 27 Jun 11 nicklas 1085                 </para>
5673 27 Jun 11 nicklas 1086               </listitem>
5673 27 Jun 11 nicklas 1087               </orderedlist>
5673 27 Jun 11 nicklas 1088               <para>
5673 27 Jun 11 nicklas 1089                 For objects in the database, the hash code is based on the id. For new objects, 
5673 27 Jun 11 nicklas 1090                 which doesn't have an id yet, we fall back to the system hash code. But, what 
5673 27 Jun 11 nicklas 1091                 happens when we save the new object to the database? If nobody has asked for 
5673 27 Jun 11 nicklas 1092                 the hash code it is safe to use the id, otherwise we must stick with the system 
5673 27 Jun 11 nicklas 1093                 hash code. Now, imagine that we load the same object from the database in 
5673 27 Jun 11 nicklas 1094                 another Hibernate session. What will now happen? The loaded object will have 
5673 27 Jun 11 nicklas 1095                 it's hash code based on the id but the original object is still using the
5673 27 Jun 11 nicklas 1096                 system hash code, which most likely is not the same as the id. Yet, the 
5673 27 Jun 11 nicklas 1097                 <methodname>equals()</methodname> method returns true. This is a violation 
5673 27 Jun 11 nicklas 1098                 of the contract for the equals method. If these two objects are used in a set 
5673 27 Jun 11 nicklas 1099                 it may cause unexpected behaviour. Therefore, do not put new objects in a 
5673 27 Jun 11 nicklas 1100                 set, or other collection, that calls the <methodname>hashCode()</methodname> 
5673 27 Jun 11 nicklas 1101                 method before the object is saved to the database.           
5673 27 Jun 11 nicklas 1102               </para>
5673 27 Jun 11 nicklas 1103             </warning>
5673 27 Jun 11 nicklas 1104             
5673 27 Jun 11 nicklas 1105             <para>
5673 27 Jun 11 nicklas 1106             See also:
5673 27 Jun 11 nicklas 1107             </para>
5673 27 Jun 11 nicklas 1108             <itemizedlist>
5673 27 Jun 11 nicklas 1109             <listitem>
5673 27 Jun 11 nicklas 1110               <para>
5673 27 Jun 11 nicklas 1111               "Hibernate in action", chapter 3.4 "Understanding object identity", page 87-90
5673 27 Jun 11 nicklas 1112               </para>
5673 27 Jun 11 nicklas 1113             </listitem>
5673 27 Jun 11 nicklas 1114             <listitem>
5673 27 Jun 11 nicklas 1115               <para>
5673 27 Jun 11 nicklas 1116               "Hibernate in action", chapter 4.1.4 "The scope of object identity", page 119-121
5673 27 Jun 11 nicklas 1117               </para>
5673 27 Jun 11 nicklas 1118             </listitem>
5673 27 Jun 11 nicklas 1119             <listitem>
5673 27 Jun 11 nicklas 1120               <para>
5673 27 Jun 11 nicklas 1121               "Hibernate in action", chapter 4.1.6 "Implementing equals() and hashCode(), page 122-126
5673 27 Jun 11 nicklas 1122               </para>
5673 27 Jun 11 nicklas 1123             </listitem>
5673 27 Jun 11 nicklas 1124             <listitem>
5673 27 Jun 11 nicklas 1125               <para>
5673 27 Jun 11 nicklas 1126               Hibernate reference documentation: <ulink 
5673 27 Jun 11 nicklas 1127                 url="http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/persistent-classes.html#persistent-classes-equalshashcode">4.3. Implementing equals() and hashCode()</ulink>
5673 27 Jun 11 nicklas 1128               </para>
5673 27 Jun 11 nicklas 1129             </listitem>
5673 27 Jun 11 nicklas 1130             </itemizedlist>
5673 27 Jun 11 nicklas 1131
3715 11 Sep 07 nicklas 1132           </listitem>
5673 27 Jun 11 nicklas 1133         </varlistentry>
5673 27 Jun 11 nicklas 1134         
5673 27 Jun 11 nicklas 1135         <varlistentry>
5673 27 Jun 11 nicklas 1136           <term>No final methods</term>
3715 11 Sep 07 nicklas 1137           <listitem>
3715 11 Sep 07 nicklas 1138             <para>
5673 27 Jun 11 nicklas 1139               No methods should be tagged with the <code>final</code> keyword. This is a 
5673 27 Jun 11 nicklas 1140               requirement to be able to use the proxy feature of Hibernate, which we need for 
5673 27 Jun 11 nicklas 1141               performance reasons.
3715 11 Sep 07 nicklas 1142             </para>
5673 27 Jun 11 nicklas 1143     
5673 27 Jun 11 nicklas 1144             <para>
5673 27 Jun 11 nicklas 1145             See also:
5673 27 Jun 11 nicklas 1146             </para>
5673 27 Jun 11 nicklas 1147             <itemizedlist>
5673 27 Jun 11 nicklas 1148             <listitem>
5673 27 Jun 11 nicklas 1149               <para>
5673 27 Jun 11 nicklas 1150               Hibernate reference documentation: <ulink 
5673 27 Jun 11 nicklas 1151                 url="http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/persistent-classes.html#persistent-classes-pojo-final">4.1.3. Prefer non-final classes</ulink>
5673 27 Jun 11 nicklas 1152               </para>
5673 27 Jun 11 nicklas 1153             </listitem>
5673 27 Jun 11 nicklas 1154             <listitem>
5673 27 Jun 11 nicklas 1155               <para>
5673 27 Jun 11 nicklas 1156               Hibernate reference documentation: <ulink 
5673 27 Jun 11 nicklas 1157                 url="http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/performance.html#performance-fetching-proxies">21.1.3. Single-ended association proxies</ulink>
5673 27 Jun 11 nicklas 1158               </para>
5673 27 Jun 11 nicklas 1159             </listitem>
5673 27 Jun 11 nicklas 1160             </itemizedlist>
3715 11 Sep 07 nicklas 1161           </listitem>
5673 27 Jun 11 nicklas 1162         </varlistentry>
3715 11 Sep 07 nicklas 1163
3715 11 Sep 07 nicklas 1164
5673 27 Jun 11 nicklas 1165         <varlistentry>
5673 27 Jun 11 nicklas 1166           <term>Second-level cache</term>
5673 27 Jun 11 nicklas 1167           <listitem>
5673 27 Jun 11 nicklas 1168             <para>
5673 27 Jun 11 nicklas 1169               To gain performance we use the second-level cache of Hibernate. It is a transparent
5673 27 Jun 11 nicklas 1170               feature that doesn't affect the code in any way. The second-level cache is configured 
5673 27 Jun 11 nicklas 1171               in the <filename>hibernate.cfg.xml</filename> and <filename>ehcache.xml</filename> 
5673 27 Jun 11 nicklas 1172               configuration files and not in the individual class mapping files. BASE is shipped 
5673 27 Jun 11 nicklas 1173               with a standard configuration, but different deployment scenarios may have to fine-tune the cache 
5673 27 Jun 11 nicklas 1174               settings for that particular hardware/software setup. It is beyond the scope of 
5673 27 Jun 11 nicklas 1175               this document to discuss this issue.
5673 27 Jun 11 nicklas 1176             </para>
5673 27 Jun 11 nicklas 1177             <para>
5673 27 Jun 11 nicklas 1178               The second-level cache is suitable for objects that are rarely modified but 
5673 27 Jun 11 nicklas 1179               are often needed. For example, we do not expect the user information represented 
5673 27 Jun 11 nicklas 1180               by the <classname docapi="net.sf.basedb.core.data">UserData</classname> object to 
5673 27 Jun 11 nicklas 1181               change very often, but it is displayed all the time as the owner of various items.
5673 27 Jun 11 nicklas 1182               Before coming up with a good caching strategy we have to answer the following questions:
5673 27 Jun 11 nicklas 1183             </para>
5673 27 Jun 11 nicklas 1184             
5673 27 Jun 11 nicklas 1185             <orderedlist>
5673 27 Jun 11 nicklas 1186             <listitem>
5673 27 Jun 11 nicklas 1187               <para>
5673 27 Jun 11 nicklas 1188               Should objects of this class be cached at all?
5673 27 Jun 11 nicklas 1189               </para>
5673 27 Jun 11 nicklas 1190             </listitem>
5673 27 Jun 11 nicklas 1191             <listitem>
5673 27 Jun 11 nicklas 1192               <para>
5673 27 Jun 11 nicklas 1193               How long timeout should we use?
5673 27 Jun 11 nicklas 1194               </para>
5673 27 Jun 11 nicklas 1195             </listitem>
5673 27 Jun 11 nicklas 1196             <listitem>
5673 27 Jun 11 nicklas 1197               <para>
5673 27 Jun 11 nicklas 1198               How many objects should we keep in memory or on disk?
5673 27 Jun 11 nicklas 1199               </para>
5673 27 Jun 11 nicklas 1200             </listitem>
5673 27 Jun 11 nicklas 1201             </orderedlist>
3715 11 Sep 07 nicklas 1202
5673 27 Jun 11 nicklas 1203             <para>
5673 27 Jun 11 nicklas 1204               The first question is the most important. Good candidates are classes with few 
5673 27 Jun 11 nicklas 1205               objects that change rarely, but are read often. Also, objects which are linked 
5673 27 Jun 11 nicklas 1206               to by many other objects are good candidates. The <classname docapi="net.sf.basedb.core.data">UserData</classname>
5673 27 Jun 11 nicklas 1207               class is an example which matches all three requirements. The <classname docapi="net.sf.basedb.core.data">TagData</classname>
5673 27 Jun 11 nicklas 1208               class is an example which fulfils the first two. The <classname docapi="net.sf.basedb.core.data">BioMaterialEventData</classname>
5673 27 Jun 11 nicklas 1209               class is on the other hand a bad cache candidate, since it is not linked to any 
5673 27 Jun 11 nicklas 1210               other object than a <classname docapi="net.sf.basedb.core.data">BioMaterialData</classname> object.
5673 27 Jun 11 nicklas 1211             </para>
5673 27 Jun 11 nicklas 1212             <para>
5673 27 Jun 11 nicklas 1213               The answer to the second question depends on how often an object is modified. 
5673 27 Jun 11 nicklas 1214               For most objects this time is probably several days or months, but we would 
5673 27 Jun 11 nicklas 1215               not gain much by keeping objects in the cache for so long. Suddenly, the 
5673 27 Jun 11 nicklas 1216               information has changed and we won't risk that old information is kept that 
5673 27 Jun 11 nicklas 1217               long. We have set the timeout to 1 hour for all classes so far, and we don't 
5673 27 Jun 11 nicklas 1218               recommend a longer timeout. The only exception is for immutable objects, that 
5673 27 Jun 11 nicklas 1219               cannot be changed at all, which may have an infinite timeout.
5673 27 Jun 11 nicklas 1220             </para>
5673 27 Jun 11 nicklas 1221             <para>
5673 27 Jun 11 nicklas 1222               The answer to the third question depends a lot on the hardware (available memory).
5673 27 Jun 11 nicklas 1223               With lots of memory we can afford to cache more objects. Caching to disk is not 
5673 27 Jun 11 nicklas 1224               really necessary if the database is on the same machine as the web server, but 
5673 27 Jun 11 nicklas 1225               if it is on another machine we have to consider the network delay to connect 
5673 27 Jun 11 nicklas 1226               to the database versus the disk access time. The default configuration does not 
5673 27 Jun 11 nicklas 1227               use disk cache.
5673 27 Jun 11 nicklas 1228             </para>
3715 11 Sep 07 nicklas 1229
5673 27 Jun 11 nicklas 1230             <para>
5673 27 Jun 11 nicklas 1231             See also:
5673 27 Jun 11 nicklas 1232             </para>
5673 27 Jun 11 nicklas 1233             <itemizedlist>
5673 27 Jun 11 nicklas 1234             <listitem>
5673 27 Jun 11 nicklas 1235               <para>
5673 27 Jun 11 nicklas 1236               "Hibernate in action", chapter 5.3 "Caching theory and practice", page 175-194.
5673 27 Jun 11 nicklas 1237               </para>
5673 27 Jun 11 nicklas 1238             </listitem>
5673 27 Jun 11 nicklas 1239             <listitem>
5673 27 Jun 11 nicklas 1240               <para>
5673 27 Jun 11 nicklas 1241                 Hibernate reference documentation: <ulink 
5673 27 Jun 11 nicklas 1242                 url="http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/performance.html#performance-cache">21.2. The Second Level Cache</ulink>
5673 27 Jun 11 nicklas 1243               </para>
5673 27 Jun 11 nicklas 1244             </listitem>
5673 27 Jun 11 nicklas 1245             </itemizedlist>
5673 27 Jun 11 nicklas 1246             
5673 27 Jun 11 nicklas 1247           </listitem>
5673 27 Jun 11 nicklas 1248         </varlistentry>
5673 27 Jun 11 nicklas 1249
5673 27 Jun 11 nicklas 1250         <varlistentry>
5673 27 Jun 11 nicklas 1251           <term>Proxies</term>
5673 27 Jun 11 nicklas 1252           <listitem>
5673 27 Jun 11 nicklas 1253             <para>
5673 27 Jun 11 nicklas 1254               Proxies are also used to gain performance, and they may have some impact on 
5673 27 Jun 11 nicklas 1255               the code. Proxies are created at runtime (by Hibernate) as a subclass of the 
5673 27 Jun 11 nicklas 1256               actual class but are not populated with data until some method of the object 
5673 27 Jun 11 nicklas 1257               is called. The data is loaded from the database the first time a method other 
5673 27 Jun 11 nicklas 1258               than <methodname>getId()</methodname> is called. Thus, we can avoid loading 
5673 27 Jun 11 nicklas 1259               data that is not needed at a particular time.
5673 27 Jun 11 nicklas 1260             </para>
3715 11 Sep 07 nicklas 1261         
5673 27 Jun 11 nicklas 1262             <para>
5673 27 Jun 11 nicklas 1263               There can be a problem with using the <code>instanceof</code> operator with proxies 
5673 27 Jun 11 nicklas 1264               and the table-per-class-hierarchy mapping. For example, if we have the abstract 
5673 27 Jun 11 nicklas 1265               class <classname>Animal</classname> and subclasses <classname>Cat</classname>
5673 27 Jun 11 nicklas 1266               and <classname>Dog</classname>. The proxy of an <classname>Animal</classname> is a 
5673 27 Jun 11 nicklas 1267               runtime generated subclass of <classname>Animal</classname>, since we do not know if it 
5673 27 Jun 11 nicklas 1268               is a <classname>Cat</classname> or <classname>Dog</classname>. So, 
5673 27 Jun 11 nicklas 1269               <code>x instanceof Dog</code> and <code>x instanceof Cat</code> would both return 
5673 27 Jun 11 nicklas 1270               false. If we hadn't used a proxy, at least one of them would always be true.
5673 27 Jun 11 nicklas 1271             </para>
3715 11 Sep 07 nicklas 1272         
5673 27 Jun 11 nicklas 1273             <para>
5673 27 Jun 11 nicklas 1274               Proxies are only used when a not-null object is linked with many-to-one or 
5673 27 Jun 11 nicklas 1275               one-to-one from another object. If we ask for a specific object by id, or by a 
5673 27 Jun 11 nicklas 1276               query, we will never get a proxy. Therefore, it only makes sense to enable 
5673 27 Jun 11 nicklas 1277               proxies for classes that can be linked from other classes. One-to-one links on 
5673 27 Jun 11 nicklas 1278               the primary key where null is allowed silently disables the proxy feature, 
5673 27 Jun 11 nicklas 1279               since Hibernate doesn't know if there is an object or not without querying 
5673 27 Jun 11 nicklas 1280               the database.
5673 27 Jun 11 nicklas 1281             </para>
5673 27 Jun 11 nicklas 1282             <bridgehead>Proxy vs. cache</bridgehead>
5673 27 Jun 11 nicklas 1283             <para>
5673 27 Jun 11 nicklas 1284               The goal of a proxy and the second-level cache are the same: to avoid hitting the 
5673 27 Jun 11 nicklas 1285               database. It is perfectly possible to enable both proxies and the cache for a 
5673 27 Jun 11 nicklas 1286               class. Then we would start with a proxy and as soon as a method is called Hibernate 
5673 27 Jun 11 nicklas 1287               would look in the second-level cache. Only if it is not there it would be loaded 
5673 27 Jun 11 nicklas 1288               from the database. But, do we really need a proxy in the first place? Well, I think 
5673 27 Jun 11 nicklas 1289               it might be better to use only the cache or only proxies. But, this also makes it 
5673 27 Jun 11 nicklas 1290               even more important that the cache is configured correctly so there is a high 
5673 27 Jun 11 nicklas 1291               probability that the object is already in the cache.
5673 27 Jun 11 nicklas 1292             </para>
5673 27 Jun 11 nicklas 1293             
5673 27 Jun 11 nicklas 1294             <para>
5673 27 Jun 11 nicklas 1295               If a class has been configured to use the second-level cache, we recommend 
5673 27 Jun 11 nicklas 1296               that proxies are disabled. For child objects in a parent-child relationship proxies 
5673 27 Jun 11 nicklas 1297               should be disabled, since they have no other links to them than from the parent. 
5673 27 Jun 11 nicklas 1298               If a class can be linked as many-to-one from several other classes it makes sense 
5673 27 Jun 11 nicklas 1299               to enable proxies. If we have a long chain of many-to-one relations it may also make 
5673 27 Jun 11 nicklas 1300               sense to enable proxies at some level, even if the second-level cache is used. 
5673 27 Jun 11 nicklas 1301               In that case we only need to create one proxy instead of looking up several objects 
5673 27 Jun 11 nicklas 1302               in the cache. Also, think about how a particular class most commonly will be used 
5673 27 Jun 11 nicklas 1303               in a client application. For example, it is very common to display the name of the 
5673 27 Jun 11 nicklas 1304               owner of an item, but we are probably not interested in displaying quota 
5673 27 Jun 11 nicklas 1305               information for that user. So, it makes sense to put users in the second-level 
5673 27 Jun 11 nicklas 1306               cache and use proxies for quota information.
5673 27 Jun 11 nicklas 1307             </para>
3715 11 Sep 07 nicklas 1308
5673 27 Jun 11 nicklas 1309             <warning>
5673 27 Jun 11 nicklas 1310               <title>Batchable classes and stateless sessions</title>
5673 27 Jun 11 nicklas 1311               <para>
5673 27 Jun 11 nicklas 1312                 Hibernate has a <emphasis>stateless session</emphasis> feature. A 
5673 27 Jun 11 nicklas 1313                 stateless session has no first-level cache and doesn't use the second-level 
5673 27 Jun 11 nicklas 1314                 cache either. This means that if we load an item with a stateless session 
5673 27 Jun 11 nicklas 1315                 Hibernate will always traverse many-to-one and one-to-one associations and 
5673 27 Jun 11 nicklas 1316                 load those objects as well, unless they are configured to use proxies.
5673 27 Jun 11 nicklas 1317               </para>
5673 27 Jun 11 nicklas 1318               
5673 27 Jun 11 nicklas 1319               <para>
5673 27 Jun 11 nicklas 1320                 BASE use stateless sessions for loading <classname docapi="net.sf.basedb.core.data">BatchableData</classname>
5673 27 Jun 11 nicklas 1321                 items (reporters, raw data and features) 
5673 27 Jun 11 nicklas 1322                 since they are many and we want to use as little memory as possible. Here it 
5673 27 Jun 11 nicklas 1323                 is required that proxies are enabled for all items that are linked from any of 
5673 27 Jun 11 nicklas 1324                 the batchable items, ie. <classname docapi="net.sf.basedb.core">RawBioAssay</classname>, 
5673 27 Jun 11 nicklas 1325                 <classname docapi="net.sf.basedb.core">ReporterType</classname>, 
5673 27 Jun 11 nicklas 1326                 <classname docapi="net.sf.basedb.core">ArrayDesignBlock</classname>, etc.
5673 27 Jun 11 nicklas 1327                 If we don't do this Hibernate will generate multiple additional select
5673 27 Jun 11 nicklas 1328                 statements for the same parent item which will affect performance 
5673 27 Jun 11 nicklas 1329                 in a bad way.
5673 27 Jun 11 nicklas 1330               </para>
5673 27 Jun 11 nicklas 1331               
5673 27 Jun 11 nicklas 1332               <para>
5673 27 Jun 11 nicklas 1333                 On the other hand, the proxies created from a stateless session cannot later 
5673 27 Jun 11 nicklas 1334                 be initialised. We have to get the ID from the proxy and the load the object 
5673 27 Jun 11 nicklas 1335                 using the regular session. But this can also results in lots of additional select
5673 27 Jun 11 nicklas 1336                 statements so if it is known before that we need some information it is recommended
5673 27 Jun 11 nicklas 1337                 that a FETCH JOIN query is used so that we get fully initialized objects instead of
5673 27 Jun 11 nicklas 1338                 proxies to begin with.
5673 27 Jun 11 nicklas 1339               </para>
5673 27 Jun 11 nicklas 1340             </warning>
5673 27 Jun 11 nicklas 1341             <para>
5673 27 Jun 11 nicklas 1342               Here is a table which summarises different settings for the second-level cache, 
5673 27 Jun 11 nicklas 1343               proxies, batch fetching and many-to-one links. Batch fetching and many-to-one links 
5673 27 Jun 11 nicklas 1344               are discussed later in this document.
5673 27 Jun 11 nicklas 1345             </para>
5673 27 Jun 11 nicklas 1346             
5673 27 Jun 11 nicklas 1347             <para>
5673 27 Jun 11 nicklas 1348               First, decide if the second-level cache should be enabled or not. Then, if 
5673 27 Jun 11 nicklas 1349               proxies should be enabled or not. The table then gives a reasonable setting for 
5673 27 Jun 11 nicklas 1350               the batch size and many-to-one mappings. NOTE! The many-to-one mappings are 
5673 27 Jun 11 nicklas 1351               the links from other classes to this one, not links from this class.
5673 27 Jun 11 nicklas 1352             </para>
5673 27 Jun 11 nicklas 1353             
5673 27 Jun 11 nicklas 1354             <para>
5673 27 Jun 11 nicklas 1355               The settings in this table are not absolute rules. In some cases there might 
5673 27 Jun 11 nicklas 1356               be a good reason for another combination. Please, write a comment about why 
5673 27 Jun 11 nicklas 1357               the recommendations were not followed.
5673 27 Jun 11 nicklas 1358             </para>
5673 27 Jun 11 nicklas 1359             
5673 27 Jun 11 nicklas 1360             <table id="core_ref.rules.datalayer.cacheproxysettings">
5673 27 Jun 11 nicklas 1361               <title>Choosing cache and proxy settings</title>
5673 27 Jun 11 nicklas 1362               <tgroup cols="4">
5673 27 Jun 11 nicklas 1363                 <colspec colname="cache" />
5673 27 Jun 11 nicklas 1364                 <colspec colname="proxy" />
5673 27 Jun 11 nicklas 1365                 <colspec colname="batchsize" />
5673 27 Jun 11 nicklas 1366                 <colspec colname="outerjoin" />
5673 27 Jun 11 nicklas 1367                 
5673 27 Jun 11 nicklas 1368                 <thead>
5673 27 Jun 11 nicklas 1369                   <row>
5673 27 Jun 11 nicklas 1370                     <entry>Global configuration</entry>
5673 27 Jun 11 nicklas 1371                     <entry namest="proxy" nameend="batchsize">Class mapping</entry>
5673 27 Jun 11 nicklas 1372                     <entry>Many-to-one mapping</entry>
5673 27 Jun 11 nicklas 1373                   </row>
5673 27 Jun 11 nicklas 1374                   <row>
5673 27 Jun 11 nicklas 1375                     <entry>Cache</entry>
5673 27 Jun 11 nicklas 1376                     <entry>Proxy</entry>
5673 27 Jun 11 nicklas 1377                     <entry>Batch-size</entry>
5673 27 Jun 11 nicklas 1378                     <entry>Outer-join</entry>
5673 27 Jun 11 nicklas 1379                   </row>
5673 27 Jun 11 nicklas 1380                 </thead>
5673 27 Jun 11 nicklas 1381                 <tbody>
5673 27 Jun 11 nicklas 1382                   <row>
5673 27 Jun 11 nicklas 1383                     <entry>no</entry>
5673 27 Jun 11 nicklas 1384                     <entry>no*</entry>
5673 27 Jun 11 nicklas 1385                     <entry>yes</entry>
5673 27 Jun 11 nicklas 1386                     <entry>true</entry>
5673 27 Jun 11 nicklas 1387                   </row>
5673 27 Jun 11 nicklas 1388                   <row>
5673 27 Jun 11 nicklas 1389                     <entry>yes</entry>
5673 27 Jun 11 nicklas 1390                     <entry>no*</entry>
5673 27 Jun 11 nicklas 1391                     <entry>no</entry>
5673 27 Jun 11 nicklas 1392                     <entry>false</entry>
5673 27 Jun 11 nicklas 1393                   </row>
5673 27 Jun 11 nicklas 1394                   <row>
5673 27 Jun 11 nicklas 1395                     <entry>no</entry>
5673 27 Jun 11 nicklas 1396                     <entry>yes</entry>
5673 27 Jun 11 nicklas 1397                     <entry>yes</entry>
5673 27 Jun 11 nicklas 1398                     <entry>false</entry>
5673 27 Jun 11 nicklas 1399                   </row>
5673 27 Jun 11 nicklas 1400                   <row>
5673 27 Jun 11 nicklas 1401                     <entry>yes</entry>
5673 27 Jun 11 nicklas 1402                     <entry>yes</entry>
5673 27 Jun 11 nicklas 1403                     <entry>no</entry>
5673 27 Jun 11 nicklas 1404                     <entry>false</entry>
5673 27 Jun 11 nicklas 1405                   </row>
5673 27 Jun 11 nicklas 1406                 </tbody>
5673 27 Jun 11 nicklas 1407               </tgroup>
5673 27 Jun 11 nicklas 1408             </table>
5673 27 Jun 11 nicklas 1409             
5673 27 Jun 11 nicklas 1410             <para>
5673 27 Jun 11 nicklas 1411               * = Do not use this setting for classes which are many-to-one linked from a batchable 
5673 27 Jun 11 nicklas 1412               class.
5673 27 Jun 11 nicklas 1413             </para>
5673 27 Jun 11 nicklas 1414             
5673 27 Jun 11 nicklas 1415             <para>
5673 27 Jun 11 nicklas 1416             See also:
5673 27 Jun 11 nicklas 1417             </para>
5673 27 Jun 11 nicklas 1418             <itemizedlist>
5673 27 Jun 11 nicklas 1419             <listitem>
5673 27 Jun 11 nicklas 1420               <para>
5673 27 Jun 11 nicklas 1421               "Hibernate in action", chapter 4.4.6 "Selecting a fetching strategy in mappings", page 146-147
5673 27 Jun 11 nicklas 1422               </para>
5673 27 Jun 11 nicklas 1423             </listitem>
5673 27 Jun 11 nicklas 1424             <listitem>
5673 27 Jun 11 nicklas 1425               <para>
5673 27 Jun 11 nicklas 1426               "Hibernate in action", chapter 6.4.1 "Polymorphic many-to-one associations", page 234-236
5673 27 Jun 11 nicklas 1427               </para>
5673 27 Jun 11 nicklas 1428             </listitem>
5673 27 Jun 11 nicklas 1429             <listitem>
5673 27 Jun 11 nicklas 1430               <para>
5673 27 Jun 11 nicklas 1431               Hibernate reference documentation: <ulink 
5673 27 Jun 11 nicklas 1432                 url="http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/performance.html#performance-fetching-proxies">21.1.3. Single-ended association proxies</ulink>
5673 27 Jun 11 nicklas 1433               </para>
5673 27 Jun 11 nicklas 1434             </listitem>
5673 27 Jun 11 nicklas 1435             </itemizedlist>
5673 27 Jun 11 nicklas 1436             
5673 27 Jun 11 nicklas 1437           </listitem>
5673 27 Jun 11 nicklas 1438         </varlistentry>
3715 11 Sep 07 nicklas 1439
5673 27 Jun 11 nicklas 1440         <varlistentry>
5673 27 Jun 11 nicklas 1441           <term>Hibernate mappings</term>
5673 27 Jun 11 nicklas 1442           <listitem>
5673 27 Jun 11 nicklas 1443             <para>
5673 27 Jun 11 nicklas 1444               We use Javadoc tags to specify the database mapping needed by Hibernate.
5673 27 Jun 11 nicklas 1445               The tags are processed by XDoclet at build time which generates the XML-based 
5673 27 Jun 11 nicklas 1446               Hibernate mapping files.
5673 27 Jun 11 nicklas 1447             </para>
5673 27 Jun 11 nicklas 1448             
5673 27 Jun 11 nicklas 1449             <note>
5673 27 Jun 11 nicklas 1450               <title>XDoclet doesn't support all mappings</title>
5673 27 Jun 11 nicklas 1451               <para>
5673 27 Jun 11 nicklas 1452               The XDoclet that we use was developed to generate mapping files for
5673 27 Jun 11 nicklas 1453               Hibernate 2.x. Since then, Hibernate has released several 3.x versions,
5673 27 Jun 11 nicklas 1454               and the mapping file structure has changed. Some changes can be handled by
5673 27 Jun 11 nicklas 1455               generating a corresponding 2.x mapping and then converting it to a 3.x
5673 27 Jun 11 nicklas 1456               mapping at build time using simple search-and-replace operations.
5673 27 Jun 11 nicklas 1457               One such case is to update the DTD reference to the 3.0 version instead of 
5673 27 Jun 11 nicklas 1458               the 2.0 version. Other changes can't use this approach. Instead we have to
5673 27 Jun 11 nicklas 1459               provide extra mappings inside an XML files. This is also needed if we need
5673 27 Jun 11 nicklas 1460               to use some of the new 3.x features that has no 2.x counterpart.
5673 27 Jun 11 nicklas 1461               </para>
5673 27 Jun 11 nicklas 1462             </note>
5673 27 Jun 11 nicklas 1463           </listitem>
5673 27 Jun 11 nicklas 1464         </varlistentry>
3715 11 Sep 07 nicklas 1465
5673 27 Jun 11 nicklas 1466         <varlistentry>
5673 27 Jun 11 nicklas 1467             <term>Class mapping</term>
5673 27 Jun 11 nicklas 1468             <listitem>
5673 27 Jun 11 nicklas 1469               
5673 27 Jun 11 nicklas 1470               <programlisting language="java">
3715 11 Sep 07 nicklas 1471 /**
3715 11 Sep 07 nicklas 1472    This class holds information about any data...
3715 11 Sep 07 nicklas 1473    @author Your name
5673 27 Jun 11 nicklas 1474    @since 3.0
3715 11 Sep 07 nicklas 1475    @hibernate.class table="`Anys`" lazy="false" batch-size="10"
3715 11 Sep 07 nicklas 1476 */
3715 11 Sep 07 nicklas 1477 public class AnyData
3715 11 Sep 07 nicklas 1478    extends CommonData
3715 11 Sep 07 nicklas 1479 {
3715 11 Sep 07 nicklas 1480    // Rest of class code...
3715 11 Sep 07 nicklas 1481 }
3715 11 Sep 07 nicklas 1482 </programlisting>
3715 11 Sep 07 nicklas 1483
3715 11 Sep 07 nicklas 1484             <para>
5673 27 Jun 11 nicklas 1485               The class declaration must contain a <code>@hibernate.class</code> Javadoc entry 
5673 27 Jun 11 nicklas 1486               where Hibernate can find the name of the table where items of this type are stored. 
5673 27 Jun 11 nicklas 1487               The table name should generally be the same as the class name, without the ending 
5673 27 Jun 11 nicklas 1488               <code>Data</code> and in a plural form. For example <classname docapi="net.sf.basedb.core.data">UserData</classname>
5673 27 Jun 11 nicklas 1489               â†’ <code>Users</code>. The back-ticks (`) around the table name tells Hibernate
5673 27 Jun 11 nicklas 1490               to enclose the name in whatever the actual database manager uses for such things 
5673 27 Jun 11 nicklas 1491               (back-ticks in MySQL, quotes for an ANSI-compatible database).
3715 11 Sep 07 nicklas 1492             </para>
5673 27 Jun 11 nicklas 1493             
5673 27 Jun 11 nicklas 1494             <important>
5673 27 Jun 11 nicklas 1495               <title>Always set the lazy attribute</title>
5673 27 Jun 11 nicklas 1496               <para>
5673 27 Jun 11 nicklas 1497                 The <sgmltag class="attribute">lazy</sgmltag> attribute enables/disables 
5673 27 Jun 11 nicklas 1498                 proxies for the class. Do not forget to specify this attribute since the 
5673 27 Jun 11 nicklas 1499                 default value is true. If proxies are enabled, it may also make sense to 
5673 27 Jun 11 nicklas 1500                 specify a <sgmltag class="attribute">batch-size</sgmltag> attribute. Then 
5673 27 Jun 11 nicklas 1501                 Hibernate will load the specified number of items in each SELECT statement
5673 27 Jun 11 nicklas 1502                 instead of loading them one by one. It may also make sense to specify a 
5673 27 Jun 11 nicklas 1503                 batch size when proxies are disabled, but then it would probably be even 
5673 27 Jun 11 nicklas 1504                 better to use eager fetching by setting <code>outer-join="true"</code>
5673 27 Jun 11 nicklas 1505                 (see many-to-one mapping).
5673 27 Jun 11 nicklas 1506               </para>
5673 27 Jun 11 nicklas 1507   
5673 27 Jun 11 nicklas 1508               <para>
5673 27 Jun 11 nicklas 1509                 Classes that are linked with a many-to-one association from a batchable 
5673 27 Jun 11 nicklas 1510                 class must specify <code>lazy="true"</code>. Otherwise the stateless session
5673 27 Jun 11 nicklas 1511                 feature of Hibernate may result in a large number of SELECT:s for the same 
5673 27 Jun 11 nicklas 1512                 item, or even circular loops if two or more items references each other.
5673 27 Jun 11 nicklas 1513               </para>
5673 27 Jun 11 nicklas 1514             </important>
5673 27 Jun 11 nicklas 1515             
5673 27 Jun 11 nicklas 1516             <important>
5673 27 Jun 11 nicklas 1517               <title>Remember to enable the second-level cache</title>
5673 27 Jun 11 nicklas 1518               <para>
5673 27 Jun 11 nicklas 1519                 Do not forget to configure settings for the second-level cache if this
5673 27 Jun 11 nicklas 1520                 should be enabled. This is done in the <filename>hibernate.cfg.xml</filename>
5673 27 Jun 11 nicklas 1521                 and <filename>ehcache.xml</filename>.
5673 27 Jun 11 nicklas 1522               </para>
5673 27 Jun 11 nicklas 1523             </important>
3715 11 Sep 07 nicklas 1524           
3715 11 Sep 07 nicklas 1525             <para>
5673 27 Jun 11 nicklas 1526             See also:
3715 11 Sep 07 nicklas 1527             </para>
5673 27 Jun 11 nicklas 1528             
5673 27 Jun 11 nicklas 1529             <itemizedlist>
5673 27 Jun 11 nicklas 1530             <listitem>
5673 27 Jun 11 nicklas 1531               <para>
5673 27 Jun 11 nicklas 1532               "Hibernate in action", chapter 3.3 "Defining the mapping metadata", page 75-87
5673 27 Jun 11 nicklas 1533               </para>
5673 27 Jun 11 nicklas 1534             </listitem>
5673 27 Jun 11 nicklas 1535             <listitem>
5673 27 Jun 11 nicklas 1536               <para>
5673 27 Jun 11 nicklas 1537               Hibernate reference documentation: <ulink 
5673 27 Jun 11 nicklas 1538                 url="http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#mapping-declaration-class">5.1.3. Entity</ulink>
5673 27 Jun 11 nicklas 1539               </para>
5673 27 Jun 11 nicklas 1540             </listitem>
5673 27 Jun 11 nicklas 1541             </itemizedlist>
5673 27 Jun 11 nicklas 1542             
3715 11 Sep 07 nicklas 1543           </listitem>
5673 27 Jun 11 nicklas 1544         </varlistentry>
5673 27 Jun 11 nicklas 1545
5673 27 Jun 11 nicklas 1546         <varlistentry>
5673 27 Jun 11 nicklas 1547           <term>Property mappings</term>
3715 11 Sep 07 nicklas 1548           <listitem>
3715 11 Sep 07 nicklas 1549             <para>
5673 27 Jun 11 nicklas 1550               Properties such as strings, integers, dates, etc. are mapped with
5673 27 Jun 11 nicklas 1551               the <code>@hibernate.property</code> Javadoc tag. The main purpose 
5673 27 Jun 11 nicklas 1552               is to define the database column name. The column names should
5673 27 Jun 11 nicklas 1553               generally be the same as the get/set method name without the get/set prefix, 
5673 27 Jun 11 nicklas 1554               and with upper-case letters converted to lower-case and an underscore inserted. 
5673 27 Jun 11 nicklas 1555               Examples:
3715 11 Sep 07 nicklas 1556             </para>
5673 27 Jun 11 nicklas 1557             
5673 27 Jun 11 nicklas 1558             <itemizedlist>
5673 27 Jun 11 nicklas 1559             <listitem>
5673 27 Jun 11 nicklas 1560               <para>
5673 27 Jun 11 nicklas 1561                 <methodname>getAddress()</methodname>
5673 27 Jun 11 nicklas 1562                 â†’ <code>column="`address`"</code>
5673 27 Jun 11 nicklas 1563               </para>
5673 27 Jun 11 nicklas 1564             </listitem>
5673 27 Jun 11 nicklas 1565             <listitem>
5673 27 Jun 11 nicklas 1566               <para>
5673 27 Jun 11 nicklas 1567                 <methodname>getLoginComment()</methodname>
5673 27 Jun 11 nicklas 1568                 â†’ <code>column="`login_comment`"</code>
5673 27 Jun 11 nicklas 1569               </para>
5673 27 Jun 11 nicklas 1570             </listitem>
5673 27 Jun 11 nicklas 1571             </itemizedlist>
5673 27 Jun 11 nicklas 1572
3715 11 Sep 07 nicklas 1573             <para>
5673 27 Jun 11 nicklas 1574               The back-ticks (`) around the column name tells Hibernate to enclose 
5673 27 Jun 11 nicklas 1575               the name in whatever the actual database manager uses for such things 
5673 27 Jun 11 nicklas 1576               (back-ticks in MySQL, quotes for an ANSI-compatible database).
3715 11 Sep 07 nicklas 1577             </para>
5673 27 Jun 11 nicklas 1578             
5673 27 Jun 11 nicklas 1579             <bridgehead>String properties</bridgehead>
5673 27 Jun 11 nicklas 1580             <programlisting language="java">
3715 11 Sep 07 nicklas 1581 public static int long MAX_STRINGPROPERTY_LENGTH = 255;
3715 11 Sep 07 nicklas 1582 private String stringProperty;
3715 11 Sep 07 nicklas 1583 /**
3715 11 Sep 07 nicklas 1584    Get the string property.
3715 11 Sep 07 nicklas 1585    @hibernate.property column="`string_property`" type="string" 
3715 11 Sep 07 nicklas 1586       length="255" not-null="true"
3715 11 Sep 07 nicklas 1587 */
3715 11 Sep 07 nicklas 1588 public String getStringProperty()
3715 11 Sep 07 nicklas 1589 {
3715 11 Sep 07 nicklas 1590    return stringProperty;
3715 11 Sep 07 nicklas 1591 }
3715 11 Sep 07 nicklas 1592 public void setStringProperty(String stringProperty)
3715 11 Sep 07 nicklas 1593 {
3715 11 Sep 07 nicklas 1594    this.stringProperty = stringProperty;
3715 11 Sep 07 nicklas 1595 }
3715 11 Sep 07 nicklas 1596 </programlisting>
3715 11 Sep 07 nicklas 1597
5673 27 Jun 11 nicklas 1598             <para>
5673 27 Jun 11 nicklas 1599               Do not use a greater value than 255 for the <sgmltag class="attribute">length</sgmltag>
5673 27 Jun 11 nicklas 1600               attribute. Some databases has that as the maximum length for character columns (ie. MySQL). 
5673 27 Jun 11 nicklas 1601               If you need to store longer texts use <code>type="text"</code> instead. You can then skip 
5673 27 Jun 11 nicklas 1602               the length attribute. Most databases will allow up to 65535 characters or more 
5673 27 Jun 11 nicklas 1603               in a text field. Do not forget to specify the <sgmltag class="attribute">not-null</sgmltag> attribute.
5673 27 Jun 11 nicklas 1604             </para>
5673 27 Jun 11 nicklas 1605             
5673 27 Jun 11 nicklas 1606             <para>
5673 27 Jun 11 nicklas 1607               You should also define a public constant <constant>MAX_STRINGPROPERTY_LENGTH</constant>
5673 27 Jun 11 nicklas 1608               containing the maximum allowed length of the string.
5673 27 Jun 11 nicklas 1609             </para>
5673 27 Jun 11 nicklas 1610
5673 27 Jun 11 nicklas 1611             <bridgehead>Numerical properties</bridgehead>
5673 27 Jun 11 nicklas 1612             
5673 27 Jun 11 nicklas 1613             <programlisting language="java">
3715 11 Sep 07 nicklas 1614 private int intProperty;
3715 11 Sep 07 nicklas 1615 /**
3715 11 Sep 07 nicklas 1616    Get the int property.
3715 11 Sep 07 nicklas 1617    @hibernate.property column="`int_property`" type="int" not-null="true"
3715 11 Sep 07 nicklas 1618 */
3715 11 Sep 07 nicklas 1619 public int getIntProperty()
3715 11 Sep 07 nicklas 1620 {
3715 11 Sep 07 nicklas 1621    return intProperty;
3715 11 Sep 07 nicklas 1622 }
3715 11 Sep 07 nicklas 1623 public void setIntProperty(int intProperty)
3715 11 Sep 07 nicklas 1624 {
3715 11 Sep 07 nicklas 1625    this.intProperty = intProperty;
3715 11 Sep 07 nicklas 1626 }
3715 11 Sep 07 nicklas 1627 </programlisting>
3715 11 Sep 07 nicklas 1628
5673 27 Jun 11 nicklas 1629             <para>
5673 27 Jun 11 nicklas 1630               It is also possible to use <classname>Integer</classname>, <classname>Long</classname>
5673 27 Jun 11 nicklas 1631               or <classname>Float</classname> objects instead of <classname>int</classname>,
5673 27 Jun 11 nicklas 1632               <classname>long</classname> and <classname>float</classname>. We have only used it 
5673 27 Jun 11 nicklas 1633               if null values have some meaning.
5673 27 Jun 11 nicklas 1634             </para>
5673 27 Jun 11 nicklas 1635             
5673 27 Jun 11 nicklas 1636             <bridgehead>Boolean properties</bridgehead>
5673 27 Jun 11 nicklas 1637             <programlisting language="java">
3715 11 Sep 07 nicklas 1638 private boolean booleanProperty;
3715 11 Sep 07 nicklas 1639 /**
3715 11 Sep 07 nicklas 1640    Get the boolean property.
3715 11 Sep 07 nicklas 1641    @hibernate.property column="`boolean_property`" 
3715 11 Sep 07 nicklas 1642       type="boolean" not-null="true"
3715 11 Sep 07 nicklas 1643 */
3715 11 Sep 07 nicklas 1644 public boolean isBooleanProperty()
3715 11 Sep 07 nicklas 1645 {
3715 11 Sep 07 nicklas 1646    return booleanProperty;
3715 11 Sep 07 nicklas 1647 }
3715 11 Sep 07 nicklas 1648 public void setBooleanProperty(boolean booleanProperty)
3715 11 Sep 07 nicklas 1649 {
3715 11 Sep 07 nicklas 1650    this.booleanProperty = booleanProperty;
3715 11 Sep 07 nicklas 1651 }
3715 11 Sep 07 nicklas 1652 </programlisting>
5673 27 Jun 11 nicklas 1653             <para>
5673 27 Jun 11 nicklas 1654               It is also possible to use a <classname>Boolean</classname> object instead of
5673 27 Jun 11 nicklas 1655               <classname>boolean</classname>. It is only required if you absolutely need 
5673 27 Jun 11 nicklas 1656               null values to handle special cases.
5673 27 Jun 11 nicklas 1657             </para>
5673 27 Jun 11 nicklas 1658
5673 27 Jun 11 nicklas 1659             <bridgehead>Date values</bridgehead>
5673 27 Jun 11 nicklas 1660             
5673 27 Jun 11 nicklas 1661             <programlisting language="java">
3715 11 Sep 07 nicklas 1662 private Date dateProperty;
3715 11 Sep 07 nicklas 1663 /**
3715 11 Sep 07 nicklas 1664    Get the date property. Null is allowed.
3715 11 Sep 07 nicklas 1665    @hibernate.property column="`date_property`" type="date" not-null="false"
3715 11 Sep 07 nicklas 1666 */
3715 11 Sep 07 nicklas 1667 public Date getDateProperty()
3715 11 Sep 07 nicklas 1668 {
3715 11 Sep 07 nicklas 1669    return dateProperty;
3715 11 Sep 07 nicklas 1670 }
3715 11 Sep 07 nicklas 1671 public void setDateProperty(Date dateProperty)
3715 11 Sep 07 nicklas 1672 {
3715 11 Sep 07 nicklas 1673    this.dateProperty = dateProperty;
3715 11 Sep 07 nicklas 1674 }
3715 11 Sep 07 nicklas 1675 </programlisting>
3715 11 Sep 07 nicklas 1676         
5673 27 Jun 11 nicklas 1677           <para>
5673 27 Jun 11 nicklas 1678             Hibernate defines several other date and time types. We have decided to use
5673 27 Jun 11 nicklas 1679             the <code>type="date"</code> type when we are only interested in the date and 
5673 27 Jun 11 nicklas 1680             the <code>type="timestamp"</code> when we are interested in both the date 
5673 27 Jun 11 nicklas 1681             and time.
5673 27 Jun 11 nicklas 1682           </para>
5673 27 Jun 11 nicklas 1683           
5673 27 Jun 11 nicklas 1684           <para>
5673 27 Jun 11 nicklas 1685           See also: 
5673 27 Jun 11 nicklas 1686           </para>
5673 27 Jun 11 nicklas 1687           
5673 27 Jun 11 nicklas 1688           <itemizedlist>
5673 27 Jun 11 nicklas 1689             <listitem>
5673 27 Jun 11 nicklas 1690               <para>
5673 27 Jun 11 nicklas 1691               "Hibernate in action", chapter 3.3.2 "Basic property and class mappings", page 78-84
5673 27 Jun 11 nicklas 1692               </para>
5673 27 Jun 11 nicklas 1693             </listitem>
5673 27 Jun 11 nicklas 1694             <listitem>
5673 27 Jun 11 nicklas 1695               <para>
5673 27 Jun 11 nicklas 1696               "Hibernate in action", chapter 6.1.1 "Built-in mapping types", page 198-200
5673 27 Jun 11 nicklas 1697               </para>
5673 27 Jun 11 nicklas 1698             </listitem>
5673 27 Jun 11 nicklas 1699             <listitem>
5673 27 Jun 11 nicklas 1700               <para>
5673 27 Jun 11 nicklas 1701               Hibernate reference documentation: <ulink 
5673 27 Jun 11 nicklas 1702                 url="http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#mapping-declaration-property">5.1.4. property</ulink>
5673 27 Jun 11 nicklas 1703               </para>
5673 27 Jun 11 nicklas 1704             </listitem>
5673 27 Jun 11 nicklas 1705             <listitem>
5673 27 Jun 11 nicklas 1706               <para>
5673 27 Jun 11 nicklas 1707               Hibernate reference documentation: <ulink 
5673 27 Jun 11 nicklas 1708                 url="http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#mapping-types-basictypes">5.2.2. Basic value types</ulink>
5673 27 Jun 11 nicklas 1709               </para>
5673 27 Jun 11 nicklas 1710             </listitem>
5673 27 Jun 11 nicklas 1711             </itemizedlist>
5673 27 Jun 11 nicklas 1712                 
3715 11 Sep 07 nicklas 1713           </listitem>
5673 27 Jun 11 nicklas 1714         </varlistentry>
5673 27 Jun 11 nicklas 1715
5673 27 Jun 11 nicklas 1716         <varlistentry id="core_ref.rules.datalayer.manytoone">
5673 27 Jun 11 nicklas 1717           <term>Many-to-one mappings</term>
3715 11 Sep 07 nicklas 1718           <listitem>
5673 27 Jun 11 nicklas 1719             <programlisting language="java">
3715 11 Sep 07 nicklas 1720 private OtherData other;
3715 11 Sep 07 nicklas 1721 /**
3715 11 Sep 07 nicklas 1722    Get the other object.
3715 11 Sep 07 nicklas 1723    @hibernate.many-to-one column="`other_id`" not-null="true" outer-join="false"
3715 11 Sep 07 nicklas 1724 */
3715 11 Sep 07 nicklas 1725 public OtherData getOther()
3715 11 Sep 07 nicklas 1726 {
3715 11 Sep 07 nicklas 1727    return other;
3715 11 Sep 07 nicklas 1728 }
3715 11 Sep 07 nicklas 1729 public void setOther(OtherData other)
3715 11 Sep 07 nicklas 1730 {
3715 11 Sep 07 nicklas 1731    this.other = other;
3715 11 Sep 07 nicklas 1732 }
3715 11 Sep 07 nicklas 1733 </programlisting>
3715 11 Sep 07 nicklas 1734           
5673 27 Jun 11 nicklas 1735           <para>
5673 27 Jun 11 nicklas 1736             We create a many-to-one mapping with the <code>@hibernate.many-to-one</code> tag. 
5673 27 Jun 11 nicklas 1737             The most important attribute is the <code>column</code> attribute which specifies the name of 
5673 27 Jun 11 nicklas 1738             the database column to use for the id of the other item. The back-ticks (`) 
5673 27 Jun 11 nicklas 1739             around the column name tells Hibernate to enclose the name in whatever the 
5673 27 Jun 11 nicklas 1740             actual database manager uses for such things (back-ticks in MySQL, quotes for 
5673 27 Jun 11 nicklas 1741             an ANSI-compatible database).
5673 27 Jun 11 nicklas 1742           </para>
3715 11 Sep 07 nicklas 1743           
5673 27 Jun 11 nicklas 1744           <para>
5673 27 Jun 11 nicklas 1745             We also recommend that the <sgmltag class="attribute">not-null</sgmltag> attribute 
5673 27 Jun 11 nicklas 1746             is specified. Hibernate will not check for null values, but it will generate table 
5673 27 Jun 11 nicklas 1747             columns that allow or disallow null values. See it as en extra safety feature while debugging. 
5673 27 Jun 11 nicklas 1748             It is also used to determine if Hibernate uses <code>LEFT JOIN</code> or 
5673 27 Jun 11 nicklas 1749             <code>INNER JOIN</code> in SQL statements.
5673 27 Jun 11 nicklas 1750           </para>
5673 27 Jun 11 nicklas 1751           
5673 27 Jun 11 nicklas 1752           <para>
5673 27 Jun 11 nicklas 1753             The <sgmltag class="attribute">outer-join</sgmltag> attribute is important and affects how the 
5673 27 Jun 11 nicklas 1754             cache and proxies are used. It can take three values: <constant>auto</constant>,
5673 27 Jun 11 nicklas 1755             <constant>true</constant> or <constant>false</constant>. If the value is 
5673 27 Jun 11 nicklas 1756             <constant>true</constant> Hibernate will always use a join to load the linked 
5673 27 Jun 11 nicklas 1757             object in a single select statement, overriding the cache and proxy settings. 
5673 27 Jun 11 nicklas 1758             This value should only be used if the class being linked has disabled both 
5673 27 Jun 11 nicklas 1759             proxies and the second-level cache, or if it is a link between a child 
5673 27 Jun 11 nicklas 1760             and parent in a parent-child relationship. A <constant>false</constant> value is best when
5673 27 Jun 11 nicklas 1761             we expect the associated object to be in the second-level cache or proxying 
5673 27 Jun 11 nicklas 1762             is enabled. This is probably the most common case. The auto setting uses a 
5673 27 Jun 11 nicklas 1763             join if proxying is disabled otherwise it uses a proxy. Since we always 
5673 27 Jun 11 nicklas 1764             know if proxying is enabled or not, this setting is not very useful. See 
5673 27 Jun 11 nicklas 1765             <xref linkend="core_ref.rules.datalayer.cacheproxysettings" /> for the 
5673 27 Jun 11 nicklas 1766             recommended settings.
5673 27 Jun 11 nicklas 1767           </para>
5673 27 Jun 11 nicklas 1768           
5673 27 Jun 11 nicklas 1769           <para>
5673 27 Jun 11 nicklas 1770             See also:
5673 27 Jun 11 nicklas 1771           </para>
5673 27 Jun 11 nicklas 1772             
5673 27 Jun 11 nicklas 1773           <itemizedlist>
5673 27 Jun 11 nicklas 1774             <listitem>
5673 27 Jun 11 nicklas 1775               <para>
5673 27 Jun 11 nicklas 1776               "Hibernate in action", chapter 3.7 "Introducing associations", page 105-112
5673 27 Jun 11 nicklas 1777               </para>
5673 27 Jun 11 nicklas 1778             </listitem>
5673 27 Jun 11 nicklas 1779             <listitem>
5673 27 Jun 11 nicklas 1780               <para>
5673 27 Jun 11 nicklas 1781               "Hibernate in action", chapter 4.4.5-4.4.6 "Fetching strategies", page 143-151
5673 27 Jun 11 nicklas 1782               </para>
5673 27 Jun 11 nicklas 1783             </listitem>
5673 27 Jun 11 nicklas 1784             <listitem>
5673 27 Jun 11 nicklas 1785               <para>
5673 27 Jun 11 nicklas 1786               "Hibernate in action", chapter 6.4.1 "Polymorphic many-to-one associations", page 234-236
5673 27 Jun 11 nicklas 1787               </para>
5673 27 Jun 11 nicklas 1788             </listitem>
5673 27 Jun 11 nicklas 1789             <listitem>
5673 27 Jun 11 nicklas 1790               <para>
5673 27 Jun 11 nicklas 1791               Hibernate reference documentation: <ulink 
5673 27 Jun 11 nicklas 1792                 url="http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#d0e7576">5.1.7. Mapping one to one and many to one associations</ulink>
5673 27 Jun 11 nicklas 1793               </para>
5673 27 Jun 11 nicklas 1794             </listitem>
5673 27 Jun 11 nicklas 1795             </itemizedlist>
3715 11 Sep 07 nicklas 1796           </listitem>
5673 27 Jun 11 nicklas 1797         </varlistentry>
5673 27 Jun 11 nicklas 1798
5673 27 Jun 11 nicklas 1799         <varlistentry id="core_ref.rules.datalayer.manytomany">
5673 27 Jun 11 nicklas 1800           <term>Many-to-many and one-to-many mappings</term>
3715 11 Sep 07 nicklas 1801           <listitem>
3715 11 Sep 07 nicklas 1802             <para>
5673 27 Jun 11 nicklas 1803               There are many variants of mapping many-to-many or one-to-many, and it is 
5673 27 Jun 11 nicklas 1804               not possible to give examples of all of them. In the code these mappings 
5673 27 Jun 11 nicklas 1805               are represented by <classname>Set</classname>:s, <classname>Map</classname>:s,
5673 27 Jun 11 nicklas 1806               <classname>List</classname>:s, or some other collection object. The most 
5673 27 Jun 11 nicklas 1807               important thing to remember is that (in our application) the collections 
5673 27 Jun 11 nicklas 1808               are only used to maintain the links between objects. They are (in most cases)
5673 27 Jun 11 nicklas 1809               not used for returning objects to client applications, as is the case with the 
5673 27 Jun 11 nicklas 1810               many-to-one mapping.
3715 11 Sep 07 nicklas 1811             </para>
5673 27 Jun 11 nicklas 1812             
3715 11 Sep 07 nicklas 1813             <para>
5673 27 Jun 11 nicklas 1814               For example, if we want to find all members of a group we do not use the 
5673 27 Jun 11 nicklas 1815               <code>GroupData.getUsers()</code> method, instead we will execute a database query
5673 27 Jun 11 nicklas 1816               to retrieve them. The reason for this design is that the logged in user may 
5673 27 Jun 11 nicklas 1817               not have access to all users and we must add a permission checking filter 
5673 27 Jun 11 nicklas 1818               before returning the user objects to the client application. Using a query
5673 27 Jun 11 nicklas 1819               will also allow client applications to specify sorting and filtering options 
5673 27 Jun 11 nicklas 1820               for the users that are returned.
3715 11 Sep 07 nicklas 1821             </para>
5673 27 Jun 11 nicklas 1822             <programlisting language="java">
5673 27 Jun 11 nicklas 1823 <![CDATA[
3715 11 Sep 07 nicklas 1824 // RoleData.java
5673 27 Jun 11 nicklas 1825 private Set<UserData> users;
3715 11 Sep 07 nicklas 1826 /**
5673 27 Jun 11 nicklas 1827    Many-to-many from roles to users.
3715 11 Sep 07 nicklas 1828    @hibernate.set table="`UserRoles`" lazy="true"
3715 11 Sep 07 nicklas 1829    @hibernate.collection-key column="`role_id`"
3715 11 Sep 07 nicklas 1830    @hibernate.collection-many-to-many column="`user_id`" 
3715 11 Sep 07 nicklas 1831       class="net.sf.basedb.core.data.UserData"
3715 11 Sep 07 nicklas 1832 */
5673 27 Jun 11 nicklas 1833 public Set<UserData> getUsers()
3715 11 Sep 07 nicklas 1834 {
5673 27 Jun 11 nicklas 1835    if (users == null) users = new HashSet<UserData>();
3715 11 Sep 07 nicklas 1836    return users;
3715 11 Sep 07 nicklas 1837 }
3715 11 Sep 07 nicklas 1838 void setUsers(Set&lt;UserData&gt; users)
3715 11 Sep 07 nicklas 1839 {
3715 11 Sep 07 nicklas 1840    this.users = users;
3715 11 Sep 07 nicklas 1841 }
5673 27 Jun 11 nicklas 1842 ]]>
3715 11 Sep 07 nicklas 1843 </programlisting>
5673 27 Jun 11 nicklas 1844             <para>
5673 27 Jun 11 nicklas 1845               As you can see this mapping is a lot more complicated than what we have 
5673 27 Jun 11 nicklas 1846               seen before. The most important thing is the <sgmltag class="attribute">lazy</sgmltag>
5673 27 Jun 11 nicklas 1847               attribute. It tells Hibernate to delay the loading of the related objects until the set 
5673 27 Jun 11 nicklas 1848               is accessed. If the value is false or missing, Hibernate will load all objects 
5673 27 Jun 11 nicklas 1849               immediately. There is almost never a good reason to specify something other 
5673 27 Jun 11 nicklas 1850               than <code>lazy="true"</code>.
5673 27 Jun 11 nicklas 1851             </para>
5673 27 Jun 11 nicklas 1852             
5673 27 Jun 11 nicklas 1853             <para>
5673 27 Jun 11 nicklas 1854               Another important thing to remember is that the getter method must always return 
5673 27 Jun 11 nicklas 1855               the same object that Hibernate passed to the setter method. Otherwise, Hibernate 
5673 27 Jun 11 nicklas 1856               will not be able to detect changes made to the collection and as a result 
5673 27 Jun 11 nicklas 1857               will have to delete and then recreate all links. To ensure that the collection
5673 27 Jun 11 nicklas 1858               object is not changed we have made the <methodname>setUsers()</methodname> method 
5673 27 Jun 11 nicklas 1859               package private, and the <methodname>getUsers()</methodname> will create a 
5673 27 Jun 11 nicklas 1860               new <classname>HashSet</classname> for us only if Hibernate didn't pass one 
5673 27 Jun 11 nicklas 1861               in the first place.
5673 27 Jun 11 nicklas 1862             </para>
5673 27 Jun 11 nicklas 1863             <para>
5673 27 Jun 11 nicklas 1864               Let's also have a look at the reverse mapping:
5673 27 Jun 11 nicklas 1865             </para>
5673 27 Jun 11 nicklas 1866             
5673 27 Jun 11 nicklas 1867             <programlisting language="java">
5673 27 Jun 11 nicklas 1868 <![CDATA[
3715 11 Sep 07 nicklas 1869 // UserData.java
5673 27 Jun 11 nicklas 1870 private Set<RoleData> roles;
3715 11 Sep 07 nicklas 1871 /**
3715 11 Sep 07 nicklas 1872    Many-to-many from users to roles
3715 11 Sep 07 nicklas 1873    @hibernate.set table="`UserRoles`" lazy="true"
3715 11 Sep 07 nicklas 1874    @hibernate.collection-key column="`user_id`"
3715 11 Sep 07 nicklas 1875    @hibernate.collection-many-to-many column="`role_id`" 
3715 11 Sep 07 nicklas 1876       class="net.sf.basedb.core.data.RoleData"
3715 11 Sep 07 nicklas 1877 */
5673 27 Jun 11 nicklas 1878 Set<RoleData> getRoles()
3715 11 Sep 07 nicklas 1879 {
3715 11 Sep 07 nicklas 1880    return roles;
3715 11 Sep 07 nicklas 1881 }
5673 27 Jun 11 nicklas 1882 void setRoles(Set<RoleData> roles)
3715 11 Sep 07 nicklas 1883 {
3715 11 Sep 07 nicklas 1884    this.roles = roles;
3715 11 Sep 07 nicklas 1885 }
5673 27 Jun 11 nicklas 1886 ]]>
3715 11 Sep 07 nicklas 1887 </programlisting>
3715 11 Sep 07 nicklas 1888             <para>
5673 27 Jun 11 nicklas 1889               The only real difference here is that both the setter and the getter methods 
5673 27 Jun 11 nicklas 1890               are package private. This is a safety measure because Hibernate will get confused if 
5673 27 Jun 11 nicklas 1891               we modify both ends. Thus, we are forced to always add/remove users to/from 
5673 27 Jun 11 nicklas 1892               the set in the <classname docapi="net.sf.basedb.core.data">RoleData</classname> object. The methods in the
5673 27 Jun 11 nicklas 1893               <classname docapi="net.sf.basedb.core.data">UserData</classname> class are never used by us.
5673 27 Jun 11 nicklas 1894               Note that we do not have to check for null and create a new set since Hibernate 
5673 27 Jun 11 nicklas 1895               will handle null values as an empty set.
3715 11 Sep 07 nicklas 1896             </para>
5673 27 Jun 11 nicklas 1897             <para>
5673 27 Jun 11 nicklas 1898               So, why do we need the second collection at all? It is never accessed 
5673 27 Jun 11 nicklas 1899               except by Hibernate, and since it is lazy it will always be "empty". 
5673 27 Jun 11 nicklas 1900               The answer is that we want to use the relation in HQL statements.
5673 27 Jun 11 nicklas 1901               For example:
5673 27 Jun 11 nicklas 1902             </para>
3715 11 Sep 07 nicklas 1903             
5673 27 Jun 11 nicklas 1904             <programlisting language="sql">
5673 27 Jun 11 nicklas 1905 SELECT ... FROM RoleData rle WHERE rle.users ...
5673 27 Jun 11 nicklas 1906 SELECT ... FROM UserData usr WHERE usr.roles ...
5673 27 Jun 11 nicklas 1907 </programlisting>
5673 27 Jun 11 nicklas 1908           
3715 11 Sep 07 nicklas 1909             <para>
5673 27 Jun 11 nicklas 1910               Without the second mapping, it would not have been possible to execute 
5673 27 Jun 11 nicklas 1911               the second HQL statement. The inverse mapping is also important in 
5673 27 Jun 11 nicklas 1912               parent-child relationships, where it is used to cascade delete the children 
5673 27 Jun 11 nicklas 1913               if a parent is deleted (see below).
3715 11 Sep 07 nicklas 1914             </para>
3715 11 Sep 07 nicklas 1915
5673 27 Jun 11 nicklas 1916             <warning>
5673 27 Jun 11 nicklas 1917               <title>Do not use the inverse="true" setting</title>
5673 27 Jun 11 nicklas 1918               <para>
5673 27 Jun 11 nicklas 1919                 Hibernate defines an <code>inverse="true"</code> setting that can be used with 
5673 27 Jun 11 nicklas 1920                 the <code>@hibernate.set</code> tag. If specified, Hibernate will ignore 
5673 27 Jun 11 nicklas 1921                 changes made to that collection. However, there is one problem with specifying 
5673 27 Jun 11 nicklas 1922                 this attribute. Hibernate doesn't delete entries in the association table, 
5673 27 Jun 11 nicklas 1923                 leading to foreign key violations if we try to delete a user. The only 
5673 27 Jun 11 nicklas 1924                 solutions are to skip the <code>inverse="true"</code> attribute or to 
5673 27 Jun 11 nicklas 1925                 manually delete the object from all collections on the non-inverse end. 
5673 27 Jun 11 nicklas 1926                 The first alternative is the most efficient since it only requires a 
5673 27 Jun 11 nicklas 1927                 single SQL statement. The second alternative must first load all associated 
5673 27 Jun 11 nicklas 1928                 objects and then issue a single delete statement for each association.
5673 27 Jun 11 nicklas 1929               </para>
5673 27 Jun 11 nicklas 1930               
5673 27 Jun 11 nicklas 1931               <para>
5673 27 Jun 11 nicklas 1932                 In the "Hibernate in action" book they have a very different design 
5673 27 Jun 11 nicklas 1933                 where they recommend that changes are made in both collections. We don't 
5673 27 Jun 11 nicklas 1934                 have to do this since we are only interested in maintaining the links, 
5673 27 Jun 11 nicklas 1935                 which is always done in one of the collections.
5673 27 Jun 11 nicklas 1936               </para>
5673 27 Jun 11 nicklas 1937             </warning>
3715 11 Sep 07 nicklas 1938
5673 27 Jun 11 nicklas 1939             <bridgehead>Parent-child relationships</bridgehead>
5673 27 Jun 11 nicklas 1940   
5673 27 Jun 11 nicklas 1941             <para>
5673 27 Jun 11 nicklas 1942               When one or more objects are tightly linked to some other object we talk 
5673 27 Jun 11 nicklas 1943               about a parent-child relationship. This kind of relationship becomes important 
5673 27 Jun 11 nicklas 1944               when we are about to delete a parent object. The children cannot exist
5673 27 Jun 11 nicklas 1945               without the parent so they must also be deleted. Luckily, Hibernate can 
5673 27 Jun 11 nicklas 1946               do this for us if we specify a <code>cascade="delete"</code> option for the link. 
5673 27 Jun 11 nicklas 1947               This example is a one-to-many link between client and help texts.
5673 27 Jun 11 nicklas 1948             </para>
3715 11 Sep 07 nicklas 1949
5673 27 Jun 11 nicklas 1950             <programlisting language="java">
5673 27 Jun 11 nicklas 1951 <![CDATA[
3715 11 Sep 07 nicklas 1952 // ClientData.java
5673 27 Jun 11 nicklas 1953 private Set<HelpData> helpTexts;
3715 11 Sep 07 nicklas 1954 /**
3715 11 Sep 07 nicklas 1955    This is the inverse end.
3715 11 Sep 07 nicklas 1956    @see HelpData#getClient()
3715 11 Sep 07 nicklas 1957    @hibernate.set lazy="true" inverse="true" cascade="delete"
3715 11 Sep 07 nicklas 1958    @hibernate.collection-key column="`client_id`"
3715 11 Sep 07 nicklas 1959    @hibernate.collection-one-to-many class="net.sf.basedb.core.data.HelpData"
3715 11 Sep 07 nicklas 1960 */
5673 27 Jun 11 nicklas 1961 Set<HelpData> getHelpTexts()
3715 11 Sep 07 nicklas 1962 {
3715 11 Sep 07 nicklas 1963    return helpTexts;
3715 11 Sep 07 nicklas 1964 }
3715 11 Sep 07 nicklas 1965
5673 27 Jun 11 nicklas 1966 void setHelpTexts(Set<HelpData> helpTexts)
3715 11 Sep 07 nicklas 1967 {
3715 11 Sep 07 nicklas 1968    this.helpTexts = helpTexts;
3715 11 Sep 07 nicklas 1969 }
3715 11 Sep 07 nicklas 1970
3715 11 Sep 07 nicklas 1971 // HelpData.java
3715 11 Sep 07 nicklas 1972 private ClientData client;
3715 11 Sep 07 nicklas 1973 /**
3715 11 Sep 07 nicklas 1974    Get the client for this help text.
3715 11 Sep 07 nicklas 1975    @hibernate.many-to-one column="`client_id`" not-null="true" 
3715 11 Sep 07 nicklas 1976       update="false" outer-join="false" unique-key="uniquehelp"
3715 11 Sep 07 nicklas 1977 */
3715 11 Sep 07 nicklas 1978 public ClientData getClient()
3715 11 Sep 07 nicklas 1979 {
3715 11 Sep 07 nicklas 1980    return client;
3715 11 Sep 07 nicklas 1981 }
3715 11 Sep 07 nicklas 1982 public void setClient(ClientData client)
3715 11 Sep 07 nicklas 1983 {
3715 11 Sep 07 nicklas 1984    this.client = client;
3715 11 Sep 07 nicklas 1985 }
5673 27 Jun 11 nicklas 1986 ]]>
3715 11 Sep 07 nicklas 1987 </programlisting>
5673 27 Jun 11 nicklas 1988             <para>
5673 27 Jun 11 nicklas 1989               This show both sides of the one-to-many mapping between parent and children. 
5673 27 Jun 11 nicklas 1990               As you can see the <code>@hibernate.set</code> doesn't specify a table, 
5673 27 Jun 11 nicklas 1991               since it is given by the <code>class</code> attribute of the 
5673 27 Jun 11 nicklas 1992               <code>@hibernate.collection-one-to-many</code> tag. 
5673 27 Jun 11 nicklas 1993             </para>
5673 27 Jun 11 nicklas 1994             
5673 27 Jun 11 nicklas 1995             <para>
5673 27 Jun 11 nicklas 1996               In a one-to-many mapping, it is always the "one" side that handles the 
5673 27 Jun 11 nicklas 1997               link so the "many" side should always be mapped with <code>inverse="true"</code>.
5673 27 Jun 11 nicklas 1998             </para>
3715 11 Sep 07 nicklas 1999
5673 27 Jun 11 nicklas 2000             <bridgehead>Maps</bridgehead>
5673 27 Jun 11 nicklas 2001             
5673 27 Jun 11 nicklas 2002             <para>
5673 27 Jun 11 nicklas 2003               Another type of many-to-many mapping uses a <interfacename>Map</interfacename>
5673 27 Jun 11 nicklas 2004               for the collection. This kind of mapping is needed when the association between
5673 27 Jun 11 nicklas 2005               two objects needs additional data to be kept as part of the association.
5673 27 Jun 11 nicklas 2006               For example, the permission (stored as an integer value) given to users that 
5673 27 Jun 11 nicklas 2007               are members of a project. Note that you should use a <interfacename>Set</interfacename>
5673 27 Jun 11 nicklas 2008               for mapping the inverse end.
5673 27 Jun 11 nicklas 2009             </para>
5673 27 Jun 11 nicklas 2010             <programlisting language="java">
5673 27 Jun 11 nicklas 2011 <![CDATA[
3715 11 Sep 07 nicklas 2012 // ProjectData.java
5673 27 Jun 11 nicklas 2013 private Map<UserData, Integer> users;
3715 11 Sep 07 nicklas 2014 /**
3715 11 Sep 07 nicklas 2015    Many-to-many mapping between projects and users including permission values.
3715 11 Sep 07 nicklas 2016    @hibernate.map table="`UserProjects`" lazy="true"
3715 11 Sep 07 nicklas 2017    @hibernate.collection-key column="`project_id`"
3715 11 Sep 07 nicklas 2018    @hibernate.index-many-to-many column="`user_id`" 
3715 11 Sep 07 nicklas 2019       class="net.sf.basedb.core.data.UserData"
3715 11 Sep 07 nicklas 2020    @hibernate.collection-element column="`permission`" type="int" not-null="true"
3715 11 Sep 07 nicklas 2021 */
5673 27 Jun 11 nicklas 2022 public Map<UserData, Integer> getUsers()
3715 11 Sep 07 nicklas 2023 {
5673 27 Jun 11 nicklas 2024    if (users == null) users = new HashMap<UserData, Integer>();
3715 11 Sep 07 nicklas 2025    return users;
3715 11 Sep 07 nicklas 2026 }
5673 27 Jun 11 nicklas 2027 void setUsers(Map<UserData, Integer> users)
3715 11 Sep 07 nicklas 2028 {
3715 11 Sep 07 nicklas 2029    this.users = users;
3715 11 Sep 07 nicklas 2030 }
3715 11 Sep 07 nicklas 2031
3715 11 Sep 07 nicklas 2032 // UserData.java
5673 27 Jun 11 nicklas 2033 private Set<ProjectData> projects;
3715 11 Sep 07 nicklas 2034 /**
3715 11 Sep 07 nicklas 2035    This is the inverse end.
3715 11 Sep 07 nicklas 2036    @see ProjectData#getUsers()
3715 11 Sep 07 nicklas 2037    @hibernate.set table="`UserProjects`" lazy="true"
3715 11 Sep 07 nicklas 2038    @hibernate.collection-key column="`user_id`"
3715 11 Sep 07 nicklas 2039    @hibernate.collection-many-to-many column="`project_id`"
3715 11 Sep 07 nicklas 2040       class="net.sf.basedb.core.data.ProjectData"
3715 11 Sep 07 nicklas 2041 */
5673 27 Jun 11 nicklas 2042 Set<ProjectData> getProjects()
3715 11 Sep 07 nicklas 2043 {
3715 11 Sep 07 nicklas 2044    return projects;
3715 11 Sep 07 nicklas 2045 }
5673 27 Jun 11 nicklas 2046 void setProjects(Set<ProjectData> projects)
3715 11 Sep 07 nicklas 2047 {
3715 11 Sep 07 nicklas 2048    this.projects = projects;
3715 11 Sep 07 nicklas 2049 }
5673 27 Jun 11 nicklas 2050 ]]>
3715 11 Sep 07 nicklas 2051 </programlisting>
5673 27 Jun 11 nicklas 2052           <para>
5673 27 Jun 11 nicklas 2053             See also:
5673 27 Jun 11 nicklas 2054           </para>
5673 27 Jun 11 nicklas 2055           
5673 27 Jun 11 nicklas 2056           <itemizedlist>
5673 27 Jun 11 nicklas 2057             <listitem>
5673 27 Jun 11 nicklas 2058               <para>
5673 27 Jun 11 nicklas 2059               "Hibernate in action", chapter 3.7 "Introducing associations", page 105-112
5673 27 Jun 11 nicklas 2060               </para>
5673 27 Jun 11 nicklas 2061             </listitem>
5673 27 Jun 11 nicklas 2062             <listitem>
5673 27 Jun 11 nicklas 2063               <para>
5673 27 Jun 11 nicklas 2064               "Hibernate in action", chapter 6.2 "Mapping collections of value types", page 211-220
5673 27 Jun 11 nicklas 2065               </para>
5673 27 Jun 11 nicklas 2066             </listitem>
5673 27 Jun 11 nicklas 2067             <listitem>
5673 27 Jun 11 nicklas 2068               <para>
5673 27 Jun 11 nicklas 2069               "Hibernate in action", chapter 6.3.2 "Many-to-many associations", page 225-233
5673 27 Jun 11 nicklas 2070               </para>
5673 27 Jun 11 nicklas 2071             </listitem>
5673 27 Jun 11 nicklas 2072             <listitem>
5673 27 Jun 11 nicklas 2073               <para>
5673 27 Jun 11 nicklas 2074               Hibernate reference documentation: <ulink 
5673 27 Jun 11 nicklas 2075                 url="http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/collections.html">Chapter 7. Collection Mapping</ulink>
5673 27 Jun 11 nicklas 2076               </para>
5673 27 Jun 11 nicklas 2077             </listitem>
5673 27 Jun 11 nicklas 2078             <listitem>
5673 27 Jun 11 nicklas 2079               <para>
5673 27 Jun 11 nicklas 2080               Hibernate reference documentation: <ulink 
5673 27 Jun 11 nicklas 2081                 url="http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/example-parentchild.html">Chapter 24. Example: Parent/Child</ulink>
5673 27 Jun 11 nicklas 2082               </para>
5673 27 Jun 11 nicklas 2083             </listitem>
5673 27 Jun 11 nicklas 2084             </itemizedlist>
5673 27 Jun 11 nicklas 2085             
3715 11 Sep 07 nicklas 2086           </listitem>
5673 27 Jun 11 nicklas 2087         </varlistentry>
5673 27 Jun 11 nicklas 2088
5673 27 Jun 11 nicklas 2089         <varlistentry>
5673 27 Jun 11 nicklas 2090           <term>One-to-one mappings</term>
3715 11 Sep 07 nicklas 2091           <listitem>
3715 11 Sep 07 nicklas 2092             <para>
5673 27 Jun 11 nicklas 2093               A one-to-one mapping can come in two different forms, depending on if both
5673 27 Jun 11 nicklas 2094               objects should have the same id or not. We start with the case were the objects 
5673 27 Jun 11 nicklas 2095               can have different id:s and the link is done with an extra column in one of 
5673 27 Jun 11 nicklas 2096               the tables. The example is from the mapping between physical bioassays and 
5673 27 Jun 11 nicklas 2097               arrayslides.
3715 11 Sep 07 nicklas 2098             </para>
3715 11 Sep 07 nicklas 2099
5673 27 Jun 11 nicklas 2100             <programlisting language="java">
5673 27 Jun 11 nicklas 2101 // PhysicalBioAssayData.java
3715 11 Sep 07 nicklas 2102 private ArraySlideData arrayslide;
3715 11 Sep 07 nicklas 2103 /**
3715 11 Sep 07 nicklas 2104    Get the array slide
5673 27 Jun 11 nicklas 2105    @hibernate.many-to-one column="`arrayslide_id`" not-null="false" 
5673 27 Jun 11 nicklas 2106       unique="true" outer-join="false"
3715 11 Sep 07 nicklas 2107 */
3715 11 Sep 07 nicklas 2108 public ArraySlideData getArraySlide()
3715 11 Sep 07 nicklas 2109 {
3715 11 Sep 07 nicklas 2110    return arrayslide;
3715 11 Sep 07 nicklas 2111 }
3715 11 Sep 07 nicklas 2112 public void setArraySlide(ArraySlideData arrayslide)
3715 11 Sep 07 nicklas 2113 {
3715 11 Sep 07 nicklas 2114    this.arrayslide = arrayslide;
3715 11 Sep 07 nicklas 2115 }
3715 11 Sep 07 nicklas 2116
3715 11 Sep 07 nicklas 2117 // ArraySlideData.java
5673 27 Jun 11 nicklas 2118 private PhysicalBioAssayData bioassay;
3715 11 Sep 07 nicklas 2119 /**
5673 27 Jun 11 nicklas 2120    Get the bioassay.
3715 11 Sep 07 nicklas 2121    @hibernate.one-to-one property-ref="arraySlide"
3715 11 Sep 07 nicklas 2122 */
5673 27 Jun 11 nicklas 2123 public PhysicalBioAssayData getPhysicalBioAssay()
3715 11 Sep 07 nicklas 2124 {
3715 11 Sep 07 nicklas 2125    return hybridization;
3715 11 Sep 07 nicklas 2126 }
5673 27 Jun 11 nicklas 2127 public void setPhysicalBioAssay(PhysicalBioAssayData bioassay)
3715 11 Sep 07 nicklas 2128 {
5673 27 Jun 11 nicklas 2129    this.bioassay = bioassay;
3715 11 Sep 07 nicklas 2130 }          
3715 11 Sep 07 nicklas 2131 </programlisting>
5673 27 Jun 11 nicklas 2132             <para>
5673 27 Jun 11 nicklas 2133               As you can see, we use the <code>@hibernate.many-to-one</code> mapping with <code>unique="true"</code>
5673 27 Jun 11 nicklas 2134               for the bioassay side. This will force the database to only allow the 
5673 27 Jun 11 nicklas 2135               same array slide to be linked once. Also note that since, <code>not-null="false"</code>,
5673 27 Jun 11 nicklas 2136               null values are allowed and it doesn't matter which end of the relation that
5673 27 Jun 11 nicklas 2137               is inserted first into the database.
5673 27 Jun 11 nicklas 2138             </para>
5673 27 Jun 11 nicklas 2139             <para>
5673 27 Jun 11 nicklas 2140               For the array slide end we use a <code>@hibernate.one-to-one</code>
5673 27 Jun 11 nicklas 2141               mapping and specify the name of the property on the other end that we are
5673 27 Jun 11 nicklas 2142               linking to. One important thing to remember is to keep both ends synchronized.
5673 27 Jun 11 nicklas 2143               This should usually be done at the core layer and not in the data layer.
5673 27 Jun 11 nicklas 2144               Doing it in the data layer may effectively disable lazy loading if the synchronization
5673 27 Jun 11 nicklas 2145               code causes proxy initialization.
5673 27 Jun 11 nicklas 2146             </para>
3715 11 Sep 07 nicklas 2147
5673 27 Jun 11 nicklas 2148             <para>
5673 27 Jun 11 nicklas 2149               The second form of a one-to-one mapping is used when both objects must 
5673 27 Jun 11 nicklas 2150               have the same id (primary key). The example is from the mapping between users 
5673 27 Jun 11 nicklas 2151               and passwords.
5673 27 Jun 11 nicklas 2152             </para>
5673 27 Jun 11 nicklas 2153             
5673 27 Jun 11 nicklas 2154             <programlisting language="java">
3715 11 Sep 07 nicklas 2155 // UserData.java
3715 11 Sep 07 nicklas 2156 /**
3715 11 Sep 07 nicklas 2157    @hibernate.id column="`id`" generator-class="foreign"
3715 11 Sep 07 nicklas 2158    @hibernate.generator-param name="property" value="password"
3715 11 Sep 07 nicklas 2159 */
3715 11 Sep 07 nicklas 2160 public int getId()
3715 11 Sep 07 nicklas 2161 {
3715 11 Sep 07 nicklas 2162    return super.getId();
3715 11 Sep 07 nicklas 2163 }
3715 11 Sep 07 nicklas 2164 private PasswordData password;
3715 11 Sep 07 nicklas 2165 /**
3715 11 Sep 07 nicklas 2166    Get the password.
3715 11 Sep 07 nicklas 2167    @hibernate.one-to-one class="net.sf.basedb.core.data.PasswordData"
3715 11 Sep 07 nicklas 2168       cascade="all" outer-join="false" constrained="true"
3715 11 Sep 07 nicklas 2169 */
3715 11 Sep 07 nicklas 2170 public PasswordData getPassword()
3715 11 Sep 07 nicklas 2171 {
3715 11 Sep 07 nicklas 2172    if (password == null)
3715 11 Sep 07 nicklas 2173    {
3715 11 Sep 07 nicklas 2174       password = new PasswordData();
3715 11 Sep 07 nicklas 2175       password.setUser(this);
3715 11 Sep 07 nicklas 2176    }
3715 11 Sep 07 nicklas 2177    return password;
3715 11 Sep 07 nicklas 2178 }
3715 11 Sep 07 nicklas 2179 void setPassword(PasswordData user)
3715 11 Sep 07 nicklas 2180 {
3715 11 Sep 07 nicklas 2181    this.password = password;
3715 11 Sep 07 nicklas 2182 }
3715 11 Sep 07 nicklas 2183
3715 11 Sep 07 nicklas 2184 // PasswordData.java
3715 11 Sep 07 nicklas 2185 private UserData user;
3715 11 Sep 07 nicklas 2186 /**
3715 11 Sep 07 nicklas 2187    Get the user.
3715 11 Sep 07 nicklas 2188    @hibernate.one-to-one class="net.sf.basedb.core.data.UserData"
3715 11 Sep 07 nicklas 2189 */
3715 11 Sep 07 nicklas 2190 public UserData getUser()
3715 11 Sep 07 nicklas 2191 {
3715 11 Sep 07 nicklas 2192    return user;
3715 11 Sep 07 nicklas 2193 }
3715 11 Sep 07 nicklas 2194 void setUser(UserData user)
3715 11 Sep 07 nicklas 2195 {
3715 11 Sep 07 nicklas 2196    this.user = user;
3715 11 Sep 07 nicklas 2197 }
3715 11 Sep 07 nicklas 2198 </programlisting>
3715 11 Sep 07 nicklas 2199           
3715 11 Sep 07 nicklas 2200             <para>
5673 27 Jun 11 nicklas 2201               In this case, we use the <code>@hibernate.one-to-one</code> mapping
5673 27 Jun 11 nicklas 2202               in both classes. The <code>constrained="true"</code> tag in <classname docapi="net.sf.basedb.core.data">UserData</classname>
5673 27 Jun 11 nicklas 2203               tells Hibernate to always insert the password first, and then the user. The makes it
5673 27 Jun 11 nicklas 2204               possible to use the (auto-generated) id for the password as the id 
5673 27 Jun 11 nicklas 2205               for the user. This is controlled by the mapping for the <methodname>UserData.getId()</methodname>
5673 27 Jun 11 nicklas 2206               method, which uses the <code>foreign</code> id generator. This generator will look 
5673 27 Jun 11 nicklas 2207               at the password property, ie. call <methodname>getPassword().getId()</methodname>
5673 27 Jun 11 nicklas 2208               to find the id for the user. Also note the initialisation code and <code>cascade="all"</code>
5673 27 Jun 11 nicklas 2209               tag in the <methodname>UserData.getPassword()</methodname> method. This is needed
5673 27 Jun 11 nicklas 2210               to avoid <classname>NullPointerException</classname>:s and to make sure everything
5673 27 Jun 11 nicklas 2211               is created and deleted properly.
3715 11 Sep 07 nicklas 2212             </para>
5673 27 Jun 11 nicklas 2213
5673 27 Jun 11 nicklas 2214             <para>
5673 27 Jun 11 nicklas 2215               See also:
5673 27 Jun 11 nicklas 2216             </para>
5673 27 Jun 11 nicklas 2217             
5673 27 Jun 11 nicklas 2218           <itemizedlist>
5673 27 Jun 11 nicklas 2219             <listitem>
5673 27 Jun 11 nicklas 2220               <para>
5673 27 Jun 11 nicklas 2221               "Hibernate in action", chapter 6.3.1 "One-to-one association", page 220-225
5673 27 Jun 11 nicklas 2222               </para>
5673 27 Jun 11 nicklas 2223             </listitem>
5673 27 Jun 11 nicklas 2224             <listitem>
5673 27 Jun 11 nicklas 2225               <para>
5673 27 Jun 11 nicklas 2226               Hibernate reference documentation: <ulink 
5673 27 Jun 11 nicklas 2227                 url="http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#d0e7576">5.1.7. 5.1.7. Mapping one to one and many to one associations</ulink>
5673 27 Jun 11 nicklas 2228               </para>
5673 27 Jun 11 nicklas 2229             </listitem>
5673 27 Jun 11 nicklas 2230             </itemizedlist>
5673 27 Jun 11 nicklas 2231
3715 11 Sep 07 nicklas 2232           </listitem>
5673 27 Jun 11 nicklas 2233         </varlistentry>
5673 27 Jun 11 nicklas 2234
5673 27 Jun 11 nicklas 2235         <varlistentry>
5673 27 Jun 11 nicklas 2236           <term>Class documentation</term>
3715 11 Sep 07 nicklas 2237           <listitem>
3715 11 Sep 07 nicklas 2238             <para>
5673 27 Jun 11 nicklas 2239               The documentation for the class doesn't have to be very lengthy. A single 
5673 27 Jun 11 nicklas 2240               sentence is usually enough. Provide tags for the author, version, last modification date 
5673 27 Jun 11 nicklas 2241               and a reference to the corresponding class in the <package>net.sf.basedb.core</package>
5673 27 Jun 11 nicklas 2242               package.
3715 11 Sep 07 nicklas 2243             </para>
5673 27 Jun 11 nicklas 2244             
5673 27 Jun 11 nicklas 2245             <programlisting language="java">
3715 11 Sep 07 nicklas 2246 /**
3715 11 Sep 07 nicklas 2247    This class holds information about any items.
3715 11 Sep 07 nicklas 2248
3715 11 Sep 07 nicklas 2249    @author Your name
5673 27 Jun 11 nicklas 2250    @since 2.0
3715 11 Sep 07 nicklas 2251    @see net.sf.basedb.core.AnyItem
3715 11 Sep 07 nicklas 2252    @base.modified $Date: 2007-08-17 09:18:29 +0200 (Fri, 17 Aug 2007) $
3715 11 Sep 07 nicklas 2253    @hibernate.class table="`Anys`" lazy="false"
3715 11 Sep 07 nicklas 2254 */
3715 11 Sep 07 nicklas 2255 public class AnyData
3715 11 Sep 07 nicklas 2256    extends CommonData
3715 11 Sep 07 nicklas 2257 {
3715 11 Sep 07 nicklas 2258 ...
3715 11 Sep 07 nicklas 2259 }
3715 11 Sep 07 nicklas 2260 </programlisting>
5673 27 Jun 11 nicklas 2261           </listitem>
5673 27 Jun 11 nicklas 2262         </varlistentry>
5673 27 Jun 11 nicklas 2263
5673 27 Jun 11 nicklas 2264         <varlistentry>
5673 27 Jun 11 nicklas 2265           <term>Method documentation</term>
5673 27 Jun 11 nicklas 2266           <listitem>
5673 27 Jun 11 nicklas 2267             <para>
5673 27 Jun 11 nicklas 2268             Write a short one-sentence description for all public getter methods. You do not 
5673 27 Jun 11 nicklas 2269             have document the parameters or the setter methods, since it would just be a 
5673 27 Jun 11 nicklas 2270             repetition. Methods defined by interfaces are documented in the interface class. 
5673 27 Jun 11 nicklas 2271             You should not have to write any documentation for those methods.
5673 27 Jun 11 nicklas 2272             </para>
5673 27 Jun 11 nicklas 2273             
5673 27 Jun 11 nicklas 2274             <para>
5673 27 Jun 11 nicklas 2275               For the inverse end of an association, which has only package private methods, 
5673 27 Jun 11 nicklas 2276               write a notice about this and provide a link to to non-inverse end.
5673 27 Jun 11 nicklas 2277             </para>
5673 27 Jun 11 nicklas 2278             
5673 27 Jun 11 nicklas 2279             <programlisting language="java">
5673 27 Jun 11 nicklas 2280 <![CDATA[
3715 11 Sep 07 nicklas 2281 // UserData.java
3715 11 Sep 07 nicklas 2282 private String address;
3715 11 Sep 07 nicklas 2283 /**
3715 11 Sep 07 nicklas 2284    Get the address for the user.
3715 11 Sep 07 nicklas 2285    @hibernate.property column="`address`" type="string" length="255"
3715 11 Sep 07 nicklas 2286 */
3715 11 Sep 07 nicklas 2287 public String getAddress()
3715 11 Sep 07 nicklas 2288 {
3715 11 Sep 07 nicklas 2289    return address;
3715 11 Sep 07 nicklas 2290 }
3715 11 Sep 07 nicklas 2291 public void setAddress(String address)
3715 11 Sep 07 nicklas 2292 {
3715 11 Sep 07 nicklas 2293    this.address = address;
3715 11 Sep 07 nicklas 2294 }
3715 11 Sep 07 nicklas 2295
5673 27 Jun 11 nicklas 2296 private Set<GroupData> groups;
3715 11 Sep 07 nicklas 2297 /**
3715 11 Sep 07 nicklas 2298    This is the inverse end.
3715 11 Sep 07 nicklas 2299    @see GroupData#getUsers()
3715 11 Sep 07 nicklas 2300    @hibernate.set table="`UserGroups`" lazy="true" inverse="true"
3715 11 Sep 07 nicklas 2301    @hibernate.collection-key column="`user_id`"
3715 11 Sep 07 nicklas 2302    @hibernate.collection-many-to-many column="`group_id`"
3715 11 Sep 07 nicklas 2303       class="net.sf.basedb.core.data.GroupData"
3715 11 Sep 07 nicklas 2304 */
5673 27 Jun 11 nicklas 2305 Set<GroupData> getGroups()
3715 11 Sep 07 nicklas 2306 {
3715 11 Sep 07 nicklas 2307    return groups;
3715 11 Sep 07 nicklas 2308 }
5673 27 Jun 11 nicklas 2309 void setGroups(Set<GroupData> groups)
3715 11 Sep 07 nicklas 2310 {
3715 11 Sep 07 nicklas 2311    this.groups = groups;
3715 11 Sep 07 nicklas 2312 }
5673 27 Jun 11 nicklas 2313 ]]>
3715 11 Sep 07 nicklas 2314 </programlisting>
5673 27 Jun 11 nicklas 2315           </listitem>
5673 27 Jun 11 nicklas 2316         </varlistentry>
5673 27 Jun 11 nicklas 2317
5673 27 Jun 11 nicklas 2318         <varlistentry>
5673 27 Jun 11 nicklas 2319           <term>Field documentation</term>
5673 27 Jun 11 nicklas 2320           <listitem>
5673 27 Jun 11 nicklas 2321             <para>
5673 27 Jun 11 nicklas 2322               Write a short one-sentence description for <code>public static final</code>
5673 27 Jun 11 nicklas 2323               fields. Private fields does not have to be documented.
5673 27 Jun 11 nicklas 2324             </para>
5673 27 Jun 11 nicklas 2325             
5673 27 Jun 11 nicklas 2326             <programlisting language="java">
3715 11 Sep 07 nicklas 2327 /**
3715 11 Sep 07 nicklas 2328    The maximum length of the name of an item that can be
3715 11 Sep 07 nicklas 2329    stored in the database.
3715 11 Sep 07 nicklas 2330    @see #setName(String)
3715 11 Sep 07 nicklas 2331 */
5673 27 Jun 11 nicklas 2332 public static final int MAX_NAME_LENGTH = 255;
3715 11 Sep 07 nicklas 2333 </programlisting>
5673 27 Jun 11 nicklas 2334           </listitem>
5673 27 Jun 11 nicklas 2335         </varlistentry>
3715 11 Sep 07 nicklas 2336
5673 27 Jun 11 nicklas 2337         <varlistentry>
5673 27 Jun 11 nicklas 2338           <term>UML diagram</term>
5673 27 Jun 11 nicklas 2339           <listitem>
3715 11 Sep 07 nicklas 2340           <para>
3715 11 Sep 07 nicklas 2341             Groups of related classes should be included in an UML-like 
3715 11 Sep 07 nicklas 2342             diagram to show how they are connected and work together.
3715 11 Sep 07 nicklas 2343             For example we group together users, groups, roles, etc. into an 
3715 11 Sep 07 nicklas 2344             authentication UML diagram. It is also possible that a single class 
3715 11 Sep 07 nicklas 2345             may appear in more than one diagram. For more information about
3715 11 Sep 07 nicklas 2346             how to create UML diagrams see 
3715 11 Sep 07 nicklas 2347             <xref linkend="documentation.magicdraw" />.
3715 11 Sep 07 nicklas 2348           </para>
5673 27 Jun 11 nicklas 2349           </listitem>
5673 27 Jun 11 nicklas 2350         </varlistentry>
5673 27 Jun 11 nicklas 2351       </variablelist>
3715 11 Sep 07 nicklas 2352
3715 11 Sep 07 nicklas 2353     </sect2>
3315 09 May 07 nicklas 2354     <sect2 id="core_ref.rules.itemclass">
3315 09 May 07 nicklas 2355       <title>Item-class rules</title>
5675 28 Jun 11 nicklas 2356       
3315 09 May 07 nicklas 2357       <para>
5675 28 Jun 11 nicklas 2358         This document contains important information about item classes for the BASE developer. 
5675 28 Jun 11 nicklas 2359         Item classes are classes that handles the business logic for the data classes in 
5675 28 Jun 11 nicklas 2360         the <code>net.sf.basedb.core.data</code> package. In general there is one item class for 
5675 28 Jun 11 nicklas 2361         each data class. When extending the database and creating new classes it is important 
5675 28 Jun 11 nicklas 2362         that it follows the design of the already existing code. 
3315 09 May 07 nicklas 2363       </para>
5675 28 Jun 11 nicklas 2364       
5675 28 Jun 11 nicklas 2365       <sect3 id="core_ref.rules.itemclass.basic">
5675 28 Jun 11 nicklas 2366         <title>Basic class and interface hierarchy</title>
5675 28 Jun 11 nicklas 2367       
5675 28 Jun 11 nicklas 2368         <para>
5675 28 Jun 11 nicklas 2369           To simplify the development of items, we have created a set of abstract classes 
5675 28 Jun 11 nicklas 2370           and interfaces. A real class for an item must inherit from one of those classes 
5675 28 Jun 11 nicklas 2371           and may implement any of the interfaces if needed. The strucure is similar to the 
5675 28 Jun 11 nicklas 2372           structure found in the <code>net.sf.basedb.core.data</code> package 
5780 04 Oct 11 nicklas 2373           (See <xref linkend="base_api.data" />). 
5675 28 Jun 11 nicklas 2374         </para>
5675 28 Jun 11 nicklas 2375
5675 28 Jun 11 nicklas 2376         <figure id="core_ref.figures.basic">
5675 28 Jun 11 nicklas 2377           <title>Basic class and interface hierarchy</title>
5675 28 Jun 11 nicklas 2378           <screenshot>
5675 28 Jun 11 nicklas 2379             <mediaobject>
5675 28 Jun 11 nicklas 2380               <imageobject>
5675 28 Jun 11 nicklas 2381                 <imagedata 
5675 28 Jun 11 nicklas 2382                   align="center"
5675 28 Jun 11 nicklas 2383                   fileref="figures/uml/corelayer.basic.png" format="PNG" />
5675 28 Jun 11 nicklas 2384               </imageobject>
5675 28 Jun 11 nicklas 2385             </mediaobject>
5675 28 Jun 11 nicklas 2386           </screenshot>
5675 28 Jun 11 nicklas 2387         </figure>
5675 28 Jun 11 nicklas 2388       
5675 28 Jun 11 nicklas 2389       </sect3>
5675 28 Jun 11 nicklas 2390       
5675 28 Jun 11 nicklas 2391       <sect3 id="core_ref.rules.itemclass.permissions">
5675 28 Jun 11 nicklas 2392         <title>Access permissions</title>
5675 28 Jun 11 nicklas 2393         <para>
5675 28 Jun 11 nicklas 2394           Each item class must be prepared to handle the access permissions for the 
5675 28 Jun 11 nicklas 2395           logged in user. The base classes will do most of the required work, but 
5675 28 Jun 11 nicklas 2396           not everything. There are four cases which the item class must be aware of: 
5675 28 Jun 11 nicklas 2397         </para>
5675 28 Jun 11 nicklas 2398         
5675 28 Jun 11 nicklas 2399         <itemizedlist>
5675 28 Jun 11 nicklas 2400           <listitem><para>Initialise permissions in the <methodname>initPermissions()</methodname> method.</para></listitem>
5675 28 Jun 11 nicklas 2401           <listitem><para>Check for <emphasis>write</emphasis> permission in settter methods.</para></listitem>
5675 28 Jun 11 nicklas 2402           <listitem><para>Check for <emphasis>use</emphasis> permission when creating associations to other items.</para></listitem>
5675 28 Jun 11 nicklas 2403           <listitem><para>Make sure the <methodname>getQuery()</methodname> method returns only items with at least read permission.</para></listitem>
5675 28 Jun 11 nicklas 2404         </itemizedlist>
5675 28 Jun 11 nicklas 2405         
5675 28 Jun 11 nicklas 2406         <bridgehead id="core_ref.rules.itemclass.initpermissions">Initialise permissions</bridgehead>
5675 28 Jun 11 nicklas 2407         
5675 28 Jun 11 nicklas 2408         <para>
5675 28 Jun 11 nicklas 2409           The permissions for an item are initialised by a call to the <methodname>initPermissions()</methodname> 
5675 28 Jun 11 nicklas 2410           method. This method is called as soon as the item becomes attached to a <classname 
5675 28 Jun 11 nicklas 2411           docapi="net.sf.basedb.core">DbControl</classname> object, which is responsible for managing items 
5675 28 Jun 11 nicklas 2412           in the database. The <methodname>initPermissions()</methodname> method shuld be overridden by
5675 28 Jun 11 nicklas 2413           subclasses that needs to grant or deny permissions that is not granted or denied by default.
5675 28 Jun 11 nicklas 2414           When overriding the <methodname>initPermissions()</methodname> method it is important to:
5675 28 Jun 11 nicklas 2415         </para>
5675 28 Jun 11 nicklas 2416         
5675 28 Jun 11 nicklas 2417         <itemizedlist>
5675 28 Jun 11 nicklas 2418           <listitem>
5675 28 Jun 11 nicklas 2419             <para>
5675 28 Jun 11 nicklas 2420               Combine the additional permissions with those that was passed as parameters. 
5675 28 Jun 11 nicklas 2421               Use the binary OR operator ( | ) with the result from the <code>Permission.grant()</code>
5675 28 Jun 11 nicklas 2422               and <code>Permission.deny()</code> methods to do this.
5675 28 Jun 11 nicklas 2423             </para>
5675 28 Jun 11 nicklas 2424           </listitem>
5675 28 Jun 11 nicklas 2425           <listitem>
5675 28 Jun 11 nicklas 2426             <para>
5675 28 Jun 11 nicklas 2427               Call <code>super.initPermissions()</code>. Otherwise, no permissions will be set all, 
5675 28 Jun 11 nicklas 2428               resulting in an <classname docapi="net.sf.basedb.core">PermissionDeniedException</classname> almost immediately.
5675 28 Jun 11 nicklas 2429             </para>
5675 28 Jun 11 nicklas 2430           </listitem>
5675 28 Jun 11 nicklas 2431         </itemizedlist>
5675 28 Jun 11 nicklas 2432         
5675 28 Jun 11 nicklas 2433         <para>
5675 28 Jun 11 nicklas 2434           Here is an example from the <classname docapi="net.sf.basedb.core">OwnedItem</classname> class. 
5675 28 Jun 11 nicklas 2435           If the currently logged in user is the same as the owner of the item, <constant>DELETE</constant>, 
5675 28 Jun 11 nicklas 2436           <constant>SET_OWNER</constant> and <constant>SET_PERMISSION</constant> permissions are granted. 
5675 28 Jun 11 nicklas 2437           Remember that delete permission also implies <constant>READ</constant>, <constant>USE</constant>
5675 28 Jun 11 nicklas 2438           and <constant>WRITE</constant> permissions. 
5675 28 Jun 11 nicklas 2439         </para>
5675 28 Jun 11 nicklas 2440         
5675 28 Jun 11 nicklas 2441         <programlisting language="java">
5675 28 Jun 11 nicklas 2442 <![CDATA[
5675 28 Jun 11 nicklas 2443 // OwnedItem.java
5675 28 Jun 11 nicklas 2444 void initPermissions(int granted, int denied)
5675 28 Jun 11 nicklas 2445 {
5675 28 Jun 11 nicklas 2446    UserData owner = getData().getOwner();
5675 28 Jun 11 nicklas 2447    // owner may be null for new items
5675 28 Jun 11 nicklas 2448    if (owner != null && owner.getId() == getSessionControl().getLoggedInUserId())
5675 28 Jun 11 nicklas 2449    {
5675 28 Jun 11 nicklas 2450       granted |= Permission.grant(Permission.DELETE, Permission.SET_OWNER, 
5675 28 Jun 11 nicklas 2451          Permission.SET_PERMISSION);
5675 28 Jun 11 nicklas 2452    }
5675 28 Jun 11 nicklas 2453    super.initPermissions(granted, denied);
5675 28 Jun 11 nicklas 2454 }        
5675 28 Jun 11 nicklas 2455 ]]>
5675 28 Jun 11 nicklas 2456 </programlisting>
5675 28 Jun 11 nicklas 2457         
5675 28 Jun 11 nicklas 2458         
5675 28 Jun 11 nicklas 2459         <para>
5675 28 Jun 11 nicklas 2460           Here is another example for <classname docapi="net.sf.basedb.core">News</classname> items, 
5675 28 Jun 11 nicklas 2461           which grants read permission to anyone (even if not logged in) if today is between 
5675 28 Jun 11 nicklas 2462           the start and end date of the news entry: 
5675 28 Jun 11 nicklas 2463         </para>
5675 28 Jun 11 nicklas 2464         
5675 28 Jun 11 nicklas 2465         <programlisting language="java">
5675 28 Jun 11 nicklas 2466 <![CDATA[
5675 28 Jun 11 nicklas 2467 // News.java
5675 28 Jun 11 nicklas 2468 void initPermissions(int granted, int denied)
5675 28 Jun 11 nicklas 2469    throws BaseException
5675 28 Jun 11 nicklas 2470 {
5675 28 Jun 11 nicklas 2471    long today = new Date().getTime();
5675 28 Jun 11 nicklas 2472    long startDate = getData().getStartDate().getTime();
5675 28 Jun 11 nicklas 2473    long endDate = getData().getEndDate() == null ? 0 : getData().getEndDate().getTime()+24*3600*1000;
5675 28 Jun 11 nicklas 2474    if (startDate <= today && (endDate == 0 || today <= endDate))
5675 28 Jun 11 nicklas 2475    {
5675 28 Jun 11 nicklas 2476       granted |= Permission.grant(Permission.READ);
5675 28 Jun 11 nicklas 2477    }
5675 28 Jun 11 nicklas 2478    super.initPermissions(granted, denied);
5675 28 Jun 11 nicklas 2479 }
5675 28 Jun 11 nicklas 2480 ]]>
5675 28 Jun 11 nicklas 2481 </programlisting>
5675 28 Jun 11 nicklas 2482         
5675 28 Jun 11 nicklas 2483         <para>
5675 28 Jun 11 nicklas 2484           A third example from the <classname docapi="net.sf.basedb.core">Help</classname> class which
5675 28 Jun 11 nicklas 2485           is a child item to <classname docapi="net.sf.basedb.core">Client</classname>. Normally you will 
5675 28 Jun 11 nicklas 2486           get <constant>READ</constant> permission on all child items if you have <constant>READ</constant>
5675 28 Jun 11 nicklas 2487           permission on the parent item, and <constant>CREATE</constant>, <constant>WRITE</constant> and 
5675 28 Jun 11 nicklas 2488           <constant>DELETE</constant> permissions if you have <constant>WRITE</constant> permission on the parent item. 
5675 28 Jun 11 nicklas 2489           In this case you don't have to override the <methodname>initPermissions()</methodname> method 
5675 28 Jun 11 nicklas 2490           if the child class extends the <classname docapi="net.sf.basedb.core">ChildItem</classname> class. 
5675 28 Jun 11 nicklas 2491           Instead, it should implement the <methodname>getSharedParent()</methodname> 
5675 28 Jun 11 nicklas 2492           method. The <methodname>ChildItem.initPermissions()</methodname> will take care of checking the 
5675 28 Jun 11 nicklas 2493           permissions on the parent instead of on the child. Note that this only works if the parent itself 
5675 28 Jun 11 nicklas 2494           hasn't overridden the <methodname>initPermissions()</methodname> method, since that method is never 
5675 28 Jun 11 nicklas 2495           called in this case. 
5675 28 Jun 11 nicklas 2496         </para>
5675 28 Jun 11 nicklas 2497         
5675 28 Jun 11 nicklas 2498         <programlisting language="java">
5675 28 Jun 11 nicklas 2499 // Help.java
5675 28 Jun 11 nicklas 2500 public class Help
5675 28 Jun 11 nicklas 2501    extends ChildItem
5675 28 Jun 11 nicklas 2502    implements Nameable
5675 28 Jun 11 nicklas 2503
5675 28 Jun 11 nicklas 2504 ...
5675 28 Jun 11 nicklas 2505
5675 28 Jun 11 nicklas 2506 SharedData getSharedParent()
5675 28 Jun 11 nicklas 2507 {
5675 28 Jun 11 nicklas 2508    return getData().getClient();
5675 28 Jun 11 nicklas 2509 }
5675 28 Jun 11 nicklas 2510 </programlisting>
5675 28 Jun 11 nicklas 2511         
5675 28 Jun 11 nicklas 2512         <bridgehead>Permissions granted by the base classes</bridgehead>
5675 28 Jun 11 nicklas 2513         
5675 28 Jun 11 nicklas 2514         <variablelist>
5675 28 Jun 11 nicklas 2515           <varlistentry>
5675 28 Jun 11 nicklas 2516             <term><classname docapi="net.sf.basedb.core">BasicItem</classname></term>
5675 28 Jun 11 nicklas 2517             <listitem>
5675 28 Jun 11 nicklas 2518               <para>
5675 28 Jun 11 nicklas 2519               This class will grant or deny permissions as the are defined by the roles the logged 
5675 28 Jun 11 nicklas 2520               in user is a member of. If a subclass extend directly from this class, it is common 
5675 28 Jun 11 nicklas 2521               that the <methodname>initPermissions()</methodname> method needs to be overridden. 
5675 28 Jun 11 nicklas 2522               </para>
5675 28 Jun 11 nicklas 2523             </listitem>
5675 28 Jun 11 nicklas 2524           </varlistentry>
5675 28 Jun 11 nicklas 2525         
5675 28 Jun 11 nicklas 2526           <varlistentry>
5675 28 Jun 11 nicklas 2527             <term><classname docapi="net.sf.basedb.core">ChildItem</classname></term>
5675 28 Jun 11 nicklas 2528             <listitem>
5675 28 Jun 11 nicklas 2529               <para>
5675 28 Jun 11 nicklas 2530               This class grant <constant>READ</constant> permission if the logged in user has 
5675 28 Jun 11 nicklas 2531               <constant>READ</constant> permission on the parent item, and <constant>CREATE</constant>, 
5675 28 Jun 11 nicklas 2532               <constant>WRITE</constant> and <constant>DELETE</constant> 
5675 28 Jun 11 nicklas 2533               permission if the logged in user has <constant>WRITE</constant> (configurable) 
5675 28 Jun 11 nicklas 2534               permission on the parent item.
5675 28 Jun 11 nicklas 2535               </para>
5675 28 Jun 11 nicklas 2536             </listitem>
5675 28 Jun 11 nicklas 2537           </varlistentry>
5675 28 Jun 11 nicklas 2538         
5675 28 Jun 11 nicklas 2539           <varlistentry>
5675 28 Jun 11 nicklas 2540             <term><classname docapi="net.sf.basedb.core">OwnedItem</classname></term>
5675 28 Jun 11 nicklas 2541             <listitem>
5675 28 Jun 11 nicklas 2542               <para>
5675 28 Jun 11 nicklas 2543               The owner of an item gets <constant>DELETE</constant>, <constant>SET_OWNER</constant> 
5675 28 Jun 11 nicklas 2544               and <constant>SET_PERMISSION</constant> permissions. Delete permission also implies read, 
5675 28 Jun 11 nicklas 2545               use and write permissions. Subclasses to this class usually doesn't have to overide the 
5675 28 Jun 11 nicklas 2546               <methodname>initPermissions()</methodname> method.
5675 28 Jun 11 nicklas 2547               </para>
5675 28 Jun 11 nicklas 2548             </listitem>
5675 28 Jun 11 nicklas 2549           </varlistentry>
5675 28 Jun 11 nicklas 2550         
5675 28 Jun 11 nicklas 2551           <varlistentry>
5675 28 Jun 11 nicklas 2552             <term><classname docapi="net.sf.basedb.core">SharedItem</classname></term>
5675 28 Jun 11 nicklas 2553             <listitem>
5675 28 Jun 11 nicklas 2554               <para>
5675 28 Jun 11 nicklas 2555               The logged in user get permissions as specified in the associated <classname docapi="net.sf.basedb.core">ItemKey</classname>
5675 28 Jun 11 nicklas 2556               and/or <classname docapi="net.sf.basedb.core">ProjectmKey</classname>. Subclasses to this class usually doesn't 
5675 28 Jun 11 nicklas 2557               have to overide the <methodname>initPermissions()</methodname> method. 
5675 28 Jun 11 nicklas 2558               </para>
5675 28 Jun 11 nicklas 2559             </listitem>
5675 28 Jun 11 nicklas 2560           </varlistentry>
5675 28 Jun 11 nicklas 2561         </variablelist>
5675 28 Jun 11 nicklas 2562         
5675 28 Jun 11 nicklas 2563         <bridgehead>Checking for write permission in setter methods</bridgehead>
5675 28 Jun 11 nicklas 2564         
5675 28 Jun 11 nicklas 2565         <para>
5675 28 Jun 11 nicklas 2566           An item class is required to check for <constant>WRITE</constant> permission in each 
5675 28 Jun 11 nicklas 2567           method that modifies the state from a public method. Example: 
5675 28 Jun 11 nicklas 2568         </para>
5675 28 Jun 11 nicklas 2569         
5675 28 Jun 11 nicklas 2570         <programlisting language="java">
5675 28 Jun 11 nicklas 2571 public void setName(String name)
5675 28 Jun 11 nicklas 2572    throws PermissionDeniedException
5675 28 Jun 11 nicklas 2573 {
5675 28 Jun 11 nicklas 2574    checkPermission(Permission.WRITE);
5675 28 Jun 11 nicklas 2575    // ... rest of code
5675 28 Jun 11 nicklas 2576 }
5675 28 Jun 11 nicklas 2577 </programlisting>
5675 28 Jun 11 nicklas 2578         
5675 28 Jun 11 nicklas 2579         <warning>
5675 28 Jun 11 nicklas 2580           <para>
5675 28 Jun 11 nicklas 2581             If you forget this, an unauthorised user may be able to change the properties of an item. 
5675 28 Jun 11 nicklas 2582             <constant>WRITE</constant> permissions are not checked in any other central place in the 
5675 28 Jun 11 nicklas 2583             core code. Place the permission check on the first line in the method, before any data validation. 
5675 28 Jun 11 nicklas 2584             This will make it easier to spot places where the permission check is forgotten. 
5675 28 Jun 11 nicklas 2585           </para>
5675 28 Jun 11 nicklas 2586         </warning>
5675 28 Jun 11 nicklas 2587         
5675 28 Jun 11 nicklas 2588         <bridgehead>Checking for use permission when creating associations</bridgehead>
5675 28 Jun 11 nicklas 2589         <para>
5675 28 Jun 11 nicklas 2590           An item class is required to check for <constant>USE</constant> permission on associated objects 
5675 28 Jun 11 nicklas 2591           in each method that modifies the association from a public method. Example from the 
5675 28 Jun 11 nicklas 2592           <classname docapi="net.sf.basedb.core">Protocol</classname> class: 
5675 28 Jun 11 nicklas 2593         </para>
5675 28 Jun 11 nicklas 2594         
5675 28 Jun 11 nicklas 2595         <programlisting language="java">
5675 28 Jun 11 nicklas 2596 public void setFile(File file)
5675 28 Jun 11 nicklas 2597    throws PermissionDeniedException
5675 28 Jun 11 nicklas 2598 {
5675 28 Jun 11 nicklas 2599    checkPermission(Permission.WRITE);
5675 28 Jun 11 nicklas 2600    if (file != null) file.checkPermission(Permission.USE);
5675 28 Jun 11 nicklas 2601    getData().setFile(file == null ? null : file.getData());
5675 28 Jun 11 nicklas 2602 }
5675 28 Jun 11 nicklas 2603 </programlisting>
5675 28 Jun 11 nicklas 2604         <warning>
5675 28 Jun 11 nicklas 2605           <para>
5675 28 Jun 11 nicklas 2606             If you forget this, an unauthorised user may be able to change the association of an item. 
5675 28 Jun 11 nicklas 2607             <constant>USE</constant> permissions are not checked in any other central place in the core 
5675 28 Jun 11 nicklas 2608             code. Place the permission check as early in the method as possible after it has been validated
5675 28 Jun 11 nicklas 2609             that the value isn't null. 
5675 28 Jun 11 nicklas 2610           </para>
5675 28 Jun 11 nicklas 2611         </warning>
5675 28 Jun 11 nicklas 2612         
5675 28 Jun 11 nicklas 2613         <bridgehead id="core_ref.rules.itemclass.getquery">Making sure the getQuery() method only returns items with read permission</bridgehead>
5675 28 Jun 11 nicklas 2614         
5675 28 Jun 11 nicklas 2615         <para>
5675 28 Jun 11 nicklas 2616           This method can be one of the most complex ones of the entire class. The query it generates 
5675 28 Jun 11 nicklas 2617           must always be compatible with the <methodname>initPermissions()</methodname> method. Ie. 
5675 28 Jun 11 nicklas 2618           it must not return any items for which the <methodname>initPermissions()</methodname> method doesn't 
5675 28 Jun 11 nicklas 2619           grant <constant>READ</constant> permission. And the other way around, if the <methodname>initPermissions()</methodname>
5675 28 Jun 11 nicklas 2620           method grants <constant>READ</constant> permission to and item, the query should be able to return it. 
5675 28 Jun 11 nicklas 2621           The simplest case is if you doesn't override the <methodname>initPermissions()</methodname> method in 
5675 28 Jun 11 nicklas 2622           such a way that it affects <constant>READ</constant> permissions. In this case you can just create a 
5675 28 Jun 11 nicklas 2623           query and return it as it is. The query implementation will take care of the rest. 
5675 28 Jun 11 nicklas 2624         </para>
5675 28 Jun 11 nicklas 2625         
5675 28 Jun 11 nicklas 2626         <programlisting language="java">
5675 28 Jun 11 nicklas 2627 <![CDATA[
5675 28 Jun 11 nicklas 2628 // Client.java
5675 28 Jun 11 nicklas 2629 public static ItemQuery<Client> getQuery()
5675 28 Jun 11 nicklas 2630 {
5675 28 Jun 11 nicklas 2631    return new ItemQuery<Client>(Client.class);
5675 28 Jun 11 nicklas 2632 }
5675 28 Jun 11 nicklas 2633 ]]>
5675 28 Jun 11 nicklas 2634 </programlisting>
5675 28 Jun 11 nicklas 2635
5675 28 Jun 11 nicklas 2636         <para>
5675 28 Jun 11 nicklas 2637           A common case is when an item is the child of another item. Usually the parent is a 
5675 28 Jun 11 nicklas 2638           <classname docapi="net.sf.basedb.core">Shareable</classname> item which means that we optimally 
5675 28 Jun 11 nicklas 2639           should check the item and project keys on the parent when returning the children. But, this is a 
5675 28 Jun 11 nicklas 2640           rather complex operation, so in this case we have choosen a different approach. The 
5675 28 Jun 11 nicklas 2641           <methodname>getQuery()</methodname> method of child items must take a parameter of the parent type. 
5675 28 Jun 11 nicklas 2642           The query can the safely return all children of that parent, since having a reference to the parent item, 
5675 28 Jun 11 nicklas 2643           means that <constant>READ</constant> permission is granted. A null value for the parent is allowed, but 
5675 28 Jun 11 nicklas 2644           then we fall back to check for role permissions only (with the help of a <classname 
5675 28 Jun 11 nicklas 2645           docapi="net.sf.basedb.core">ChildFilter</classname> object). 
5675 28 Jun 11 nicklas 2646         </para>
5675 28 Jun 11 nicklas 2647         <programlisting language="java">
5675 28 Jun 11 nicklas 2648 <![CDATA[
5675 28 Jun 11 nicklas 2649 // Help.java
5675 28 Jun 11 nicklas 2650 private static final QueryRuntimeFilter RUNTIME_FILTER = 
5675 28 Jun 11 nicklas 2651    new QueryRuntimeFilterFactory.ChildFilter(Item.HELP, Item.CLIENT);
5675 28 Jun 11 nicklas 2652
5675 28 Jun 11 nicklas 2653 public static ItemQuery<Help> getQuery(Client client)
5675 28 Jun 11 nicklas 2654 {
5675 28 Jun 11 nicklas 2655    ItemQuery<Help> query = null;
5675 28 Jun 11 nicklas 2656    if (client != null)
5675 28 Jun 11 nicklas 2657    {
5675 28 Jun 11 nicklas 2658       query = new ItemQuery<Help>(Help.class, null);
5675 28 Jun 11 nicklas 2659       query.restrictPermanent(
5675 28 Jun 11 nicklas 2660          Restrictions.eq(
5675 28 Jun 11 nicklas 2661             Hql.property("client"), 
5675 28 Jun 11 nicklas 2662             Hql.entity(client)
5675 28 Jun 11 nicklas 2663          )
5675 28 Jun 11 nicklas 2664       );
5675 28 Jun 11 nicklas 2665    }
5675 28 Jun 11 nicklas 2666    else
5675 28 Jun 11 nicklas 2667    {
5675 28 Jun 11 nicklas 2668       query = new ItemQuery<Help>(Help.class, RUNTIME_FILTER);
5675 28 Jun 11 nicklas 2669    }
5675 28 Jun 11 nicklas 2670    return query;
5675 28 Jun 11 nicklas 2671 }
5675 28 Jun 11 nicklas 2672 ]]>
5675 28 Jun 11 nicklas 2673 </programlisting>
5675 28 Jun 11 nicklas 2674
5675 28 Jun 11 nicklas 2675         <para>
5675 28 Jun 11 nicklas 2676           There are many other variants of the <methodname>getQuery()</methodname> method, for example all items 
5675 28 Jun 11 nicklas 2677           having to with the authentication, <classname docapi="net.sf.basedb.core">User</classname>, 
5675 28 Jun 11 nicklas 2678           <classname docapi="net.sf.basedb.core">Group</classname>, <classname docapi="net.sf.basedb.core">Role</classname>, etc. 
5675 28 Jun 11 nicklas 2679           must check the logged in user's membership. We don't show any more examples here. Take a look in the source code 
5781 04 Oct 11 nicklas 2680           if you want more information. You can also read <xref linkend="core_api.query" /> for more examples. 
5675 28 Jun 11 nicklas 2681         </para>
5675 28 Jun 11 nicklas 2682
5675 28 Jun 11 nicklas 2683       </sect3>
5675 28 Jun 11 nicklas 2684       
5675 28 Jun 11 nicklas 2685       <sect3 id="core_ref.rules.itemclass.validation">
5675 28 Jun 11 nicklas 2686         <title>Data validation</title>
5675 28 Jun 11 nicklas 2687         
5675 28 Jun 11 nicklas 2688         <para>
5675 28 Jun 11 nicklas 2689           An item class must validate all data that is passed to it as parameters. There are three types of validation: 
5675 28 Jun 11 nicklas 2690         </para>
5675 28 Jun 11 nicklas 2691         
5675 28 Jun 11 nicklas 2692         <orderedlist>
5675 28 Jun 11 nicklas 2693           <listitem>
5675 28 Jun 11 nicklas 2694             <para>
5675 28 Jun 11 nicklas 2695             Validation of properties that are independent of other properties. For example, the length of a string or the value of number. 
5675 28 Jun 11 nicklas 2696             </para>
5675 28 Jun 11 nicklas 2697           </listitem>
5675 28 Jun 11 nicklas 2698           <listitem>
5675 28 Jun 11 nicklas 2699             <para>
5675 28 Jun 11 nicklas 2700             Validation of properties that depends on other properties on the same object. For example, we have 
5675 28 Jun 11 nicklas 2701             properties for the row and column counts, and then an array of linked objects for each position. 
5675 28 Jun 11 nicklas 2702             </para>
5675 28 Jun 11 nicklas 2703           </listitem>
5675 28 Jun 11 nicklas 2704           <listitem>
5675 28 Jun 11 nicklas 2705             <para>
5675 28 Jun 11 nicklas 2706             Validation of properties that depends on the values of other objects. For example, the login of a 
5675 28 Jun 11 nicklas 2707             user must be unique among all users. 
5675 28 Jun 11 nicklas 2708             </para>
5675 28 Jun 11 nicklas 2709           </listitem>
5675 28 Jun 11 nicklas 2710         </orderedlist>
5675 28 Jun 11 nicklas 2711         
5675 28 Jun 11 nicklas 2712         <para>
5675 28 Jun 11 nicklas 2713           For each of these types of validation we have choosen a strategy that is as simple as possible 
5675 28 Jun 11 nicklas 2714           and doesn't force us to complex requirements on the code for objects. First, we may note that 
5675 28 Jun 11 nicklas 2715           case 1 is very common, case 2 is very uncommon, and case 3 is just a bit more common than case 2. 
5675 28 Jun 11 nicklas 2716         </para>
5675 28 Jun 11 nicklas 2717         
5675 28 Jun 11 nicklas 2718         <bridgehead>Case 1 validation</bridgehead>
5675 28 Jun 11 nicklas 2719         
5675 28 Jun 11 nicklas 2720         <para>
5675 28 Jun 11 nicklas 2721           For case 1 we choose to make the validation in the set method for each property. Example: 
5675 28 Jun 11 nicklas 2722         </para>
5675 28 Jun 11 nicklas 2723         
5675 28 Jun 11 nicklas 2724         <programlisting language="java">
5675 28 Jun 11 nicklas 2725 public void setName(String name)
5675 28 Jun 11 nicklas 2726    throws InvalidDataException
5675 28 Jun 11 nicklas 2727 {
5675 28 Jun 11 nicklas 2728    checkPermission(Permission.WRITE);
5675 28 Jun 11 nicklas 2729    // Null is not allowed
5675 28 Jun 11 nicklas 2730    if (name == null) throw new InvalidUseOfNullException("name");
5675 28 Jun 11 nicklas 2731    // The name must not be too long
5675 28 Jun 11 nicklas 2732    if (name.length > MAX_NAME_LENGTH) 
5675 28 Jun 11 nicklas 2733    {
5675 28 Jun 11 nicklas 2734       throw new StringTooLongException("name", name, MAX_NAME_LENGTH);
5675 28 Jun 11 nicklas 2735    }
5675 28 Jun 11 nicklas 2736    getData().setName(name);
5675 28 Jun 11 nicklas 2737 }
5675 28 Jun 11 nicklas 2738 // Note! In this case we should actually use NameableUtil instead
5675 28 Jun 11 nicklas 2739 </programlisting>
5675 28 Jun 11 nicklas 2740       
5675 28 Jun 11 nicklas 2741         <para>
5675 28 Jun 11 nicklas 2742           This will take care of all case 1 validation except that we cannot check properties that 
5675 28 Jun 11 nicklas 2743           doesn't allow null values if the method never is called. To solve this problem we have 
5675 28 Jun 11 nicklas 2744           two strategies: 
5675 28 Jun 11 nicklas 2745         </para>
5675 28 Jun 11 nicklas 2746         
5675 28 Jun 11 nicklas 2747         <itemizedlist>
5675 28 Jun 11 nicklas 2748           <listitem>
5675 28 Jun 11 nicklas 2749             <para>
5675 28 Jun 11 nicklas 2750             Provide a default value that is set in the constructor. For example the name 
5675 28 Jun 11 nicklas 2751             of a new user can be initilised to "New user". 
5675 28 Jun 11 nicklas 2752             </para>
5675 28 Jun 11 nicklas 2753           </listitem>
5675 28 Jun 11 nicklas 2754           <listitem>
5675 28 Jun 11 nicklas 2755             <para>
5675 28 Jun 11 nicklas 2756               Use constructor methods with parameters for required objects. 
5675 28 Jun 11 nicklas 2757             </para>
5675 28 Jun 11 nicklas 2758           </listitem>
5675 28 Jun 11 nicklas 2759         </itemizedlist>
5675 28 Jun 11 nicklas 2760         
5675 28 Jun 11 nicklas 2761         <para>
5675 28 Jun 11 nicklas 2762           Which strategy to use is decided from case to case. Failure to validate a property will usually 
5675 28 Jun 11 nicklas 2763           result in a database exception, so no real harm is done, except that we don't want to show the 
5675 28 Jun 11 nicklas 2764           ugly error messages to our users. The <classname docapi="net.sf.basedb.core">News</classname>
5675 28 Jun 11 nicklas 2765           class uses a mix of the two strategies:
5675 28 Jun 11 nicklas 2766         </para>
5675 28 Jun 11 nicklas 2767         
5675 28 Jun 11 nicklas 2768         <programlisting language="java">
5675 28 Jun 11 nicklas 2769 // News.java
5675 28 Jun 11 nicklas 2770 public static News getNew(DbControl dc, Date startDate, Date newsDate)
5675 28 Jun 11 nicklas 2771 {
5675 28 Jun 11 nicklas 2772    News n = dc.newItem(News.class);
5675 28 Jun 11 nicklas 2773    n.setName("New news");
5675 28 Jun 11 nicklas 2774    n.setStartDate(startDate);
5675 28 Jun 11 nicklas 2775    n.setNewsDate(newsDate);
5675 28 Jun 11 nicklas 2776    n.getData().setEntryDate(new Date());
5675 28 Jun 11 nicklas 2777    return n;
5675 28 Jun 11 nicklas 2778 }
5675 28 Jun 11 nicklas 2779 ...
5675 28 Jun 11 nicklas 2780 public void setStartDate(Date startDate)
5675 28 Jun 11 nicklas 2781    throws PermissionDeniedException, InvalidDataException
5675 28 Jun 11 nicklas 2782 {
5675 28 Jun 11 nicklas 2783    checkPermission(Permission.WRITE);
5675 28 Jun 11 nicklas 2784    getData().setStartDate(DateUtil.setNotNullDate(startDate, "startDate"));
5675 28 Jun 11 nicklas 2785 }
5675 28 Jun 11 nicklas 2786 ...
5675 28 Jun 11 nicklas 2787 </programlisting>
5675 28 Jun 11 nicklas 2788       
5675 28 Jun 11 nicklas 2789         <bridgehead>Case 2 validation</bridgehead>
5675 28 Jun 11 nicklas 2790         
5675 28 Jun 11 nicklas 2791         <para>
5675 28 Jun 11 nicklas 2792           This case requires interception of saves and updates and a call to the <methodname>validate()</methodname>
5675 28 Jun 11 nicklas 2793           method on the item. This automatically done on items which implements the <interfacename 
5675 28 Jun 11 nicklas 2794           docapi="net.sf.basedb.core">Validatable</interfacename> interface. Internally this functionality is 
5675 28 Jun 11 nicklas 2795           implemented by the <classname docapi="net.sf.basedb.core">DbControl</classname> class, which keeps a 
5675 28 Jun 11 nicklas 2796           "commit queue" that holds all loaded items that implements the <interfacename 
5675 28 Jun 11 nicklas 2797           docapi="net.sf.basedb.core">Validatable</interfacename> interface. When <methodname>DbControl.commit()</methodname> 
5675 28 Jun 11 nicklas 2798           is called, the queue is iterated and the <methodname>validate()</methodname> method is called for each item.
5675 28 Jun 11 nicklas 2799           Here is another example from the <classname docapi="net.sf.basedb.core">News</classname> class which must 
5675 28 Jun 11 nicklas 2800           validate that the three dates (startDate, newsData and endData) are in proper order: 
5675 28 Jun 11 nicklas 2801         </para>
5675 28 Jun 11 nicklas 2802         <programlisting language="java">
5675 28 Jun 11 nicklas 2803 <![CDATA[
5675 28 Jun 11 nicklas 2804 // News.java
5675 28 Jun 11 nicklas 2805 void validate()
5675 28 Jun 11 nicklas 2806    throws InvalidDataException, BaseException
5675 28 Jun 11 nicklas 2807 {
5675 28 Jun 11 nicklas 2808    super.validate();
5675 28 Jun 11 nicklas 2809    Date startDate = getData().getStartDate();
5675 28 Jun 11 nicklas 2810    Date newsDate = getData().getNewsDate();
5675 28 Jun 11 nicklas 2811    Date endDate = getData().getEndDate();
5675 28 Jun 11 nicklas 2812    if (startDate.after(newsDate))
5675 28 Jun 11 nicklas 2813    {
5675 28 Jun 11 nicklas 2814       throw new InvalidDataException("Invalid date. startDate is after newsDate.");
5675 28 Jun 11 nicklas 2815    }
5675 28 Jun 11 nicklas 2816    if (endDate != null && newsDate.after(endDate)) 
5675 28 Jun 11 nicklas 2817    {
5675 28 Jun 11 nicklas 2818       throw new InvalidDataException("Invalid date. newsDate is after endDate.");
5675 28 Jun 11 nicklas 2819    }
5675 28 Jun 11 nicklas 2820 }
5675 28 Jun 11 nicklas 2821 ]]>
5675 28 Jun 11 nicklas 2822 </programlisting>
5675 28 Jun 11 nicklas 2823         
5675 28 Jun 11 nicklas 2824         <bridgehead>Case 3 validation</bridgehead>
5675 28 Jun 11 nicklas 2825         <para>
5675 28 Jun 11 nicklas 2826           Usually, we do not bother with checking for this case, but delegates to the database 
5675 28 Jun 11 nicklas 2827           to do the check. The reason that we do not bother to check for this case is that we can't 
5675 28 Jun 11 nicklas 2828           be sure to succeed even if we first check the database. It is possible that during the time 
5675 28 Jun 11 nicklas 2829           between our check and the actual insert or update, another transaction has already inserted 
5675 28 Jun 11 nicklas 2830           another object into the database that violates the check. This is not perfect and the error 
5675 28 Jun 11 nicklas 2831           messages are a bit ugly, but under the circumstances it is the best we can do. 
5675 28 Jun 11 nicklas 2832         </para>
5675 28 Jun 11 nicklas 2833       </sect3>
5675 28 Jun 11 nicklas 2834       
5675 28 Jun 11 nicklas 2835       <sect3 id="core_ref.rules.itemclass.transactions">
5675 28 Jun 11 nicklas 2836         <title>Participating in transactions</title>
5675 28 Jun 11 nicklas 2837         
5675 28 Jun 11 nicklas 2838         <para>
5675 28 Jun 11 nicklas 2839           Sometimes it is neccessary for an item to intercept certain events. For example, 
5675 28 Jun 11 nicklas 2840           the <classname docapi="net.sf.basedb.core">File</classname> object needs to know 
5675 28 Jun 11 nicklas 2841           if a transaction has been completed or rollbacked so it can clean up temporary 
5675 28 Jun 11 nicklas 2842           files that have been used. We have created the <interfacename 
5675 28 Jun 11 nicklas 2843           docapi="net.sf.basedb.core">Transactional</interfacename> interface, which is a tagging 
5675 28 Jun 11 nicklas 2844           interface that tells the core to call certain methods on the item at certain events. 
5675 28 Jun 11 nicklas 2845           The interface doesn't contain any methods, the item class needs to override methods 
5675 28 Jun 11 nicklas 2846           from the <classname docapi="net.sf.basedb.core">BasicItem</classname> class. The following 
5675 28 Jun 11 nicklas 2847           events/methods have been defined: 
5675 28 Jun 11 nicklas 2848         </para>
5675 28 Jun 11 nicklas 2849         
5675 28 Jun 11 nicklas 2850         <note>
5675 28 Jun 11 nicklas 2851           <para>
5675 28 Jun 11 nicklas 2852           The methods are always called for new items and items that are about to be 
5675 28 Jun 11 nicklas 2853           deleted. It is only neccessary for an item to implement the <interfacename 
5675 28 Jun 11 nicklas 2854           docapi="net.sf.basedb.core">Transactional</interfacename> interface if it 
5675 28 Jun 11 nicklas 2855           needs to act on <constant>UPDATE</constant> events.
5675 28 Jun 11 nicklas 2856           </para>
5675 28 Jun 11 nicklas 2857         </note>
5675 28 Jun 11 nicklas 2858         
5675 28 Jun 11 nicklas 2859         <variablelist>
5675 28 Jun 11 nicklas 2860           <varlistentry>
5675 28 Jun 11 nicklas 2861             <term>onBeforeCommit(Action)</term>
5675 28 Jun 11 nicklas 2862             <listitem>
5675 28 Jun 11 nicklas 2863               <para>
5675 28 Jun 11 nicklas 2864                 This method is called before a commit is issued to Hibernate. It should be used by an 
5675 28 Jun 11 nicklas 2865                 item when it needs to update dependent objects before anything is written to the database.
5675 28 Jun 11 nicklas 2866                 Note that nothing has been sent to the database yet and new items has not got an id when
5675 28 Jun 11 nicklas 2867                 this method is called. If you override this method you must call <methodname>super.onBeforeCommit()</methodname> 
5675 28 Jun 11 nicklas 2868                 to allow the superclass to do whatever it needs to do. Here is an example from the 
5675 28 Jun 11 nicklas 2869                 <classname docapi="net.sf.basedb.core">OwnedItem</classname> class which sets the owner to the 
5675 28 Jun 11 nicklas 2870                 currently logged in user, if no owner has been explicitely specified: 
5675 28 Jun 11 nicklas 2871               </para>
5675 28 Jun 11 nicklas 2872               
5675 28 Jun 11 nicklas 2873               <programlisting language="java">
5675 28 Jun 11 nicklas 2874 <![CDATA[
5675 28 Jun 11 nicklas 2875 void onBeforeCommit(Transactional.Action action)
5675 28 Jun 11 nicklas 2876    throws NotLoggedInException, BaseException
5675 28 Jun 11 nicklas 2877 {
5675 28 Jun 11 nicklas 2878    super.onBeforeCommit(action);
5675 28 Jun 11 nicklas 2879    if (action == Transactional.Action.CREATE && getData().getOwner() == null)
5675 28 Jun 11 nicklas 2880    {
5675 28 Jun 11 nicklas 2881       org.hibernate.Session session = getDbControl().getHibernateSession();
5675 28 Jun 11 nicklas 2882       int loggedInuserId = getSessionControl().getLoggedInUserId();
5675 28 Jun 11 nicklas 2883       UserData owner = 
5675 28 Jun 11 nicklas 2884          HibernateUtil.loadData(session, UserData.class, loggedInuserId);
5675 28 Jun 11 nicklas 2885       if (owner == null) throw new NotLoggedInException();
5675 28 Jun 11 nicklas 2886       getData().setOwner(owner);
5675 28 Jun 11 nicklas 2887    }
5675 28 Jun 11 nicklas 2888 }
5675 28 Jun 11 nicklas 2889 ]]>
5675 28 Jun 11 nicklas 2890 </programlisting>
5675 28 Jun 11 nicklas 2891             </listitem>
5675 28 Jun 11 nicklas 2892           </varlistentry>
5675 28 Jun 11 nicklas 2893           
5675 28 Jun 11 nicklas 2894           <varlistentry>
5675 28 Jun 11 nicklas 2895             <term>setProjectDefaults(Project)</term>
5675 28 Jun 11 nicklas 2896             <listitem>
5675 28 Jun 11 nicklas 2897               <para>
5675 28 Jun 11 nicklas 2898                 This method is called before inserting new items into the database
5675 28 Jun 11 nicklas 2899                 to allow items to propagate default values from the active project.
5675 28 Jun 11 nicklas 2900                 The method is only called when a project is active. Subclasses should
5675 28 Jun 11 nicklas 2901                 always call <methodname>super.setProjectDefaults()</methodname>
5675 28 Jun 11 nicklas 2902                 and should only set default values that hasn't been explicitely set
5675 28 Jun 11 nicklas 2903                 by client code (including <code>setFoo(null)</code> calls).
5675 28 Jun 11 nicklas 2904               </para>
5675 28 Jun 11 nicklas 2905               
5675 28 Jun 11 nicklas 2906               <note>
5675 28 Jun 11 nicklas 2907                 <para>
5675 28 Jun 11 nicklas 2908                 With few exceptions a project can only hold <classname docapi="net.sf.basedb.core">ItemSubtype</classname>
5675 28 Jun 11 nicklas 2909                 items as default values. This means that the item that is going to use the default
5675 28 Jun 11 nicklas 2910                 value should implement the <interfacename docapi="net.sf.basedb.core">Subtypeable</interfacename>
5675 28 Jun 11 nicklas 2911                 interface and list the other related item types in the <code>@SubtypableRelatedItems</code>
5675 28 Jun 11 nicklas 2912                 annotation.
5675 28 Jun 11 nicklas 2913                 </para>
5675 28 Jun 11 nicklas 2914               </note>
5675 28 Jun 11 nicklas 2915               
5675 28 Jun 11 nicklas 2916               <programlisting language="java">
5675 28 Jun 11 nicklas 2917 <![CDATA[
5820 24 Oct 11 nicklas 2918 // DerivedBioAssay.java
5675 28 Jun 11 nicklas 2919 @Override
5675 28 Jun 11 nicklas 2920 @SubtypableRelatedItems({Item.PHYSICALBIOASSAY, Item.DERIVEDBIOASSAYSET, Item.SOFTWARE, Item.HARDWARE, Item.PROTOCOL})
5675 28 Jun 11 nicklas 2921 public ItemSubtype getItemSubtype()
5675 28 Jun 11 nicklas 2922 {
5675 28 Jun 11 nicklas 2923   return getDbControl().getItem(ItemSubtype.class, getData().getItemSubtype());
5675 28 Jun 11 nicklas 2924 }
5675 28 Jun 11 nicklas 2925
5675 28 Jun 11 nicklas 2926 /**
5675 28 Jun 11 nicklas 2927   Set protocol, hardware and software from project default settings.
5675 28 Jun 11 nicklas 2928 */
5675 28 Jun 11 nicklas 2929 @Override
5675 28 Jun 11 nicklas 2930 void setProjectDefaults(Project activeProject)
5675 28 Jun 11 nicklas 2931   throws BaseException
5675 28 Jun 11 nicklas 2932 {
5675 28 Jun 11 nicklas 2933   super.setProjectDefaults(activeProject);
5675 28 Jun 11 nicklas 2934   if (!hasPermission(Permission.WRITE)) return;
5675 28 Jun 11 nicklas 2935     
5675 28 Jun 11 nicklas 2936   DbControl dc = getDbControl();
5675 28 Jun 11 nicklas 2937   if (!protocolHasBeenSet)
5675 28 Jun 11 nicklas 2938   {
5675 28 Jun 11 nicklas 2939     ProtocolData protocol = 
5675 28 Jun 11 nicklas 2940       (ProtocolData)activeProject.findDefaultRelatedData(dc, this, Item.PROTOCOL, false);
5675 28 Jun 11 nicklas 2941     if (protocol != null)
5675 28 Jun 11 nicklas 2942     {
5675 28 Jun 11 nicklas 2943       getData().setProtocol(protocol);
5675 28 Jun 11 nicklas 2944       protocolHasBeenSet = true;
5675 28 Jun 11 nicklas 2945     }
5675 28 Jun 11 nicklas 2946   }
5675 28 Jun 11 nicklas 2947   if (!hardwareHasBeenSet)
5675 28 Jun 11 nicklas 2948   {
5675 28 Jun 11 nicklas 2949     HardwareData hardware = 
5675 28 Jun 11 nicklas 2950       (HardwareData)activeProject.findDefaultRelatedData(dc, this, Item.HARDWARE, false);
5675 28 Jun 11 nicklas 2951     if (hardware != null) 
5675 28 Jun 11 nicklas 2952     {
5675 28 Jun 11 nicklas 2953       getData().setHardware(hardware);
5675 28 Jun 11 nicklas 2954       hardwareHasBeenSet = true;
5675 28 Jun 11 nicklas 2955     }
5675 28 Jun 11 nicklas 2956   }
5675 28 Jun 11 nicklas 2957   if (!softwareHasBeenSet)
5675 28 Jun 11 nicklas 2958   {
5675 28 Jun 11 nicklas 2959     SoftwareData software = 
5675 28 Jun 11 nicklas 2960       (SoftwareData)activeProject.findDefaultRelatedData(dc, this, Item.SOFTWARE, false);
5675 28 Jun 11 nicklas 2961     if (software != null) 
5675 28 Jun 11 nicklas 2962     {
5675 28 Jun 11 nicklas 2963       getData().setSoftware(software);
5675 28 Jun 11 nicklas 2964       softwareHasBeenSet = true;
5675 28 Jun 11 nicklas 2965     }
5675 28 Jun 11 nicklas 2966   }
5675 28 Jun 11 nicklas 2967 }
5675 28 Jun 11 nicklas 2968 ]]>
5675 28 Jun 11 nicklas 2969 </programlisting>
5675 28 Jun 11 nicklas 2970             </listitem>
5675 28 Jun 11 nicklas 2971           </varlistentry>
5675 28 Jun 11 nicklas 2972
5675 28 Jun 11 nicklas 2973           <varlistentry>
5675 28 Jun 11 nicklas 2974             <term>onAfterInsert()</term>
5675 28 Jun 11 nicklas 2975             <listitem>
5675 28 Jun 11 nicklas 2976               <para>
5675 28 Jun 11 nicklas 2977                 This method is called on all items directly after Hibernate has inserted 
5675 28 Jun 11 nicklas 2978                 it into the database. This method can be used in place of the 
5675 28 Jun 11 nicklas 2979                 <methodname>onBeforeCommit()</methodname> in case the id is needed.
5675 28 Jun 11 nicklas 2980               </para>
5675 28 Jun 11 nicklas 2981             </listitem>
5675 28 Jun 11 nicklas 2982           </varlistentry>
5675 28 Jun 11 nicklas 2983
5675 28 Jun 11 nicklas 2984           <varlistentry>
5675 28 Jun 11 nicklas 2985             <term>onAfterCommit(Action)</term>
5675 28 Jun 11 nicklas 2986             <listitem>
5675 28 Jun 11 nicklas 2987               <para>
5675 28 Jun 11 nicklas 2988                 This method is called after a successful commit has been issued to Hibernate. It should be 
5675 28 Jun 11 nicklas 2989                 used by an item which needs to do additional processing. For example the 
5675 28 Jun 11 nicklas 2990                 <classname docapi="net.sf.basedb.core">File</classname> object may need to cleanup temporary files. 
5675 28 Jun 11 nicklas 2991                 This method should not use the database and it must not fail, since it is impossible to rollback 
5675 28 Jun 11 nicklas 2992                 anything that has already been committed to the database. If the method fails, it should log 
5675 28 Jun 11 nicklas 2993                 an exception with the <methodname>Application.log()</methodname> method. 
5675 28 Jun 11 nicklas 2994               </para>
5675 28 Jun 11 nicklas 2995             </listitem>
5675 28 Jun 11 nicklas 2996           </varlistentry>
5675 28 Jun 11 nicklas 2997
5675 28 Jun 11 nicklas 2998           <varlistentry>
5675 28 Jun 11 nicklas 2999             <term>onRollback(Action)</term>
5675 28 Jun 11 nicklas 3000             <listitem>
5675 28 Jun 11 nicklas 3001               <para>
5675 28 Jun 11 nicklas 3002                 This method is called after an unsuccessful commit has been issued to Hibernate. The same rules as 
5675 28 Jun 11 nicklas 3003                 for the <methodname>onAfterCommit()</methodname> method applies to this method. 
5675 28 Jun 11 nicklas 3004               </para>
5675 28 Jun 11 nicklas 3005             </listitem>
5675 28 Jun 11 nicklas 3006           </varlistentry>
5675 28 Jun 11 nicklas 3007         </variablelist>
5675 28 Jun 11 nicklas 3008         
5675 28 Jun 11 nicklas 3009         <para>
5675 28 Jun 11 nicklas 3010           Internally this functionality is implemented by the <classname docapi="net.sf.basedb.core">DbControl</classname>
5675 28 Jun 11 nicklas 3011           class, which keeps a "commit queue" that holds all new objects, all objects that are about to be deleted 
5675 28 Jun 11 nicklas 3012           and all objects that implements the <interfacename docapi="net.sf.basedb.core">Transactional</interfacename> 
5675 28 Jun 11 nicklas 3013           interface. When <methodname>DbControl.commit()</methodname>  is called, the queue is iterated and 
5675 28 Jun 11 nicklas 3014           <methodname>onBeforeCommit()</methodname> is called for each item, and then 
5675 28 Jun 11 nicklas 3015           either <methodname>onAfterCommit()</methodname> or <methodname>onRollback()</methodname>.
5675 28 Jun 11 nicklas 3016           The <classname docapi="net.sf.basedb.core.Transactional">Action</classname> parameter is of an 
5675 28 Jun 11 nicklas 3017           enumeration type which can hae three different values:
5675 28 Jun 11 nicklas 3018         </para>
5675 28 Jun 11 nicklas 3019
5675 28 Jun 11 nicklas 3020
5675 28 Jun 11 nicklas 3021         <itemizedlist>
5675 28 Jun 11 nicklas 3022           <listitem>
5675 28 Jun 11 nicklas 3023             <para>
5675 28 Jun 11 nicklas 3024             <constant>CREATE</constant>: This is a new item which is saved to the database for the first time.
5675 28 Jun 11 nicklas 3025             </para>
5675 28 Jun 11 nicklas 3026           </listitem>
5675 28 Jun 11 nicklas 3027           <listitem>
5675 28 Jun 11 nicklas 3028             <para>
5675 28 Jun 11 nicklas 3029             <constant>UPDATE</constant>: This is an existing item, which has been modified.
5675 28 Jun 11 nicklas 3030             </para>
5675 28 Jun 11 nicklas 3031           </listitem>
5675 28 Jun 11 nicklas 3032           <listitem>
5675 28 Jun 11 nicklas 3033             <para>
5675 28 Jun 11 nicklas 3034             <constant>DELETE</constant>: This is an existing item, which is now being deleted from the database 
5675 28 Jun 11 nicklas 3035             </para>
5675 28 Jun 11 nicklas 3036           </listitem>
5675 28 Jun 11 nicklas 3037         </itemizedlist>
5675 28 Jun 11 nicklas 3038
5675 28 Jun 11 nicklas 3039       </sect3>
5675 28 Jun 11 nicklas 3040       
5675 28 Jun 11 nicklas 3041       <sect3 id="core_ref.rules.itemclass.template">
5675 28 Jun 11 nicklas 3042         <title>Template code for item classes</title>
5675 28 Jun 11 nicklas 3043         
5675 28 Jun 11 nicklas 3044         <para>
5675 28 Jun 11 nicklas 3045           The <ulink url="../../examples/AnyItem.java.txt">AnyItem.java</ulink> and <ulink 
5675 28 Jun 11 nicklas 3046           url="../../examples/AChildItem.java.txt">AChildItem.java</ulink> files 
5675 28 Jun 11 nicklas 3047           contains two complete item classes with lots of template methods. Please copy and paste as much as you want 
5675 28 Jun 11 nicklas 3048           from these, but do not forget to change the specific details. 
5675 28 Jun 11 nicklas 3049         </para>
5675 28 Jun 11 nicklas 3050         
5675 28 Jun 11 nicklas 3051         <bridgehead>Class declaration</bridgehead>
5675 28 Jun 11 nicklas 3052         
5675 28 Jun 11 nicklas 3053         <para>
5675 28 Jun 11 nicklas 3054           An item class should extend one of the four classes: <classname docapi="net.sf.basedb.core">BasicItem</classname>, 
5675 28 Jun 11 nicklas 3055           <classname docapi="net.sf.basedb.core">OwnedItem</classname>, <classname docapi="net.sf.basedb.core">SharedItem</classname>
5675 28 Jun 11 nicklas 3056           and <classname docapi="net.sf.basedb.core">CommonItem</classname>. Which one depends on what combination of 
5675 28 Jun 11 nicklas 3057           interfaces are needed for that item. The most common situation is probably to extend the <classname 
5675 28 Jun 11 nicklas 3058           docapi="net.sf.basedb.core">CommonItem</classname> class. Do not forget to include the GNU licence and
5675 28 Jun 11 nicklas 3059           copyright statement. Also note that the corresponding data layer class is specified as a
5675 28 Jun 11 nicklas 3060           generics parameter of the superclass.
5675 28 Jun 11 nicklas 3061         </para>
5675 28 Jun 11 nicklas 3062         
5675 28 Jun 11 nicklas 3063         <programlisting language="java">
5675 28 Jun 11 nicklas 3064 <![CDATA[
5675 28 Jun 11 nicklas 3065 /*
5675 28 Jun 11 nicklas 3066   $Id $
5675 28 Jun 11 nicklas 3067
5675 28 Jun 11 nicklas 3068   Copyright (C) 2011 Your name
5675 28 Jun 11 nicklas 3069
5675 28 Jun 11 nicklas 3070   This file is part of BASE - BioArray Software Environment.
7982 14 Jun 21 nicklas 3071   Available at https://base.thep.lu.se/
5675 28 Jun 11 nicklas 3072
5675 28 Jun 11 nicklas 3073   BASE is free software; you can redistribute it and/or
5675 28 Jun 11 nicklas 3074   modify it under the terms of the GNU General Public License
5675 28 Jun 11 nicklas 3075   as published by the Free Software Foundation; either version 3
5675 28 Jun 11 nicklas 3076   of the License, or (at your option) any later version.
5675 28 Jun 11 nicklas 3077
5675 28 Jun 11 nicklas 3078   BASE is distributed in the hope that it will be useful,
5675 28 Jun 11 nicklas 3079   but WITHOUT ANY WARRANTY; without even the implied warranty of
5675 28 Jun 11 nicklas 3080   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5675 28 Jun 11 nicklas 3081   GNU General Public License for more details.
5675 28 Jun 11 nicklas 3082
5675 28 Jun 11 nicklas 3083   You should have received a copy of the GNU General Public License
5675 28 Jun 11 nicklas 3084   along with BASE. If not, see <http://www.gnu.org/licenses/>.
5675 28 Jun 11 nicklas 3085 */
5675 28 Jun 11 nicklas 3086 package net.sf.basedb.core;
5675 28 Jun 11 nicklas 3087 import net.sf.basedb.core.data.AnyData;
5675 28 Jun 11 nicklas 3088 /**
5675 28 Jun 11 nicklas 3089   This class is used to represent an AnyItem in BASE.
5675 28 Jun 11 nicklas 3090
5675 28 Jun 11 nicklas 3091   @author Your name
5675 28 Jun 11 nicklas 3092   @since 3.0
5675 28 Jun 11 nicklas 3093   @see AnyData
5675 28 Jun 11 nicklas 3094   @base.modified $Date$
5675 28 Jun 11 nicklas 3095 */
5675 28 Jun 11 nicklas 3096 public class AnyItem
5675 28 Jun 11 nicklas 3097   extends CommonItem<AnyData>
5675 28 Jun 11 nicklas 3098 {
5675 28 Jun 11 nicklas 3099   ...
5675 28 Jun 11 nicklas 3100 }
5675 28 Jun 11 nicklas 3101 ]]>
5675 28 Jun 11 nicklas 3102 </programlisting>
5675 28 Jun 11 nicklas 3103
5675 28 Jun 11 nicklas 3104         <bridgehead>Static methods and fields</bridgehead>
5675 28 Jun 11 nicklas 3105         
5675 28 Jun 11 nicklas 3106         <variablelist>
5675 28 Jun 11 nicklas 3107           <varlistentry>
5675 28 Jun 11 nicklas 3108             <term>getNew(DbControl)</term>
5675 28 Jun 11 nicklas 3109             <listitem>
5675 28 Jun 11 nicklas 3110               <para>
5675 28 Jun 11 nicklas 3111               This method is used to create a new item. The new item must be created by calling the 
5675 28 Jun 11 nicklas 3112               <methodname>DbControl.newItem()</methodname>. 
5675 28 Jun 11 nicklas 3113               </para>
5675 28 Jun 11 nicklas 3114               
5675 28 Jun 11 nicklas 3115               <programlisting language="java">
5675 28 Jun 11 nicklas 3116 <![CDATA[
5675 28 Jun 11 nicklas 3117 /**
5675 28 Jun 11 nicklas 3118   Create a new <code>AnyItem</code> item.
5675 28 Jun 11 nicklas 3119   
5675 28 Jun 11 nicklas 3120   @param dc The <code>DbControl</code> which will be used for
5675 28 Jun 11 nicklas 3121     permission checking and database access
5675 28 Jun 11 nicklas 3122   @return The new <code>AnyItem</code> item
5675 28 Jun 11 nicklas 3123   @throws BaseException If there is an error
5675 28 Jun 11 nicklas 3124 */
5675 28 Jun 11 nicklas 3125 public static AnyItem getNew(DbControl dc)
5675 28 Jun 11 nicklas 3126   throws BaseException
5675 28 Jun 11 nicklas 3127 {
5675 28 Jun 11 nicklas 3128   AnyItem a = dc.newItem(AnyItem.class);
5675 28 Jun 11 nicklas 3129   a.setName("New any item");
5675 28 Jun 11 nicklas 3130   return a;
5675 28 Jun 11 nicklas 3131 }
5675 28 Jun 11 nicklas 3132 ]]>
5675 28 Jun 11 nicklas 3133 </programlisting>
5675 28 Jun 11 nicklas 3134               <para>
5675 28 Jun 11 nicklas 3135                 The method must initialise all not-null properties to a sensible default values or it may take values as parameters:
5675 28 Jun 11 nicklas 3136               </para>
5675 28 Jun 11 nicklas 3137               <programlisting language="java">
5675 28 Jun 11 nicklas 3138 <![CDATA[
5675 28 Jun 11 nicklas 3139 // User.java
5675 28 Jun 11 nicklas 3140 public static User getNew(DbControl dc, String login, String password)
5675 28 Jun 11 nicklas 3141    throws BaseException
5675 28 Jun 11 nicklas 3142 {
5675 28 Jun 11 nicklas 3143    User u = dc.newItem(User.class);
5675 28 Jun 11 nicklas 3144    u.setName("New user");
5675 28 Jun 11 nicklas 3145    u.setLogin(login);
5675 28 Jun 11 nicklas 3146    u.setPassword(password);
5675 28 Jun 11 nicklas 3147    int defaultQuotaId = SystemItems.getId(Quota.DEFAULT);
5675 28 Jun 11 nicklas 3148    org.hibernate.Session session = dc.getHibernateSession();
5675 28 Jun 11 nicklas 3149    QuotaData defaultQuota = 
5675 28 Jun 11 nicklas 3150       HibernateUtil.loadData(session, QuotaData.class, defaultQuotaId);
5675 28 Jun 11 nicklas 3151    u.getData().setQuota(defaultQuota);
5675 28 Jun 11 nicklas 3152    return u;
5675 28 Jun 11 nicklas 3153 }
5675 28 Jun 11 nicklas 3154 ]]>
5675 28 Jun 11 nicklas 3155 </programlisting>
5675 28 Jun 11 nicklas 3156               <para>
5675 28 Jun 11 nicklas 3157                 When the default value is an association to another item, use the data object 
5675 28 Jun 11 nicklas 3158                 (<classname docapi="net.sf.basedb.core.data">QuotaData</classname>) not the item object 
5675 28 Jun 11 nicklas 3159                 (<classname docapi="net.sf.basedb.core">Quota</classname>) to create the association. 
5675 28 Jun 11 nicklas 3160                 The reason for this is that the logged in user may not have read permission to the default 
5675 28 Jun 11 nicklas 3161                 object. Ie. The logged in user may have permission to create users, but not permission to 
5675 28 Jun 11 nicklas 3162                 read quota. 
5675 28 Jun 11 nicklas 3163               </para>
5675 28 Jun 11 nicklas 3164
5675 28 Jun 11 nicklas 3165             </listitem>
5675 28 Jun 11 nicklas 3166           </varlistentry>
5675 28 Jun 11 nicklas 3167         
5675 28 Jun 11 nicklas 3168           <varlistentry>
5675 28 Jun 11 nicklas 3169             <term>getById(DbControl, int)</term>
5675 28 Jun 11 nicklas 3170             <listitem>
5675 28 Jun 11 nicklas 3171               <para>
5675 28 Jun 11 nicklas 3172                 This method is used to load an item from the database when the id of that item is known. 
5675 28 Jun 11 nicklas 3173                 Use the <methodname>DbControl.loadItem()</methodname> method to load the item. If the item 
5675 28 Jun 11 nicklas 3174                 is not found an <classname docapi="net.sf.basedb.core">ItemNotFoundException</classname> should 
5675 28 Jun 11 nicklas 3175                 be thrown. 
5675 28 Jun 11 nicklas 3176               </para>
5675 28 Jun 11 nicklas 3177               
5675 28 Jun 11 nicklas 3178               <programlisting language="java">
5675 28 Jun 11 nicklas 3179 <![CDATA[
5675 28 Jun 11 nicklas 3180 /**
5675 28 Jun 11 nicklas 3181   Get an <code>AnyItem</code> item when you know the id.
5675 28 Jun 11 nicklas 3182   
5675 28 Jun 11 nicklas 3183   @param dc The <code>DbControl</code> which will be used for
5675 28 Jun 11 nicklas 3184     permission checking and database access.
5675 28 Jun 11 nicklas 3185   @param id The id of the item to load
5675 28 Jun 11 nicklas 3186   @return The <code>AnyItem</code> item
5675 28 Jun 11 nicklas 3187   @throws ItemNotFoundException If an item with the specified 
5675 28 Jun 11 nicklas 3188     id is not found
5675 28 Jun 11 nicklas 3189   @throws PermissionDeniedException If the logged in user doesn't 
5675 28 Jun 11 nicklas 3190     have read permission to the item
5675 28 Jun 11 nicklas 3191   @throws BaseException If there is another error
5675 28 Jun 11 nicklas 3192 */
5675 28 Jun 11 nicklas 3193 public static AnyItem getById(DbControl dc, int id)
5675 28 Jun 11 nicklas 3194   throws ItemNotFoundException, PermissionDeniedException, BaseException
5675 28 Jun 11 nicklas 3195 {
5675 28 Jun 11 nicklas 3196   AnyItem a = dc.loadItem(AnyItem.class, id);
5675 28 Jun 11 nicklas 3197   if (a == null) throw new ItemNotFoundException("AnyItem[id="+id+"]");
5675 28 Jun 11 nicklas 3198   return a;
5675 28 Jun 11 nicklas 3199 }
5675 28 Jun 11 nicklas 3200 ]]>
5675 28 Jun 11 nicklas 3201 </programlisting>
5675 28 Jun 11 nicklas 3202               
5675 28 Jun 11 nicklas 3203             </listitem>
5675 28 Jun 11 nicklas 3204           </varlistentry>
5675 28 Jun 11 nicklas 3205         
5675 28 Jun 11 nicklas 3206           <varlistentry>
5675 28 Jun 11 nicklas 3207             <term>getQuery()</term>
5675 28 Jun 11 nicklas 3208             <listitem>
5675 28 Jun 11 nicklas 3209               <para>
5675 28 Jun 11 nicklas 3210               See <xref linkend="core_ref.rules.itemclass.getquery" />.
5675 28 Jun 11 nicklas 3211               </para>
5675 28 Jun 11 nicklas 3212             </listitem>
5675 28 Jun 11 nicklas 3213           </varlistentry>
5675 28 Jun 11 nicklas 3214         </variablelist>
5675 28 Jun 11 nicklas 3215         
5675 28 Jun 11 nicklas 3216         <bridgehead>Constructors</bridgehead>
5675 28 Jun 11 nicklas 3217         
5675 28 Jun 11 nicklas 3218         <para>
5675 28 Jun 11 nicklas 3219           Each item class needs only one constructor, which takes an object of the corresponding
5675 28 Jun 11 nicklas 3220           data class as a parameter. The constructor should never be invoked directly. Use the 
5675 28 Jun 11 nicklas 3221           <methodname>DbControl.newItem()</methodname> method. 
5675 28 Jun 11 nicklas 3222         </para>
5675 28 Jun 11 nicklas 3223
5675 28 Jun 11 nicklas 3224         <programlisting language="java">
5675 28 Jun 11 nicklas 3225 <![CDATA[
5675 28 Jun 11 nicklas 3226 AnyItem(AnyData anyData)
5675 28 Jun 11 nicklas 3227 {
5675 28 Jun 11 nicklas 3228   super(anyData);
5675 28 Jun 11 nicklas 3229 }
5675 28 Jun 11 nicklas 3230 ]]>
5675 28 Jun 11 nicklas 3231 </programlisting>
5675 28 Jun 11 nicklas 3232
5675 28 Jun 11 nicklas 3233         <bridgehead>Core methods</bridgehead>
5675 28 Jun 11 nicklas 3234         
5675 28 Jun 11 nicklas 3235         <variablelist>
5675 28 Jun 11 nicklas 3236           <varlistentry>
5675 28 Jun 11 nicklas 3237             <term>isUsed()</term>
5675 28 Jun 11 nicklas 3238             <listitem>
5675 28 Jun 11 nicklas 3239               <para>
5675 28 Jun 11 nicklas 3240                 This method is defined by the <classname docapi="net.sf.basedb.core">BasicItem</classname> class and
5675 28 Jun 11 nicklas 3241                 is called whenever we need to know if there are other items referencing the current item. The main
5675 28 Jun 11 nicklas 3242                 use case is to let client applications know if it is safe to delete an object or not.
5675 28 Jun 11 nicklas 3243                 The default implementation checks <classname docapi="net.sf.basedb.core">AnyToAny</classname> 
5675 28 Jun 11 nicklas 3244                 links between items. A subclass must override this method if it can be referenced by other items. 
5675 28 Jun 11 nicklas 3245                 A subclass should always call <methodname>super.isUsed()</methodname> as a last check if it is not 
5675 28 Jun 11 nicklas 3246                 used by any other item. The method should check if it is beeing used (referenced by) some other item. 
5675 28 Jun 11 nicklas 3247                 For example, a <classname docapi="net.sf.basedb.core">Tag</classname> is used if there is an 
5675 28 Jun 11 nicklas 3248                 <classname docapi="net.sf.basedb.core">Extract</classname> with that tag. The simplest way to check 
5675 28 Jun 11 nicklas 3249                 if the item is used is to use a predefined query that counts the number of references.
5675 28 Jun 11 nicklas 3250               </para>
5675 28 Jun 11 nicklas 3251               
5675 28 Jun 11 nicklas 3252               <programlisting language="java">
5675 28 Jun 11 nicklas 3253 <![CDATA[
5675 28 Jun 11 nicklas 3254 /**
5675 28 Jun 11 nicklas 3255   Check if:
5675 28 Jun 11 nicklas 3256   <ul>
5675 28 Jun 11 nicklas 3257   <li>Some {@link Extract}:s are marked with this tag
5675 28 Jun 11 nicklas 3258   </ul>
5675 28 Jun 11 nicklas 3259 */
5675 28 Jun 11 nicklas 3260 public boolean isUsed()
5675 28 Jun 11 nicklas 3261   throws BaseException
5675 28 Jun 11 nicklas 3262 {
5675 28 Jun 11 nicklas 3263   org.hibernate.Session session = getDbControl().getHibernateSession();
5675 28 Jun 11 nicklas 3264   org.hibernate.Query query = HibernateUtil.getPredefinedQuery(session, 
5675 28 Jun 11 nicklas 3265     "GET_EXTRACTS_FOR_TAG", "count(*)");
5675 28 Jun 11 nicklas 3266   /*
5675 28 Jun 11 nicklas 3267     SELECT {1}
5675 28 Jun 11 nicklas 3268     FROM ExtractData ext
5675 28 Jun 11 nicklas 3269     WHERE ext.tag = :tag
5675 28 Jun 11 nicklas 3270   */
5675 28 Jun 11 nicklas 3271   query.setEntity("tag", this.getData());
5675 28 Jun 11 nicklas 3272   boolean used = HibernateUtil.loadData(Long.class, query) > 0;
5675 28 Jun 11 nicklas 3273   return used || super.isUsed();
5675 28 Jun 11 nicklas 3274 }
5675 28 Jun 11 nicklas 3275 ]]>
5675 28 Jun 11 nicklas 3276 </programlisting>
5675 28 Jun 11 nicklas 3277               
5675 28 Jun 11 nicklas 3278               <para>
5675 28 Jun 11 nicklas 3279                 Sometimes it may be harder to decide what counts as using an item or not. Some examples:
5675 28 Jun 11 nicklas 3280               </para>
5675 28 Jun 11 nicklas 3281               
5675 28 Jun 11 nicklas 3282               <itemizedlist>
5675 28 Jun 11 nicklas 3283                 <listitem>
5675 28 Jun 11 nicklas 3284                   <para>
5675 28 Jun 11 nicklas 3285                     An event for a sample does not count as using the sample, since they hava a 
5675 28 Jun 11 nicklas 3286                     parent-child relationship. Ie. deleting the sample will also delete all events
5675 28 Jun 11 nicklas 3287                     associated with it. On the other hand, the protocol registered for the event counts 
5675 28 Jun 11 nicklas 3288                     as using the protocol, because deleting the protocol should not delete all events.
5675 28 Jun 11 nicklas 3289                   </para>
5675 28 Jun 11 nicklas 3290                 </listitem>
5675 28 Jun 11 nicklas 3291                 <listitem>
5675 28 Jun 11 nicklas 3292                   <para>
5675 28 Jun 11 nicklas 3293                     As a general rule, if one item is used by a second item, then the second item cannot 
5675 28 Jun 11 nicklas 3294                     be used by the first. It could lead to situations where it would be impossible to 
5675 28 Jun 11 nicklas 3295                     delete either one of them. 
5675 28 Jun 11 nicklas 3296                   </para>
5675 28 Jun 11 nicklas 3297                 </listitem>
5675 28 Jun 11 nicklas 3298               </itemizedlist>
5675 28 Jun 11 nicklas 3299             </listitem>
5675 28 Jun 11 nicklas 3300           </varlistentry>
5675 28 Jun 11 nicklas 3301
5675 28 Jun 11 nicklas 3302           <varlistentry>
5675 28 Jun 11 nicklas 3303             <term>getUsingItems()</term>
5675 28 Jun 11 nicklas 3304             <listitem>
5675 28 Jun 11 nicklas 3305               <para>
5675 28 Jun 11 nicklas 3306                 Find all items that are referencing this one. This method is related to the 
5675 28 Jun 11 nicklas 3307                 <methodname>isUsed()</methodname> method and is defined in the <classname docapi="net.sf.basedb.core">BasicItem</classname>
5675 28 Jun 11 nicklas 3308                 class. The default implementation load all items linked via an <classname docapi="net.sf.basedb.core">AnyToAny</classname>
5675 28 Jun 11 nicklas 3309                 link that has the <code>usingTo</code> flag set to true. A subclass must override this method if it can 
5675 28 Jun 11 nicklas 3310                 be referenced to be used by other items. A subclass should always call <methodname>super.getUsingItems()</methodname> 
5675 28 Jun 11 nicklas 3311                 first and then add extra items to the Set returned by that call. For example, a <classname docapi="net.sf.basedb.core">Tag</classname>
5675 28 Jun 11 nicklas 3312                 should load all <classname docapi="net.sf.basedb.core">Extract</classname>:s with that tag. 
5675 28 Jun 11 nicklas 3313               </para>
5675 28 Jun 11 nicklas 3314               <programlisting language="java">
5675 28 Jun 11 nicklas 3315 <![CDATA[
5675 28 Jun 11 nicklas 3316 /**
5675 28 Jun 11 nicklas 3317   Get all:
5675 28 Jun 11 nicklas 3318   <ul>
5675 28 Jun 11 nicklas 3319   <li>{@link Extract}:s marked with this tag
5675 28 Jun 11 nicklas 3320   <ul>
5675 28 Jun 11 nicklas 3321 */
5675 28 Jun 11 nicklas 3322 @Override
5675 28 Jun 11 nicklas 3323 public Set<ItemProxy> getUsingItems()
5675 28 Jun 11 nicklas 3324 {
5675 28 Jun 11 nicklas 3325   Set<ItemProxy> using = super.getUsingItems();
5675 28 Jun 11 nicklas 3326   org.hibernate.Session session = getDbControl().getHibernateSession();
5675 28 Jun 11 nicklas 3327     
5675 28 Jun 11 nicklas 3328   // Extracts
5675 28 Jun 11 nicklas 3329   org.hibernate.Query query = HibernateUtil.getPredefinedQuery(session, 
5675 28 Jun 11 nicklas 3330       "GET_EXTRACTS_FOR_TAG", "ext.id");
5675 28 Jun 11 nicklas 3331   /*
5675 28 Jun 11 nicklas 3332     SELECT {1}
5675 28 Jun 11 nicklas 3333     FROM ExtractData ext
5675 28 Jun 11 nicklas 3334     WHERE ext.tag = :tag
5675 28 Jun 11 nicklas 3335   */
5675 28 Jun 11 nicklas 3336   query.setEntity("tag", this.getData());
5675 28 Jun 11 nicklas 3337   addUsingItems(using, Item.EXTRACT, query);
5675 28 Jun 11 nicklas 3338   return using;
5675 28 Jun 11 nicklas 3339 }
5675 28 Jun 11 nicklas 3340 ]]>
5675 28 Jun 11 nicklas 3341 </programlisting>
5675 28 Jun 11 nicklas 3342             </listitem>
5675 28 Jun 11 nicklas 3343           </varlistentry>
5675 28 Jun 11 nicklas 3344           
5675 28 Jun 11 nicklas 3345           <varlistentry>
5675 28 Jun 11 nicklas 3346             <term>initPermissions(int, int)</term>
5675 28 Jun 11 nicklas 3347             <listitem>
5675 28 Jun 11 nicklas 3348               <para>
5675 28 Jun 11 nicklas 3349                 See <xref linkend="core_ref.rules.itemclass.initpermissions" />.
5675 28 Jun 11 nicklas 3350               </para>
5675 28 Jun 11 nicklas 3351             </listitem>
5675 28 Jun 11 nicklas 3352           </varlistentry>
5675 28 Jun 11 nicklas 3353         
5675 28 Jun 11 nicklas 3354           <varlistentry>
5675 28 Jun 11 nicklas 3355             <term>validate() </term>
5675 28 Jun 11 nicklas 3356             <listitem>
5675 28 Jun 11 nicklas 3357               <para>
5675 28 Jun 11 nicklas 3358                 See <xref linkend="core_ref.rules.itemclass.validation" />.
5675 28 Jun 11 nicklas 3359               </para>
5675 28 Jun 11 nicklas 3360             </listitem>
5675 28 Jun 11 nicklas 3361           </varlistentry>
5675 28 Jun 11 nicklas 3362         
5675 28 Jun 11 nicklas 3363           <varlistentry>
5675 28 Jun 11 nicklas 3364             <term>onBeforeCommit(Action)</term>
5675 28 Jun 11 nicklas 3365             <term>setProjectDefaults(Project)</term>
5675 28 Jun 11 nicklas 3366             <term>onAfterInsert()</term>
5675 28 Jun 11 nicklas 3367             <term>onAfterCommit(Action) </term>
5675 28 Jun 11 nicklas 3368             <term>onRollback(Action)</term>
5675 28 Jun 11 nicklas 3369             <listitem>
5675 28 Jun 11 nicklas 3370               <para>
5675 28 Jun 11 nicklas 3371                 See <xref linkend="core_ref.rules.itemclass.transactions"/>.
5675 28 Jun 11 nicklas 3372               </para>
5675 28 Jun 11 nicklas 3373             </listitem>
5675 28 Jun 11 nicklas 3374           </varlistentry>
5675 28 Jun 11 nicklas 3375         </variablelist>
5675 28 Jun 11 nicklas 3376         
5675 28 Jun 11 nicklas 3377         <bridgehead>Getter and setter methods</bridgehead>
5675 28 Jun 11 nicklas 3378         
5675 28 Jun 11 nicklas 3379         <para>
5675 28 Jun 11 nicklas 3380           The get methods for basic property types are usually very simple. All that is needed is to 
5675 28 Jun 11 nicklas 3381           return the value. Be aware of date values though, they are mutable and must be copied. 
5675 28 Jun 11 nicklas 3382         </para>
5675 28 Jun 11 nicklas 3383           
5675 28 Jun 11 nicklas 3384         <programlisting language="java">
5675 28 Jun 11 nicklas 3385 <![CDATA[
5675 28 Jun 11 nicklas 3386 /**
5675 28 Jun 11 nicklas 3387    Get the value of the string property.
5675 28 Jun 11 nicklas 3388 */
5675 28 Jun 11 nicklas 3389 public String getStringProperty()
5675 28 Jun 11 nicklas 3390 {
5675 28 Jun 11 nicklas 3391    return getData().getStringProperty();
5675 28 Jun 11 nicklas 3392 }
5675 28 Jun 11 nicklas 3393
5675 28 Jun 11 nicklas 3394 /**
5675 28 Jun 11 nicklas 3395    Get the value of the int property.
5675 28 Jun 11 nicklas 3396 */
5675 28 Jun 11 nicklas 3397 public int getIntProperty()
5675 28 Jun 11 nicklas 3398 {
5675 28 Jun 11 nicklas 3399    return getData().getIntProperty();
5675 28 Jun 11 nicklas 3400 }
5675 28 Jun 11 nicklas 3401
5675 28 Jun 11 nicklas 3402 /**
5675 28 Jun 11 nicklas 3403    Get the value of the boolean property.
5675 28 Jun 11 nicklas 3404 */
5675 28 Jun 11 nicklas 3405 public boolean isBooleanProperty()
5675 28 Jun 11 nicklas 3406 {
5675 28 Jun 11 nicklas 3407    return getData().isBooleanProperty();
5675 28 Jun 11 nicklas 3408 }
5675 28 Jun 11 nicklas 3409
5675 28 Jun 11 nicklas 3410 /**
5675 28 Jun 11 nicklas 3411    Get the value of the date property.
5675 28 Jun 11 nicklas 3412    @return A date object or null if unknown
5675 28 Jun 11 nicklas 3413 */
5675 28 Jun 11 nicklas 3414 public Date getDateProperty()
5675 28 Jun 11 nicklas 3415 {
5675 28 Jun 11 nicklas 3416    return DateUtil.copy(getData().getDateProperty());
5675 28 Jun 11 nicklas 3417 }
5675 28 Jun 11 nicklas 3418 ]]>
5675 28 Jun 11 nicklas 3419 </programlisting>
5675 28 Jun 11 nicklas 3420
5675 28 Jun 11 nicklas 3421           <para>
5675 28 Jun 11 nicklas 3422             The set methods must always check for <constant>WRITE</constant> permission and validate
5675 28 Jun 11 nicklas 3423             the parameters. There are plenty of utility method to help with this.
5675 28 Jun 11 nicklas 3424           </para>
5675 28 Jun 11 nicklas 3425           
5675 28 Jun 11 nicklas 3426           <programlisting language="java">
5675 28 Jun 11 nicklas 3427 <![CDATA[
5675 28 Jun 11 nicklas 3428 /**
5675 28 Jun 11 nicklas 3429    The maximum length of the string property. Check the length
5675 28 Jun 11 nicklas 3430    agains this value before calling {@link #setStringProperty(String)}
5675 28 Jun 11 nicklas 3431    to avoid exceptions.
5675 28 Jun 11 nicklas 3432 */
5675 28 Jun 11 nicklas 3433 public static final int MAX_STRINGPROPERTY_LENGTH = 
5675 28 Jun 11 nicklas 3434    AnyData.MAX_STRINGPROPERTY_LENGTH;
5675 28 Jun 11 nicklas 3435
5675 28 Jun 11 nicklas 3436 /**
5675 28 Jun 11 nicklas 3437    Set the value of the string property. Null values are not 
5675 28 Jun 11 nicklas 3438    allowed and the length must be shorter than 
5675 28 Jun 11 nicklas 3439    {@link #MAX_STRINGPROPERTY_LENGTH}.
5675 28 Jun 11 nicklas 3440    @param value The new value
5675 28 Jun 11 nicklas 3441    @throws PermissionDeniedException If the logged in user
5675 28 Jun 11 nicklas 3442       doesn't have write permission
5675 28 Jun 11 nicklas 3443    @throws InvalidDataException If the value is null or too long
5675 28 Jun 11 nicklas 3444 */
5675 28 Jun 11 nicklas 3445 public void setStringProperty(String value)
5675 28 Jun 11 nicklas 3446    throws PermissionDeniedException, InvalidDataException
5675 28 Jun 11 nicklas 3447 {
5675 28 Jun 11 nicklas 3448    checkPermission(Permission.WRITE);
5675 28 Jun 11 nicklas 3449    getData.setStringProperty(
5675 28 Jun 11 nicklas 3450       StringUtil.setNotNullString(value, "stringProperty", MAX_STRINGPROPERTY_LENGTH)
5675 28 Jun 11 nicklas 3451    );
5675 28 Jun 11 nicklas 3452 }
5675 28 Jun 11 nicklas 3453
5675 28 Jun 11 nicklas 3454 /**
5675 28 Jun 11 nicklas 3455    Set the value of the int property. The value mustn't be less than
5675 28 Jun 11 nicklas 3456    zero.
5675 28 Jun 11 nicklas 3457    @param value The new value
5675 28 Jun 11 nicklas 3458    @throws PermissionDeniedException If the logged in user
5675 28 Jun 11 nicklas 3459       doesn't have write permission
5675 28 Jun 11 nicklas 3460    @throws InvalidDataException If the value is less than zero
5675 28 Jun 11 nicklas 3461 */
5675 28 Jun 11 nicklas 3462
5675 28 Jun 11 nicklas 3463 public void setIntProperty(int value)
5675 28 Jun 11 nicklas 3464    throws PermissionDeniedException, InvalidDataException
5675 28 Jun 11 nicklas 3465 {
5675 28 Jun 11 nicklas 3466    checkPermission(Permission.WRITE);
5675 28 Jun 11 nicklas 3467    getData.setIntProperty(
5675 28 Jun 11 nicklas 3468       IntegerUtil.checkMin(value, "intProperty", 0)
5675 28 Jun 11 nicklas 3469    );
5675 28 Jun 11 nicklas 3470 }
5675 28 Jun 11 nicklas 3471
5675 28 Jun 11 nicklas 3472 /**
5675 28 Jun 11 nicklas 3473    Set the value of the boolean property. 
5675 28 Jun 11 nicklas 3474    @param value The new value
5675 28 Jun 11 nicklas 3475    @throws PermissionDeniedException If the logged in user
5675 28 Jun 11 nicklas 3476       doesn't have write permission
5675 28 Jun 11 nicklas 3477 */
5675 28 Jun 11 nicklas 3478 public void setBooleanProperty(boolean value)
5675 28 Jun 11 nicklas 3479    throws PermissionDeniedException
5675 28 Jun 11 nicklas 3480 {
5675 28 Jun 11 nicklas 3481    checkPermission(Permission.WRITE);
5675 28 Jun 11 nicklas 3482    getData.setBooleanProperty(value);
5675 28 Jun 11 nicklas 3483 }
5675 28 Jun 11 nicklas 3484
5675 28 Jun 11 nicklas 3485 /**
5675 28 Jun 11 nicklas 3486    Set the value of the date property. Null values are allowed.
5675 28 Jun 11 nicklas 3487    @param value The new value
5675 28 Jun 11 nicklas 3488    @throws PermissionDeniedException If the logged in user
5675 28 Jun 11 nicklas 3489       doesn't have write permission
5675 28 Jun 11 nicklas 3490 */
5675 28 Jun 11 nicklas 3491 public void setDateProperty(Date value)
5675 28 Jun 11 nicklas 3492    throws PermissionDeniedException
5675 28 Jun 11 nicklas 3493 {
5675 28 Jun 11 nicklas 3494    checkPermission(Permission.WRITE);
5675 28 Jun 11 nicklas 3495    getData().setDateProperty(DateUtil.setNullableDate(value, "dateProperty"));
5675 28 Jun 11 nicklas 3496 }
5675 28 Jun 11 nicklas 3497 ]]>
5675 28 Jun 11 nicklas 3498 </programlisting>
5675 28 Jun 11 nicklas 3499
5675 28 Jun 11 nicklas 3500         <bridgehead>Many-to-one associations</bridgehead>
5675 28 Jun 11 nicklas 3501         
5675 28 Jun 11 nicklas 3502         <para>
5675 28 Jun 11 nicklas 3503           Many-to-one associations require sligthly more work. First of all, the item must be connected to a 
5675 28 Jun 11 nicklas 3504           <classname docapi="net.sf.basedb.core">DbControl</classname> since it is used to load the information 
5675 28 Jun 11 nicklas 3505           from the database and crete the new item object. Secondly, we must make sure to check for use 
5675 28 Jun 11 nicklas 3506           permission on the referenced object in the setter method.
5675 28 Jun 11 nicklas 3507         </para>
5675 28 Jun 11 nicklas 3508         
5675 28 Jun 11 nicklas 3509         <programlisting language="java">
5675 28 Jun 11 nicklas 3510 <![CDATA[
5675 28 Jun 11 nicklas 3511 /**
5675 28 Jun 11 nicklas 3512    Get the associated other item.
5675 28 Jun 11 nicklas 3513    @return The OtherItem item
5675 28 Jun 11 nicklas 3514    @throws PermissionDeniedException If the logged in user 
5675 28 Jun 11 nicklas 3515       doesn't have read permission
5675 28 Jun 11 nicklas 3516    @throws BaseException If there is another error
5675 28 Jun 11 nicklas 3517 */
5675 28 Jun 11 nicklas 3518 public OtherItem getOtherItem()
5675 28 Jun 11 nicklas 3519    throws PermissionDeniedException, BaseException
5675 28 Jun 11 nicklas 3520 {
5675 28 Jun 11 nicklas 3521    return getDbControl().getItem(OtherItem.class, getData().getOtherItem());
5675 28 Jun 11 nicklas 3522 }
5675 28 Jun 11 nicklas 3523
5675 28 Jun 11 nicklas 3524 /**
5675 28 Jun 11 nicklas 3525    Set the associated item. Null is not allowed.
5675 28 Jun 11 nicklas 3526    @param other The other item
5675 28 Jun 11 nicklas 3527    @throws PermissionDeniedException If the logged in user 
5675 28 Jun 11 nicklas 3528       doesn't have write permission
5675 28 Jun 11 nicklas 3529    @throws InvalidDataException If the other item is null
5675 28 Jun 11 nicklas 3530    @throws BaseException If there is another error
5675 28 Jun 11 nicklas 3531 */
5675 28 Jun 11 nicklas 3532 public void setOtherItem(OtherItem other)
5675 28 Jun 11 nicklas 3533    throws PermissionDeniedException, InvalidDataException, BaseException
5675 28 Jun 11 nicklas 3534 {
5675 28 Jun 11 nicklas 3535    checkPermission(Permission.WRITE);
5675 28 Jun 11 nicklas 3536    if (otherItem == null) throw new InvalidUseOfNullException("otherItem");
5675 28 Jun 11 nicklas 3537    getData().setOtherItem(otherItem.getData());
5675 28 Jun 11 nicklas 3538 }
5675 28 Jun 11 nicklas 3539 ]]>
5675 28 Jun 11 nicklas 3540 </programlisting>
5675 28 Jun 11 nicklas 3541
5675 28 Jun 11 nicklas 3542         <bridgehead>One-to-many and many-to-many associations</bridgehead>
5675 28 Jun 11 nicklas 3543         <para>
5675 28 Jun 11 nicklas 3544           If the association is a one-to-many or many-to-many it becomes a little more complicated again. 
5675 28 Jun 11 nicklas 3545           There are many types of such associations and how they are handled usually depends on if the 
5675 28 Jun 11 nicklas 3546           are set:s, map:s, list:s or any other type of collections. In all cases we need methods for adding 
5675 28 Jun 11 nicklas 3547           and removing items, and a method that returns a <interfacename docapi="net.sf.basedb.core.query">Query</interfacename>
5675 28 Jun 11 nicklas 3548           that can list all associated items. The first example if for parent/child relationship, which is a one-to-many 
5675 28 Jun 11 nicklas 3549           association where the children are mapped as a set. 
5675 28 Jun 11 nicklas 3550         </para>
5675 28 Jun 11 nicklas 3551         
5675 28 Jun 11 nicklas 3552         <programlisting language="java">
5675 28 Jun 11 nicklas 3553 <![CDATA[
5675 28 Jun 11 nicklas 3554 /**
5675 28 Jun 11 nicklas 3555    Create a child item for this any item.
5675 28 Jun 11 nicklas 3556    @return The new AChildItem object
5675 28 Jun 11 nicklas 3557    @throws PermissionDeniedException If the logged in user doesn't have
5675 28 Jun 11 nicklas 3558       write permission
5675 28 Jun 11 nicklas 3559    @throws BaseException If there is another error
5675 28 Jun 11 nicklas 3560 */
5675 28 Jun 11 nicklas 3561 public AChildItem newChildItem()
5675 28 Jun 11 nicklas 3562    throws PermissionDeniedException, BaseException
5675 28 Jun 11 nicklas 3563 {
5675 28 Jun 11 nicklas 3564    checkPermission(Permission.WRITE);
5675 28 Jun 11 nicklas 3565    return AChildItem.getNew(getDbControl(), this);
5675 28 Jun 11 nicklas 3566 }
5675 28 Jun 11 nicklas 3567
5675 28 Jun 11 nicklas 3568 /**
5675 28 Jun 11 nicklas 3569    Get a query that will return all child items for this any item.
5675 28 Jun 11 nicklas 3570    @return A {@link Query} object
5675 28 Jun 11 nicklas 3571 */
5675 28 Jun 11 nicklas 3572 public ItemQuery<AChildItem> getChildItems()
5675 28 Jun 11 nicklas 3573 {
5675 28 Jun 11 nicklas 3574   return AChildItem.getQuery(this);
5675 28 Jun 11 nicklas 3575 }
5675 28 Jun 11 nicklas 3576 ]]>
5675 28 Jun 11 nicklas 3577 </programlisting>
5675 28 Jun 11 nicklas 3578         <para>
5675 28 Jun 11 nicklas 3579           The second example is for the many-to-many associations between users and roles, which is also mapped as a set. 
5675 28 Jun 11 nicklas 3580         </para>
5675 28 Jun 11 nicklas 3581         <programlisting language="java">
5675 28 Jun 11 nicklas 3582 <![CDATA[
5675 28 Jun 11 nicklas 3583 // Role.java
5675 28 Jun 11 nicklas 3584 /**
5675 28 Jun 11 nicklas 3585    Add a user to this role.
5675 28 Jun 11 nicklas 3586    @param user The user to add
5675 28 Jun 11 nicklas 3587    @throws PermissionDeniedException If the logged in user doesn't 
5675 28 Jun 11 nicklas 3588       have write permission for the role and 
5675 28 Jun 11 nicklas 3589       use permission for the user
5675 28 Jun 11 nicklas 3590    @throws InvalidDataException If the user is null
5675 28 Jun 11 nicklas 3591 */
5675 28 Jun 11 nicklas 3592 public void addUser(User user)
5675 28 Jun 11 nicklas 3593    throws PermissionDeniedException, InvalidDataException
5675 28 Jun 11 nicklas 3594 {
5675 28 Jun 11 nicklas 3595    checkPermission(Permission.WRITE);
5675 28 Jun 11 nicklas 3596    if (user == null) throw new InvalidUseOfNullException("user");
5675 28 Jun 11 nicklas 3597    user.checkPermission(Permission.USE);
5675 28 Jun 11 nicklas 3598    getData().getUsers().add(user.getData());
5675 28 Jun 11 nicklas 3599 }
5675 28 Jun 11 nicklas 3600
5675 28 Jun 11 nicklas 3601 /**
5675 28 Jun 11 nicklas 3602    Remove a user from this role.
5675 28 Jun 11 nicklas 3603    @param user The user to remove
5675 28 Jun 11 nicklas 3604    @throws PermissionDeniedException If the logged in user doesn't 
5675 28 Jun 11 nicklas 3605       have write permission for the role and 
5675 28 Jun 11 nicklas 3606       use permission for the user
5675 28 Jun 11 nicklas 3607    @throws InvalidDataException If the user is null
5675 28 Jun 11 nicklas 3608 */
5675 28 Jun 11 nicklas 3609 public void removeUser(User user)
5675 28 Jun 11 nicklas 3610    throws PermissionDeniedException, InvalidDataException
5675 28 Jun 11 nicklas 3611 {
5675 28 Jun 11 nicklas 3612    checkPermission(Permission.WRITE);
5675 28 Jun 11 nicklas 3613    if (user == null) throw new InvalidUseOfNullException("user");
5675 28 Jun 11 nicklas 3614    user.checkPermission(Permission.USE);
5675 28 Jun 11 nicklas 3615    getData().getUsers().remove(user.getData());
5675 28 Jun 11 nicklas 3616 }
5675 28 Jun 11 nicklas 3617
5675 28 Jun 11 nicklas 3618 /**
5675 28 Jun 11 nicklas 3619    Check if the given user is member of this role or not.
5675 28 Jun 11 nicklas 3620    @param user The user to check
5675 28 Jun 11 nicklas 3621    @return TRUE if the user is member, FALSE otherwise
5675 28 Jun 11 nicklas 3622 */
5675 28 Jun 11 nicklas 3623 public boolean isMember(User user)
5675 28 Jun 11 nicklas 3624 {
5675 28 Jun 11 nicklas 3625    return getData().getUsers().contains(user.getData());
5675 28 Jun 11 nicklas 3626 }
5675 28 Jun 11 nicklas 3627
5675 28 Jun 11 nicklas 3628 /**
5675 28 Jun 11 nicklas 3629    Get a query that returns the users that
5675 28 Jun 11 nicklas 3630    are members of this role. This query excludes users that the logged 
5675 28 Jun 11 nicklas 3631    in user doesn't have permission to read.
5675 28 Jun 11 nicklas 3632    @see User#getQuery()
5675 28 Jun 11 nicklas 3633 */
5675 28 Jun 11 nicklas 3634 public ItemQuery<User> getUsers()
5675 28 Jun 11 nicklas 3635 {
5675 28 Jun 11 nicklas 3636    ItemQuery<User> query = User.getQuery();
5675 28 Jun 11 nicklas 3637    query.joinPermanent(
5675 28 Jun 11 nicklas 3638       Hql.innerJoin("roles", Item.ROLE.getAlias())
5675 28 Jun 11 nicklas 3639    );
5675 28 Jun 11 nicklas 3640    query.restrictPermanent(
5675 28 Jun 11 nicklas 3641       Restrictions.eq(
5675 28 Jun 11 nicklas 3642          Hql.alias(Item.ROLE.getAlias()), 
5675 28 Jun 11 nicklas 3643          Hql.entity(this)
5675 28 Jun 11 nicklas 3644       )
5675 28 Jun 11 nicklas 3645    );
5675 28 Jun 11 nicklas 3646    return query;
5675 28 Jun 11 nicklas 3647 }
5675 28 Jun 11 nicklas 3648
5675 28 Jun 11 nicklas 3649 // User.java
5675 28 Jun 11 nicklas 3650 /**
5675 28 Jun 11 nicklas 3651    Get a query that returns the roles where this user is a
5675 28 Jun 11 nicklas 3652    member. The query excludes roles that the logged in user doesn't have 
5675 28 Jun 11 nicklas 3653    permission to read.
5675 28 Jun 11 nicklas 3654    @see Role#getQuery()
5675 28 Jun 11 nicklas 3655 */
5675 28 Jun 11 nicklas 3656 public ItemQuery<Role> getRoles()
5675 28 Jun 11 nicklas 3657 {
5675 28 Jun 11 nicklas 3658    ItemQuery<Role> query = Role.getQuery();
5675 28 Jun 11 nicklas 3659    query.joinPermanent(
5675 28 Jun 11 nicklas 3660       Hql.innerJoin("users", Item.USER.getAlias())
5675 28 Jun 11 nicklas 3661    );
5675 28 Jun 11 nicklas 3662    query.restrictPermanent(
5675 28 Jun 11 nicklas 3663       Restrictions.eq(
5675 28 Jun 11 nicklas 3664          Hql.alias(Item.USER.getAlias()), 
5675 28 Jun 11 nicklas 3665          Hql.entity(this)
5675 28 Jun 11 nicklas 3666       )
5675 28 Jun 11 nicklas 3667    );
5675 28 Jun 11 nicklas 3668    return query;
5675 28 Jun 11 nicklas 3669 }
5675 28 Jun 11 nicklas 3670 ]]>
5675 28 Jun 11 nicklas 3671 </programlisting>
5675 28 Jun 11 nicklas 3672         <para>
5675 28 Jun 11 nicklas 3673           Note that we have a query method in both classes, but the association can only be changed from the 
5675 28 Jun 11 nicklas 3674           <classname docapi="net.sf.based.core">Role</classname>. We recommend that modifier methods are put
5675 28 Jun 11 nicklas 3675           in one of the classes only. The last example is the many-to-many relation between projects and users 
5675 28 Jun 11 nicklas 3676           which is a map to the permission for the user in the project. 
5675 28 Jun 11 nicklas 3677         </para>
5675 28 Jun 11 nicklas 3678         
5675 28 Jun 11 nicklas 3679         <programlisting language="java">
5675 28 Jun 11 nicklas 3680 <![CDATA[
5675 28 Jun 11 nicklas 3681 // Project.java
5675 28 Jun 11 nicklas 3682 /**
5675 28 Jun 11 nicklas 3683    Grant a user permissions to this project. Use an empty set
5675 28 Jun 11 nicklas 3684    or null to remove the user from this project.
5675 28 Jun 11 nicklas 3685
5675 28 Jun 11 nicklas 3686    @param user The user
5675 28 Jun 11 nicklas 3687    @param permissions The permissions to grant, or null to revoke all permissions
5675 28 Jun 11 nicklas 3688    @throws PermissionDeniedException If the logged in user doesn't have
5675 28 Jun 11 nicklas 3689       write permission for the project
5675 28 Jun 11 nicklas 3690    @throws InvalidDataException If the user is null
5675 28 Jun 11 nicklas 3691    @see Permission
5675 28 Jun 11 nicklas 3692 */
5675 28 Jun 11 nicklas 3693 public void setPermissions(User user, Set<Permission> permissions)
5675 28 Jun 11 nicklas 3694    throws PermissionDeniedException, InvalidDataException
5675 28 Jun 11 nicklas 3695 {
5675 28 Jun 11 nicklas 3696    checkPermission(Permission.WRITE);
5675 28 Jun 11 nicklas 3697    if (user == null) throw new InvalidUseOfNullException("user");
5675 28 Jun 11 nicklas 3698    if (permissions == null || permissions.isEmpty())
5675 28 Jun 11 nicklas 3699    {
5675 28 Jun 11 nicklas 3700       getData().getUsers().remove(user.getData());
5675 28 Jun 11 nicklas 3701    }
5675 28 Jun 11 nicklas 3702    else
5675 28 Jun 11 nicklas 3703    {
5675 28 Jun 11 nicklas 3704       getData().getUsers().put(user.getData(), Permission.grant(permissions));
5675 28 Jun 11 nicklas 3705    }
5675 28 Jun 11 nicklas 3706 }
5675 28 Jun 11 nicklas 3707
5675 28 Jun 11 nicklas 3708 /**
5675 28 Jun 11 nicklas 3709    Get the permissions for a user in this project.
5675 28 Jun 11 nicklas 3710    @param user The user for which we want to get the permission
5675 28 Jun 11 nicklas 3711    @return A set containing the granted permissions, or an
5675 28 Jun 11 nicklas 3712       empty set if no permissions have been granted
5675 28 Jun 11 nicklas 3713    @throws InvalidDataException If the user is null
5675 28 Jun 11 nicklas 3714    @see Permission
5675 28 Jun 11 nicklas 3715 */
5675 28 Jun 11 nicklas 3716 public Set<Permission> getPermissions(User user)
5675 28 Jun 11 nicklas 3717    throws InvalidDataException
5675 28 Jun 11 nicklas 3718 {
5675 28 Jun 11 nicklas 3719    if (user == null) throw new InvalidUseOfNullException("user");
5675 28 Jun 11 nicklas 3720    return Permission.fromInt(getData().getUsers().get(user.getData()));
5675 28 Jun 11 nicklas 3721 }
5675 28 Jun 11 nicklas 3722
5675 28 Jun 11 nicklas 3723 /**
5675 28 Jun 11 nicklas 3724    Get a query that returns the users that
5675 28 Jun 11 nicklas 3725    are members of this project. This query excludes users that the logged 
5675 28 Jun 11 nicklas 3726    in user doesn't have permission to read.
5675 28 Jun 11 nicklas 3727    @see User#getQuery()
5675 28 Jun 11 nicklas 3728 */
5675 28 Jun 11 nicklas 3729 public ItemQuery<User> getUsers()
5675 28 Jun 11 nicklas 3730 {
5675 28 Jun 11 nicklas 3731    ItemQuery<User> query = User.getQuery();
5675 28 Jun 11 nicklas 3732    query.joinPermanent(
5675 28 Jun 11 nicklas 3733       Hql.innerJoin("projects", Item.PROJECT.getAlias())
5675 28 Jun 11 nicklas 3734    );
5675 28 Jun 11 nicklas 3735    query.restrictPermanent(
5675 28 Jun 11 nicklas 3736       Restrictions.eq(
5675 28 Jun 11 nicklas 3737          Hql.alias(Item.PROJECT.getAlias()), 
5675 28 Jun 11 nicklas 3738          Hql.entity(this)
5675 28 Jun 11 nicklas 3739       )
5675 28 Jun 11 nicklas 3740    );
5675 28 Jun 11 nicklas 3741    return query;
5675 28 Jun 11 nicklas 3742 }
5675 28 Jun 11 nicklas 3743
5675 28 Jun 11 nicklas 3744 // User.java
5675 28 Jun 11 nicklas 3745 /**
5675 28 Jun 11 nicklas 3746    Get a query that returns the projects where this user is a
5675 28 Jun 11 nicklas 3747    member. The query excludes projects that the logged in user doesn't have 
5675 28 Jun 11 nicklas 3748    permission to read. The query doesn't include projects where this user is
5675 28 Jun 11 nicklas 3749    the owner.
5675 28 Jun 11 nicklas 3750    @see Project#getQuery()
5675 28 Jun 11 nicklas 3751 */
5675 28 Jun 11 nicklas 3752 public ItemQuery<Project> getProjects()
5675 28 Jun 11 nicklas 3753 {
5675 28 Jun 11 nicklas 3754    ItemQuery<Project> query = Project.getQuery();
5675 28 Jun 11 nicklas 3755    query.joinPermanent(
5675 28 Jun 11 nicklas 3756       Hql.innerJoin("users", Item.USER.getAlias())
5675 28 Jun 11 nicklas 3757    );
5675 28 Jun 11 nicklas 3758    query.restrictPermanent(
5675 28 Jun 11 nicklas 3759       Restrictions.eq(
5675 28 Jun 11 nicklas 3760          Hql.index(Item.USER.getAlias(), null), 
5675 28 Jun 11 nicklas 3761          Hql.entity(this)
5675 28 Jun 11 nicklas 3762       )
5675 28 Jun 11 nicklas 3763    );
5675 28 Jun 11 nicklas 3764    return query;
5675 28 Jun 11 nicklas 3765 }
5675 28 Jun 11 nicklas 3766 ]]>
5675 28 Jun 11 nicklas 3767 </programlisting>
5675 28 Jun 11 nicklas 3768         <para>
5675 28 Jun 11 nicklas 3769           As you can see from these examples, the code is very different depending on the type of 
5675 28 Jun 11 nicklas 3770           association. We don't give any more examples here, but if you are unsure you should look 
5675 28 Jun 11 nicklas 3771           in the source code to get more inspiration. 
5675 28 Jun 11 nicklas 3772         </para>
5675 28 Jun 11 nicklas 3773       </sect3>
3315 09 May 07 nicklas 3774     </sect2>    
5675 28 Jun 11 nicklas 3775
3315 09 May 07 nicklas 3776     <sect2 id="core_ref.rules.batchclass">
3315 09 May 07 nicklas 3777       <title>Batch-class rules</title>
3315 09 May 07 nicklas 3778       <para>
3315 09 May 07 nicklas 3779         TODO
3315 09 May 07 nicklas 3780       </para>
5675 28 Jun 11 nicklas 3781     </sect2>
5675 28 Jun 11 nicklas 3782     
3315 09 May 07 nicklas 3783     <sect2 id="core_ref.rules.testclass">
3315 09 May 07 nicklas 3784       <title>Test-class rules</title>
3315 09 May 07 nicklas 3785       <para>
3315 09 May 07 nicklas 3786         TODO
3315 09 May 07 nicklas 3787       </para>
5675 28 Jun 11 nicklas 3788     </sect2>
3315 09 May 07 nicklas 3789   </sect1>
3315 09 May 07 nicklas 3790
3675 16 Aug 07 jari 3791 </chapter>