Sure thing... this is my first patch ever... so someone might want to be
extra careful with it :)

I got the howto i wrote from web CVS and cut the new from the email and then
did this:

diff -u extend-user-howto.xml extend_user_howto_new.xml >>
extend-user-howto-patchfile.txt

look right to everyone?

----- Original Message -----
From: "Daniel Rall" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Thursday, August 30, 2001 6:16 PM
Subject: Re: [HOWTO] Extend TurbineUser with your own class... - New Version
for review


> "Scott Eade" <[EMAIL PROTECTED]> writes:
>
> > Below is my completely revamped XDOC version of extend-user-howto.xml.
> >
> > Can those of you that are interested please have a look at this and let
me know
> > if you agree with my approach which is a combination of the approaches
put
> > forward by a number of different people on this list.
> >
> > The approach documented works, but I am not going to be too surprised if
> > there are different opinions as to the best way of doing this. It should
be noted
> > however that this is the only way I have been able to get this working
without
> > risking the loss of code when regenerating the OM layer code.
> >
> > I'll try out any suggestions and update the document before requesting a
> > commit.
>
> Please send a unidiff.
>
> http://jakarta.apache.org/site/source.html
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
>
>
--- extend-user-howto.xml       Sun Sep 02 00:42:46 2001
+++ extend_user_howto_new.xml   Sun Sep 02 00:40:00 2001
@@ -5,110 +5,323 @@
     <title>Extend User Howto</title>
     <author email="[EMAIL PROTECTED]">Jon S. Stevens</author>
     <author email="[EMAIL PROTECTED]">Dan A. Bachelder</author>
+    <author email="[EMAIL PROTECTED]">Scott B. Eade</author>
   </properties>
-
+  
   <body>
-
+  
   <section name="Extend User">
+  
+     <p>
+      This is a not quite quick-and-dirty HOWTO on extending the TurbineUser and
+      its functionality.  The motivating factors for extending TurbineUser are:
+        <ol>
+        <li>
+          to be able to make use of TURBINE_USER.USER_ID as a foreign key in
+          application tables; and
+        </li>
+        <li>
+          to be able to represent additional user attributes by adding columns
+          to TURBINE_USER.
+        </li>
+        </ol>
+     </p>
+     <p>
+      The example herein uses TDK 2.1 and the TDK sample application Newapp.
+      To illustrate solutions to both of out motivators we will:
+        <ol>
+        <li>
+          Add a CREATE_USER_ID column to the RDF application table.
+        </li>
+        <li>
+          Add a TITLE column to TURBINE_USER.
+        </li>
+        </ol>
+     </p>
+     <p>
+      First we update the schema for the project (in this case
+      newapp-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.
+     </p>
+     <source><![CDATA[
+  <table name="NEWAPP_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>
 
-    <p>
-      This is a quick a dirty HOWTO on extending the TurbineUser and
-      its functionality. <br/>
-      All information is based on what I had to do to get this to work
-      under TDK 2.1.
-    </p>
-
-    <p>
-      Define your User in your [PROJECT]-schema.xml file:
-    </p>
-
-    <source><![CDATA[
-
-  <table name="SCARAB_USER" javaName="ScarabUserImpl" alias="TurbineUser"
-         baseClass="org.apache.turbine.om.security.TurbineUser"
-         basePeer="org.apache.turbine.om.security.peer.TurbineUserPeer">
-    <column name="USER_ID" primaryKey="true" required="true"
-            type="INTEGER"/>
+  <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="NEWAPP_USER">
+      <reference local="CREATE_USER_ID" foreign="USER_ID"/>
+    </foreign-key>
   </table>
     ]]></source>
-
-    <p>
-      You only need to define the columns in which you are referring to as a
-      foreign key elsewhere in your database. In our case, that is
-      just USER_ID. <br/>
-      This will NOT create a new table in your schema, it simply allows you to
-      make foreign key references to the TURBINE_USER table in you applications
-      schema.
-    </p>
-
-    <p>
-      Any new columns need to be added to the TURBINE_USER def. in the
-      turbine-schema.xml file.
-    </p>
-
-    <p>
-      Create an interface which describes the additional methods you are adding
-      to your User object:
-    </p>
-
-    <source><![CDATA[
-  public interface ScarabUser extends User
+     <p>
+      The columns we want to add to TurbineUser must be defined in
+      turbine-schema.xml thus:
+    </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>
-      Using TDK 2.1 "ant init" will regenerate your OM layer, including the
-      implementations referenced in the following paragraphs (ScarabUserImpl,
-      ScarabUserImplPeer, BaseScarabUserImpl and  BaseScarabUserImplPeer). <br/>
-      <b>IT WILL ALSO RECREATE YOUR DATABASE TABLES DESTROYING ALL DATA
-      THEREIN.</b>
-    </p>
-
-    <p>
-      Have Torque create an implementation of ScarabUser. You should then fill
-      it with the methods that you defined in ScarabUser. It should extend the
-      Base class and look something like this:
-    </p>
-
-    <source><![CDATA[
-  public class ScarabUserImpl extends BaseScarabUserImpl
-         implements Persistent, ScarabUser
+     <p>
+      Before we create the adapter classes referred to above we will first
+      extend TurbineMapBuilder in order to tell Turbine about the additional
+      columns we are adding to TurbineUser.  Note that you can actually omit
+      this step and not even define database columns for the additional
+      attributes you want to add if you don't care to have easy external access
+      to the data.  If you do this the data for the additional attributes will
+      be written to TURBINE_USER.OBJECTDATA along with any other data added to
+      the the perm hashtable (this is a way cool feature, you should also look
+      into the temp hashtable if you like this).
+     </p>
+     <source><![CDATA[
+package org.mycompany.newapp.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.turbine.util.db.map.TurbineMapBuilder;
+
+public class TurbineMapBuilderAdapter extends TurbineMapBuilder
+{
+   public String getTitle()
+   {
+        return "TITLE";
+   }
+
+    public String getUser_Title()
+    {
+        return getTableUser() + '.' + getTitle();
+    }
+
+    public void doBuild()
+        throws java.lang.Exception
+    {
+        super.doBuild();
+
+        // Make some objects.
+        String string = new String("");
+        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);
+    }
+}
     ]]></source>
-
-    <p>
-      You may need to add your interface (ScarabUser) to the implements
-      statement manually.
-    </p>
-
-    <p>
-      Have Torque create the appropriate Peer class (mine is empty so far):
-    </p>
-
-    <source><![CDATA[
-  public class ScarabUserImplPeer
-      extends org.tigris.scarab.om.BaseScarabUserImplPeer
-  {
-  }
+     <p>
+      Now we will implement the pair of adapters we referred to in our schema.
+      First we implement TurbineUserAdapter to provide access to the primary key
+      as well as the column we are adding to TurbineUser.  If you are going to
+      use OBJECTDATA (and not define new columns in the database) you can still
+      add accessor methods here for convenience if you like, alternatively you
+      can just use setPerm() directly.
+    </p>
+     <source><![CDATA[
+package org.mycompany.newapp.om;
+
+import org.apache.turbine.om.security.TurbineUser;
+import org.apache.turbine.om.NumberKey;
+
+public class TurbineUserAdapter extends TurbineUser
+{
+    public static final String TITLE = "TITLE";
+
+    public NumberKey getUserId()
+    {
+        return (NumberKey) getPrimaryKey();
+    }
+
+    public void setTitle(String title)
+    {
+        setPerm(TITLE, title);
+    }
+
+    public String getTitle()
+    {
+        String tmp = null;
+        try
+        {
+            tmp = (String) getPerm(TITLE);
+            if ( tmp.length() == 0 )
+                tmp = null;
+        }
+        catch ( Exception e )
+        {
+        }
+        return tmp;
+    }
+}
     ]]></source>
+     <p>
+       Next comes TurbineUserPeerAdapter to which we also add details of the new
+       database columns (the body will be empty if you choose to use
+       OBJECTDATA).
+     </p>
+     <source><![CDATA[
+package org.mycompany.newapp.om;
+
+import java.util.Vector;
+
+import org.apache.turbine.om.security.peer.TurbineUserPeer;
+import org.mycompany.newapp.util.db.map.TurbineMapBuilderAdapter;
+
+public class TurbineUserPeerAdapter extends TurbineUserPeer
+{
+    private static final TurbineMapBuilderAdapter mapBuilder =
+        (TurbineMapBuilderAdapter) getMapBuilder();
 
-    <p>
-      In your TurbineResources.properties file modify the following properties
-      to tell Turbine to point at your specific implementations of the User
-      interface:
+    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 init 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>
+      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 init 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
+    {
+        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);
+    }
+
+    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();
+        }
+    }
+}
+    ]]></source>
+     <p>
+      Now we can now 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>
+     <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
+      Turbine about the new classes we are using for Users and the new
+      MapBuilder.  To do this we need to update the following entries in
+      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
+    ]]></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
+      from TurbineUser thus:
     </p>
-
-    <source><![CDATA[
-  services.SecurityService.user.class=org.tigris.scarab.om.ScarabUserImpl
-  services.SecurityService.userPeer.class=org.tigris.scarab.om.ScarabUserImplPeer
+     <source><![CDATA[
+        NewappUser user = (NewappUser) data.getUser();
     ]]></source>
-
-    <p>
-      As you can see, it isn't real hard to override Turbine's concept of a User
-      with your own specific implementation. If you wish to rename column names
-      and what not, then you will need to do a bit more work and is beyond the
-      scope of this tutorial.
+     <p>
+      Extending TurbineUser should be relatively straightforward with the help
+      of this information.
     </p>
-
-  </section>
+     <p>
+      Enjoy.
+    </p>
+   </section>
 </body>
 </document>
-

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to