Much more clear than what I had put together! thanks!

----- Original Message -----
From: "Scott Eade" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Wednesday, August 29, 2001 9:31 PM
Subject: Re: [HOWTO] Extend TurbineUser with your own class... - New Version
for review


> 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.
>
> Cheers,
>
> Scott
>
> ------------------- extend-user-howto.xml -----------------------
>
> <?xml version="1.0"?>
>  <document>
>   <properties>
>     <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>
>
>   <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>
>       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>
>       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>
>       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();
>
>     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.TurbineMapBuilderAdap
ter
>  services.SecurityService.user.class=org.mycompany.newapp.om.NewappUser
>
services.SecurityService.userPeer.class=org.mycompany.newapp.om.NewappUserPe
er
>     ]]></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[
>         NewappUser user = (NewappUser) data.getUser();
>     ]]></source>
>      <p>
>       Extending TurbineUser should be relatively straightforward with the
help
>       of this information.
>     </p>
>      <p>
>       Enjoy.
>     </p>
>    </section>
> </body>
> </document>
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
>
>


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

Reply via email to