Index: extend-user-howto.xml
===================================================================
RCS file: /home/cvspublic/jakarta-turbine-2/xdocs/howto/extend-user-howto.xml,v
retrieving revision 1.7
diff -u -r1.7 extend-user-howto.xml
--- extend-user-howto.xml	13 May 2002 19:51:46 -0000	1.7
+++ extend-user-howto.xml	11 Dec 2002 06:35:41 -0000
@@ -3,6 +3,7 @@
 <document>
   <properties>
     <title>Extend User Howto</title>
+    <author email="quintonm@bellsouth.net">Quinton McCombs</author>
     <author email="jon@latchkey.com">Jon S. Stevens</author>
     <author email="dan@chowda.net">Dan A. Bachelder</author>
     <author email="seade@backstagetech.com.au">Scott B. Eade</author>
@@ -28,11 +29,12 @@
         </ol>
      </p>
      <p>
-      The example herein uses TDK 2.1 and the TDK sample application Newapp.
+      The example herein uses a very simple object model with only one table.  
+      This table would be defined in your project-schema.xml file.
       To illustrate solutions to both of out motivators we will:
         <ol>
         <li>
-          Add a CREATE_USER_ID column to the RDF application table.
+          Add a REVIEWED_BY_USER_ID column to the BOOK application table.
         </li>
         <li>
           Add a TITLE column to TURBINE_USER.
@@ -45,58 +47,54 @@
       a transaction.  See the very end of this howto for further details.
      </p>
      <p>
-      First we update the schema for the project (in this case
-      newapp-schema.xml) to include an alias definition of TurbineUser (which
+     Here is the sample project-schema.xml file before making modifications
+     to reference TURBINE_USER.
+     <source><![CDATA[
+     <database defaultIdMethod="native" defaultJavaType="object">
+         <table name="BOOK">
+             <column name="BOOK_ID" required="true" primaryKey="true" type="INTEGER"/>
+             <column name="TITLE" required="true" type="VARCHAR"/>
+             <column name="AUTHOR" required="true" type="VARCHAR"/>
+             <column name="REVIEWED_BY_USER_ID" type="INTEGER"/>
+         </table>
+     </database>]]></source>
+     </p>
+     <p>
+      First we update the schema for the project (project-schema.xml)
+      to include an alias definition of TurbineUser (which
       will NOT create a new table) as well as the desired foreign key
       references.  Note how the TurbineUser definition refers to a pair of
       adapter classes (that we will create shortly) and how it is only
       necessary to define the columns we are referring to as foreign keys
       elsewhere in the application database.  Note also the addition of
-      CREATE_USER_ID as a foreign key in the RDF table.
+      REVIEWED_BY_USER_ID as a foreign key in the BOOK table.
      </p>
      <source><![CDATA[
-  <table name="TURBINE_USER" javaName="NewappUser" alias="TurbineUser"
-    baseClass="org.mycompany.newapp.om.TurbineUserAdapter"
-    basePeer="org.mycompany.newapp.om.TurbineUserPeerAdapter">
-    <!-- Unique identifier -->
-    <column name="USER_ID" primaryKey="true" required="true" type="integer"/>
-  </table>
-
-  <table name="RDF" idMethod="autoincrement">
-    <column name="RDF_ID" required="true" autoIncrement="true"
-        primaryKey="true" type="INTEGER"/>
-    <column name="TITLE" size="255" type="VARCHAR"/>
-    <column name="BODY" size="255" type="VARCHAR"/>
-    <column name="URL" size="255" type="VARCHAR"/>
-    <column name="AUTHOR" size="255" type="VARCHAR"/>
-    <column name="DEPT" size="255" type="VARCHAR"/>
-    <column name="CREATE_USER_ID" required="true" type="INTEGER"/>
-    <foreign-key foreignTable="TURBINE_USER">
-      <reference local="CREATE_USER_ID" foreign="USER_ID"/>
-    </foreign-key>
-  </table>]]></source>
-     <p>
-      The columns we want to add to TurbineUser must be defined in
-      turbine-schema.xml thus:
+     <database defaultIdMethod="native" defaultJavaType="object">
+         <table name="TURBINE_USER" alias="ExtendedUser" 
+                baseClass="org.mycompany.sampleapp.om.TurbineUserAdapter" 
+                basePeer="org.mycompany.sampleapp.om.TurbineUserPeerAdapter">
+             <column name="USER_ID" required="true" primaryKey="true" type="INTEGER"/>
+         </table>
+         <table name="BOOK">
+             <column name="BOOK_ID" required="true" primaryKey="true" type="INTEGER"/>
+             <column name="TITLE" required="true" type="VARCHAR"/>
+             <column name="AUTHOR" required="true" type="VARCHAR"/>
+             <column name="REVIEWED_BY_USER_ID" type="INTEGER"/>
+             <foreign-key foreignTable="TURBINE_USER">
+                 <reference local="REVIEWED_BY_USER_ID" foreign="USER_ID"/>
+             </foreign-key>
+         </table>
+     </database>]]></source>
+     <p>
+      Although we are adding a column to TURBINE_USER, do not modify 
+      turbine-schema.xml.  This will only make things more confusing.  Insetad,
+      rename your turbine-schema.xml file to turbine-schema.original.  This will 
+      also prevent the org.mycompany.sampleapp.om.Turbine* and 
+      org.mycompany.sampleapp.om.BaseTurbine* object from beging generated 
+      during the project-om ant task.  This is not a problem as these objects 
+      are not used.
     </p>
-     <source><![CDATA[
-  <table name="TURBINE_USER" idMethod="idbroker">
-    <column name="USER_ID" required="true" primaryKey="true" type="INTEGER"/>
-    <column name="LOGIN_NAME" required="true" size="32" type="VARCHAR"/>
-    <column name="PASSWORD_VALUE" required="true" size="32" type="VARCHAR"/>
-    <column name="FIRST_NAME" required="true" size="99" type="VARCHAR"/>
-    <column name="LAST_NAME" required="true" size="99" type="VARCHAR"/>
-    <column name="EMAIL" size="99" type="VARCHAR"/>
-    <column name="CONFIRM_VALUE" size="99" type="VARCHAR"/>
-    <column name="TITLE" size="99" type="VARCHAR"/> <!-- New column -->
-    <column name="MODIFIED" type="TIMESTAMP"/>
-    <column name="CREATED" type="TIMESTAMP"/>
-    <column name="LAST_LOGIN" type="TIMESTAMP"/>
-    <column name="OBJECTDATA" type="VARBINARY"/>
-    <unique>
-        <unique-column name="LOGIN_NAME"/>
-    </unique>
-  </table>]]></source>
      <p>
       Before we create the adapter classes referred to above we will first
       extend TurbineMapBuilder in order to tell Turbine about the additional
@@ -109,12 +107,12 @@
       into the temp hashtable if you like this).
      </p>
      <source><![CDATA[
-package org.mycompany.newapp.util.db.map;
+package org.mycompany.sampleapp.util.db.map;
 
 import java.util.Date;
 
-import org.apache.turbine.services.db.TurbineDB;
-import org.apache.turbine.util.db.map.TableMap;
+import org.apache.torque.Torque;
+import org.apache.torque.map.TableMap;
 import org.apache.turbine.util.db.map.TurbineMapBuilder;
 
 public class TurbineMapBuilderAdapter extends TurbineMapBuilder
@@ -141,14 +139,12 @@
     {
         super.doBuild();
 
-        // Make some objects.
-        String string = new String("");
+        // Make dummy object - required for adding a column to the map
         Integer integer = new Integer(0);
-        java.util.Date date = new Date();
 
         // Add extra User columns.
-        TableMap tMap = TurbineDB.getDatabaseMap().getTable(getTableUser());
-        tMap.addColumn(getTitle(), string);
+        TableMap tMap = Torque.getDatabaseMap().getTable(getTableUser());
+        tMap.addColumn(getClientId(),integer);
     }
 }]]></source>
      <p>
@@ -161,18 +157,19 @@
       setPerm() directly.
     </p>
      <source><![CDATA[
-package org.mycompany.newapp.om;
+package org.mycompany.sampleapp.om;
 
 import org.apache.turbine.om.security.TurbineUser;
-import org.apache.turbine.om.NumberKey;
+import org.apache.torque.om.NumberKey;
+import org.apache.turbine.util.ObjectUtils;
 
 public class TurbineUserAdapter extends TurbineUser
 {
     public static final String TITLE = "TITLE";
 
-    public NumberKey getUserId()
+    public Integer getUserId()
     {
-        return (NumberKey) getPrimaryKey();
+        return new Integer(((NumberKey)getPrimaryKey()).intValue());
     }
 
     public void setTitle(String title)
@@ -205,98 +202,41 @@
 
 import java.util.Vector;
 
+import org.mycompany.sampleapp.util.db.map.TurbineMapBuilderAdapter;
+import org.apache.torque.*;
+import org.apache.torque.om.*;
+import org.apache.torque.util.*;
 import org.apache.turbine.om.security.peer.TurbineUserPeer;
-import org.mycompany.newapp.util.db.map.TurbineMapBuilderAdapter;
 
 public class TurbineUserPeerAdapter extends TurbineUserPeer
 {
+    /** the default database name for this class */
+    public static final String DATABASE_NAME = "default";
+    private static TurbineMapBuilderAdapter mapBuilder;
+
     private static final TurbineMapBuilderAdapter mapBuilder =
-        (TurbineMapBuilderAdapter) getMapBuilder();
+        (TurbineMapBuilderAdapter)getMapBuilder("org.mycompany.sampleapp.util.db.map.TurbineMapBuilderAdapter");
 
     public static final String TITLE = mapBuilder.getUser_Title();
-}]]></source>
-     <p>
-      We can now use "ant project-om" to generate our OM layer using
-      the adapter classes we defined above.  Note that "ant init"
-      (WARNING: THE <code>init</code> TARGET WILL DELETE ALL DATA IN
-      YOUR DATABASE), or any other target that triggers a compile of
-      the OM layer will result in a compile error of BaseRdf due to
-      the fact that NewappUserPeer does not implement a retrieveByPK()
-      method.
-    </p>
-     <p>
-      So lets implement retrieveByPK() so that everything can compile.  This
-      needs to be implemented in NewappUserPeer which was generated by torque
-      when we executed project-om above (but it won't be deleted should we need
-      to regenerate the OM layer at some stage in the future - like in about 2
-      minutes).
-    </p>
-     <source><![CDATA[
-package org.mycompany.newapp.om;
-
-import java.util.*;
-
-import com.workingdogs.village.*;
-
-import org.apache.turbine.om.peer.*;
-import org.apache.turbine.util.*;
-import org.apache.turbine.util.db.*;
-import org.apache.turbine.util.db.map.*;
-import org.apache.turbine.util.db.pool.DBConnection;
-import org.apache.turbine.om.ObjectKey;
-import org.apache.turbine.services.db.TurbineDB;
-
-import org.mycompany.newapp.om.map.*;
-
-public class NewappUserPeer
-    extends org.mycompany.newapp.om.BaseNewappUserPeer
-{
-    public static NewappUser retrieveByPK(ObjectKey pk)
-        throws Exception
+    
+    /**
+     * Builds a criteria object to select by a primary key value.  Of course,
+     * it could also be used for an update or delete.
+     * @param pk Primary key to select/update/delete
+     * @return A Criteria object built to select by primary key
+     */
+    public static Criteria buildCriteria(ObjectKey pk)
     {
-        DBConnection db = null;
-        NewappUser retVal = null;
-
-        try
-        {
-            db = TurbineDB.getConnection(getMapBuilder()
-                .getDatabaseMap().getName());
-            retVal = retrieveByPK(pk, db);
-        }
-        finally
-        {
-            if (db != null)
-            {
-                TurbineDB.releaseConnection(db);
-            }
-        }
-        return(retVal);
-    }
+        Criteria crit = new Criteria();
+        crit.add(TurbineUserPeer.USER_ID,pk.getValue());
 
-    public static NewappUser retrieveByPK( ObjectKey pk, DBConnection dbcon )
-        throws Exception
-    {
-        Criteria criteria = new Criteria();
-        criteria.add( USER_ID, pk );
-        Vector v = doSelect(criteria, dbcon);
-        if ( v.size() != 1)
-        {
-            throw new Exception("Failed to select one and only one row.");
-        }
-        else
-        {
-            return (NewappUser)v.firstElement();
-        }
+        return crit;
     }
 }]]></source>
      <p>
-      Now we can use "ant init" to generate the rest of the things it
-      generates - this will include the regenreation of the OM layer, the
-      generation of the sql to create the database tables and the actual
-      execution of this sql to recreate the database tables to now include any
-      additional columns we have defined (<b>AS A CONSEQUENCE ALL DATA IN THE
-      DATABASE WILL BE DESTROYED</b>).
-     </p>
+      We can now use "ant project-om" to generate our OM layer using
+      the adapter classes we defined above.  
+    </p>
      <p>
       With any luck everything will compile okay and we are only a small step
       away from being able to use the new OM layer.  The last step is to tell
@@ -305,18 +245,18 @@
       TurbineResources.properties:
      </p>
      <source><![CDATA[
-database.maps.builder=org.mycompany.newapp.util.db.map.TurbineMapBuilderAdapter
-services.SecurityService.user.class=org.mycompany.newapp.om.NewappUser
-services.SecurityService.userPeer.class=org.mycompany.newapp.om.NewappUserPeer
+database.maps.builder=org.mycompany.sampleapp.util.db.map.TurbineMapBuilderAdapter
+services.SecurityService.user.class=org.mycompany.sampleapp.om.ExtendedUser
+services.SecurityService.userPeer.class=org.mycompany.sampleapp.om.ExtendedUserPeer
 ]]></source>
      <p>
       That is basically it.  We can now modify our application to utilise the
       new columns via the methods defined in the OM objects we have modified.
-      Note that in order to access the new methods in NewappUser we need to cast
+      Note that in order to access the new methods in ExtendedUser we need to cast
       from TurbineUser thus:
     </p>
      <source><![CDATA[
-NewappUser user = (NewappUser) data.getUser();]]></source>
+ExtendedUSer user = (ExtendedUSer) data.getUser();]]></source>
      <p>
       Extending TurbineUser should be relatively straightforward with the help
       of this information.
@@ -365,20 +305,20 @@
      ExtendedTurbineUser.save() is invoked.  Here is an example:
     </p>
     <source><![CDATA[
-Rdf rdf = new Rdf();
-data.getParameters().setProperties(rdf);
-NewappUser user = (NewappUser) data.getUser();
-user.addRdf(rdf);
-user.save(); // !!!! rdf is not saved !!!!]]></source>
+Book book = new Book();
+data.getParameters().setProperties(book);
+ExtendedUser user = (ExtendedUser) data.getUser();
+user.addBook(book);
+user.save(); // !!!! book is not saved !!!!]]></source>
     <p>
      Of course replacing the last two lines with:
     </p>
     <source><![CDATA[
-rdf.setCreateUserId(user.getUserId());
-rdf.save();]]></source>
+book.setReviewedByUserId(user.getUserId());
+book.save();]]></source>
     <p>
-     will in fact save the Rdf, this is beside the point - the other method
-     addRdf() shouldn't exist if it doesn't work and this is a trivial example.
+     will in fact save the Book, this is beside the point - the other method
+     addBook() shouldn't exist if it doesn't work and this is a trivial example.
     </p>
     <p>
      In addition to this, there is no equivalent save(dbConn) method provided

