| <!DOCTYPE html> |
| |
| |
| <!-- |
| | Generated by Apache Maven Doxia Site Renderer 2.0.0 from src/site/xdoc/howto/extend-user-howto.xml at 10 Sep 2025 |
| | Rendered using Apache Maven Fluido Skin 2.1.0 |
| --> |
| <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> |
| <head> |
| <meta charset="UTF-8" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> |
| <meta name="generator" content="Apache Maven Doxia Site Renderer 2.0.0" /> |
| <title>Extend User Howto – Apache Turbine</title> |
| <link rel="stylesheet" href="../css/apache-maven-fluido-2.1.0.min.css" /> |
| <link rel="stylesheet" href="../css/site.css" /> |
| <link rel="stylesheet" href="../css/print.css" media="print" /> |
| <script src="../js/apache-maven-fluido-2.1.0.min.js"></script> |
| <link rel="icon" type="image/png" sizes="48x48" href="https://apache.org/favicons/favicon.ico"> |
| <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> |
| <style>.github-fork-ribbon:before { background-color: orange; }</style> |
| </head> |
| <body> |
| <a class="github-fork-ribbon right-top" href="https://github.com/apache/turbine-build" data-ribbon="Fork me on GitHub">Fork me on GitHub</a> |
| <div class="container-fluid container-fluid-top"> |
| <header> |
| <div id="banner"> |
| <div class="pull-left"><div id="bannerLeft"><h1><a href="https://turbine.apache.org/"><img src="https://www.apache.org/img/feather_glyph_notm.png" style="width: 50px;" /> The Apache Turbine project</a></h1></div></div> |
| <div class="pull-right"><div id="bannerRight"><h1><a href="https://turbine.apache.org/"><img src="https://turbine.apache.org/images/logo.gif" alt="Apache Turbine" /></a></h1></div></div> |
| <div class="clear"><hr/></div> |
| </div> |
| |
| <div id="breadcrumbs"> |
| <ul class="breadcrumb"> |
| <li id="publishDate">Last Published: 01 Apr 2025<span class="divider">|</span> |
| </li> |
| <li id="projectVersion">Version: 7.1-SNAPSHOT</li> |
| <li class="pull-right"><span class="divider">|</span> |
| <a href="https://turbine.apache.org/fulcrum/">Fulcrum</a></li> |
| <li class="pull-right"><span class="divider">|</span> |
| <a href="https://turbine.apache.org/">Turbine</a></li> |
| <li class="pull-right"><a href="https://www.apache.org">Apache</a></li> |
| </ul> |
| </div> |
| </header> |
| <div class="row-fluid"> |
| <header id="leftColumn" class="span2"> |
| <nav class="well sidebar-nav"> |
| <ul class="nav nav-list"> |
| <li class="nav-header">General Information</li> |
| <li><a href="../index.html">Overview</a></li> |
| <li><a href="../features.html">Features</a></li> |
| <li><a href="../fsd.html">Specification</a></li> |
| <li><a href="../getting-started.html">Getting Started</a></li> |
| <li><a href="../how-to-build.html">Howto Build Turbine</a></li> |
| <li><a href="../changes-report.html">Changes</a></li> |
| <li class="nav-header">Documentation</li> |
| <li><a href="../services/index.html"><span class="icon-chevron-right"></span>Services</a></li> |
| <li><a href="../howto/index.html"><span class="icon-chevron-down"></span>Howtos</a> |
| <ul class="nav nav-list"> |
| <li><a href="../howto/action-event-howto.html">Action Events Howto</a></li> |
| <li><a href="../howto/annotations.html">Annotations Howto</a></li> |
| <li><a href="../howto/configuration-howto.html">Configuration Howto</a></li> |
| <li class="active"><a>Extend User Howto</a></li> |
| <li><a href="../howto/hibernate-howto.html">Hibernate OM Howto</a></li> |
| <li><a href="../howto/intake-howto.html">Intake Howto</a></li> |
| <li><a href="../howto/jsp-howto.html">JSP Howto</a></li> |
| <li><a href="../howto/migrate-from-2_1-howto.html">Migrating from 2.1 to 2.2</a></li> |
| <li><a href="../howto/migrate-from-2_2-howto.html">Migrating from 2.2 to 2.3</a></li> |
| <li><a href="../howto/migrate-from-2_3-howto.html">Migrating from 2.3 to 4.0</a></li> |
| <li><a href="../howto/migrate-from-4_0-howto.html">Migrating from 4.0 to 5.0</a></li> |
| <li><a href="../howto/pullmodel-howto.html">Pull Model Howto</a></li> |
| <li><a href="../howto/python-howto.html">Python Howto</a></li> |
| <li><a href="../howto/security-howto.html">Security Howto</a></li> |
| <li><a href="../howto/services-howto.html">Services Howto</a></li> |
| <li><a href="../howto/url-mapper-howto.html">URL Mapper Howto</a></li> |
| <li><a href="../howto/url-rewriting-howto.html">URL Rewriting Howto</a></li> |
| <li><a href="../howto/context-howto.html">Velocity Context Howto</a></li> |
| <li><a href="../howto/velocity-site-howto.html">Velocity Site Howto</a></li> |
| <li><a href="../howto/velocityonlylayout-howto.html">VelocityOnlyLayout Howto</a></li> |
| </ul></li> |
| <li><a href="https://cwiki.apache.org/confluence/display/TURBINE">Wiki</a></li> |
| <li><a href="../apidocs/index.html">JavaDocs</a></li> |
| <li class="nav-header">Development</li> |
| <li><a href="../proposals.html">Proposals</a></li> |
| <li><a href="../how-to-help.html">How To Help</a></li> |
| <li><a href="../todo.html">Todo</a></li> |
| <li class="nav-header">Project Documentation</li> |
| <li><a href="../project-info.html"><span class="icon-chevron-right"></span>Project Information</a></li> |
| <li><a href="../project-reports.html"><span class="icon-chevron-right"></span>Project Reports</a></li> |
| <li class="nav-header">Apache</li> |
| <li><a href="https://www.apache.org/">Apache Website</a></li> |
| <li><a href="https://www.apache.org/licenses/">License</a></li> |
| <li><a href="https://www.apache.org/foundation/how-it-works.html">How the ASF works</a></li> |
| <li><a href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li> |
| <li><a href="https://www.apache.org/foundation/thanks.html">Thanks</a></li> |
| <li><a href="https://www.apache.org/security/">Security</a></li> |
| </ul> |
| </nav> |
| <div class="well sidebar-nav"> |
| <form id="search-form" action="https://www.google.com/search" method="get" > |
| <input value="http://turbine.apache.org/turbine/turbine-7-0" name="sitesearch" type="hidden" /> |
| <input class="search-query" name="q" id="query" type="text" placeholder="Search with Google..." /> |
| </form> |
| <div id="poweredBy"> |
| <div class="clear"></div> |
| <div class="clear"></div> |
| <a href="https://maven.apache.org/" class="builtBy" target="_blank"><img class="builtBy" alt="Built by Maven" src="../images/logos/maven-feather.png" /></a> |
| </div> |
| </div> |
| </header> |
| <main id="bodyColumn" class="span10"> |
| |
| |
| |
| |
| <section><a id="Important_note"></a> |
| <h1>Important note</h1> |
| |
| <p> |
| The information in this HOWTO pertains to Turbine 2.2. Please refer |
| to the <a href="../services/security-service.html">Torque |
| Security Service</a> page for information on extending TurbineUser |
| in Turbine 2.3 and beyond. |
| </p> |
| </section> |
| <section><a id="Introduction"></a> |
| <h1>Introduction</h1> |
| |
| <p> |
| This is a HOWTO on extending the TurbineUser and its |
| functionality. The motivating factors for extending TurbineUser |
| are: |
| </p> |
| <ol style="list-style-type: decimal;"> |
| |
| <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> |
| 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 our motivators we will: |
| </p> |
| <ol style="list-style-type: decimal;"> |
| |
| <li> |
| Add a REVIEWED_BY_USER_ID column to the BOOK application table. This will |
| also include a foreign key reference back to TURBINE_USER. |
| </li> |
| |
| <li> |
| Add a TITLE column to TURBINE_USER. |
| </li> |
| </ol> |
| |
| |
| <p> |
| <b>Important Note:</b> This solution is functionally incomplete in that |
| it does not support the ability to use TurbineUser as a commit point for |
| a transaction. See the very end of this document for further details. |
| </p> |
| |
| |
| <p> |
| It is also important to note that this HOWTO is intended for use with |
| the database implementation of the SecurityService. I will not address |
| how to extend TurbineUser for use with any other implementation. |
| </p> |
| </section> |
| |
| <section><a id="How_does_TurbineUser_actually_work.3F"></a> |
| <h1>How does TurbineUser actually work?</h1> |
| |
| |
| <p> |
| The inplementation of TurbineUser and TurbineUserPeer is distributed |
| with Turbine in the <code>org.apache.turbine.om.security</code> |
| package. It is _NOT_ generated by Torque at this time. There are |
| no corresponding Base* classes nor a TurbineUserMapBuilder either. |
| </p> |
| |
| <p> |
| TurbineUser implements the User interface (from the same package). |
| This interface is used by the Security Service and a few other |
| services as well. This is the reason behind not generating TurbineUser |
| through Torque. It would have no idea how to provide an implementation |
| of the User interface leaving that inplementaion to you. |
| </p> |
| |
| <p> |
| The MapBuilder for TurbineUser is |
| <code>org.apache.turbine.util.db.map.TurbineMapBuilder</code>. This |
| MapBuilder is also used by Turbine for the other Turbine* classes |
| that are defined in the turbine-schema.xml file distributed with Turbine. |
| </p> |
| |
| <p> |
| The turbine-schema.xml file is the source of a small problem. The ant task |
| used to generate your OM layer will generate OM objects for all of the tables |
| defined in this file along with the MapBuilders. These classes do not really |
| hurt anything but they can be a source of confusion. There are not used |
| by Turbine for anything! |
| </p> |
| |
| <p> |
| One valid reason for leaving this file in place is for the ant task that will |
| create your database schema for you. Since the task will not modify the schema |
| for you after it is created (to add/remove columns, indexes, etc), it is of |
| little use after the database is created other than to serve as a reference. |
| </p> |
| |
| <p> |
| Later in this discussion, you will be given instruction to rename this file to |
| prevent it from being used by the ant tasks as well as removing any objects |
| generated as a result. |
| </p> |
| |
| <p> |
| Another interesting fact about TurbineUser is the way in which data stored in |
| the database is accessed. Instead of using using private attributes for storage |
| within the object, all attibutes are stored in a hashtable (known herein as the |
| perm hashtable). Access to the perm hashtable is controlled through the |
| getPerm/setPerm methods. |
| </p> |
| |
| <p> |
| When the object is returned from the database, data from the columns are |
| added to the perm hashtable for you. When you save the object, the data |
| is removed from the perm hashtable and written to the appropriate database |
| columns. |
| </p> |
| |
| <p> |
| As you will read later, any data left in the perm hashtable that does |
| not have a mapped database column (more on this later) |
| during the save operation will be serialized and written to the |
| TURBINE_USER.OBJECTDATA column. |
| </p> |
| |
| <p> |
| Another very nice feature of TurbineUser is the getTemp/setTemp |
| methods. This allows you to store data in TurbineUser for the duration |
| of the session. It will not be written to your persistent storage. |
| It is ONLY for the session. Keep in mind that the login action will |
| replace the user object in the session with a user object from your |
| persistent storage thus removing any data you might have stored in the |
| user. |
| </p> |
| |
| </section> |
| |
| <section><a id="Modifications_to_project-schema.xml"></a> |
| <h1>Modifications to project-schema.xml</h1> |
| |
| <p> |
| Here is the sample project-schema.xml file before making modifications |
| to reference TURBINE_USER. |
| </p> |
| |
| <pre class="prettyprint"><code> |
| |
| <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"/> |
| </table> |
| </database> |
| |
| </code></pre> |
| |
| <p> |
| First we update the schema to include an alias definition of TurbineUser |
| as well as the desired foreign key |
| references. Note how the TurbineUser definition refers to a pair of |
| adapter classes (we will create these 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 |
| REVIEWED_BY_USER_ID as a foreign key in the BOOK table. |
| </p> |
| |
| <pre class="prettyprint"><code> |
| |
| <database defaultIdMethod="native" defaultJavaType="object"> |
| <table name="EXTENDED_USER" alias="TurbineUser" |
| 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="EXTENDED_USER"> |
| <reference local="REVIEWED_BY_USER_ID" foreign="USER_ID"/> |
| </foreign-key> |
| </table> |
| </database> |
| |
| </code></pre> |
| |
| <p> |
| Notice the attribute on the database tag for defaultJavaType. I used |
| "object" as the value. The default is "primitive". You do not have to |
| use "object"!!! |
| </p> |
| |
| <p> |
| Turbine Version 2.1 only: In this version of Turbine, the only option was to use the |
| primitive types. However, this posed a small problem. It was not |
| possible to have number or boolean types that contained null values. |
| If a null value was found in the database for columns of these types, |
| the value returned from the OM object was 0 or false, respectively. |
| This also implies that you can not have non-required foreign key |
| references back to TURBINE_USER. The primary key of TURBINE_USER |
| is a number. |
| </p> |
| </section> |
| |
| <section><a id="Deciding_how_additional_data_in_Turbine_User_will_be_stored"></a> |
| <h1>Deciding how additional data in Turbine User will be stored</h1> |
| |
| <p> |
| There are two ways in which additional data in your extended TurbineUser |
| object can be stored. The first, and simplest method, is to store it in |
| the perm hashtable. As described earlier, any data in the perm hashtable |
| not mapped to a database column will get serialized into the |
| TURBINE_USER.OBJECTDATA column. The second, and perferred method, is to |
| use additional database column(s) for storage. |
| </p> |
| |
| <p> |
| Although storing the additional data in the TURBINE_USER.OBJECTDATA |
| column is the simplest method, it has a few drawbacks. |
| </p> |
| <ol style="list-style-type: decimal;"> |
| |
| <li> |
| You will not have easy access to the data through SQL. |
| </li> |
| |
| <li> |
| You will not be able to specify criteria to select TurbineUser |
| objects from the database by filtering on data stored in |
| TURBINE_USER.OBJECTDATA. |
| </li> |
| |
| <li> |
| There is an upper limit to the amount of data that can be stored |
| in the TURBINE_USER.OBJECTDATA column. A few users have reported |
| on the mailing list that they ran into this problem. The limit |
| will vary from one database to another. This limit is reduced |
| by persistent pull tools (see the docs on the PullService for |
| details), if you have any in your project, |
| as they are stored using this method by the PullService. |
| </li> |
| </ol> |
| |
| |
| <p> |
| If you do decide to store some of your additional attributes |
| in the TURBINE_USER.OBJECTDATA column, you need to be careful |
| of possible conflicts with the keys used in the perm hashtable by |
| TurbineUser. When |
| the object is saved to the database, this data is removed from the |
| perm hashtable and written to the correct columns. The keys used in the |
| perm hashtable are the uppercase names of the columns. The column names |
| are not fully qualified with the names of the table like |
| <code>TURBINE_USER.LAST_NAME</code>. Instead the key used is |
| <code>LAST_NAME</code>. See |
| <code>org.apache.turbine.util.db.map.TurbineMapBuilder</code> for a |
| complete list of the keys used for the default columns. |
| </p> |
| |
| <p> |
| If you choose to use additional database columns, you will not have |
| any of the drawbacks mentioned above. Using the additional columns |
| is the approach that should be taken unless you have a |
| <strong>VERY</strong> good reason not to do so. |
| </p> |
| </section> |
| |
| <section><a id="Implementing_adapter_and_map_builder_classes"></a> |
| <h1>Implementing adapter and map builder classes</h1> |
| |
| <p> |
| First, we will extend the map builder used by Turbine for the Turbine* |
| classes to add the additional column(s) that we will be using in |
| TURBINE_USER. |
| </p> |
| |
| <pre class="prettyprint"><code> |
| |
| package org.mycompany.sampleapp.util.db.map; |
| |
| import org.apache.torque.Torque; |
| import org.apache.torque.map.TableMap; |
| import org.apache.turbine.util.db.map.TurbineMapBuilder; |
| |
| /** |
| * Used to add the mapping of additional columns into any of the |
| * TURBINE_* tables. This can be implemented as an empty class |
| * if you are not adding any additional database columns. |
| */ |
| public class TurbineMapBuilderAdapter extends TurbineMapBuilder |
| { |
| /* |
| * Note: The getUser_*() methods in this class should be static, but |
| * getTableUser() and the initial field level methods are incorrectly |
| * declared in TurbineMapBuilder and hence we must use non-static methods |
| * here. |
| */ |
| |
| /** |
| * Gets the name of the database column that we are adding to |
| * TURBINE_USER. |
| * @return The name of the database column. |
| */ |
| public static String getTitle() |
| { |
| return "TITLE"; |
| } |
| |
| /** |
| * Gets the fully qualified column name (TABLE.COLUMN) that will be |
| * used to store the Title attribute in the extended TurbineUser object. |
| * @return The fully qualified database column name. |
| */ |
| public String getUser_Title() |
| { |
| return getTableUser() + '.' + getTitle(); |
| } |
| |
| /** |
| * Creates the map used by Torque to persist the Turbine* objects |
| * to the TURBINE_* tables. |
| * @throws Exception generic error |
| */ |
| public void doBuild() throws Exception |
| { |
| // the superclass version of the MapBuilder must be called to create |
| // the mappings for the default columns. |
| super.doBuild(); |
| |
| // When you add a column to the database map, the map must know |
| // what type of data will be stored in the column. For that |
| // purpose, we will create a few dummy objects to serve as |
| // data type indicators. Not all of them are used in our example. |
| Integer dummyInteger = new Integer(0); |
| Date dummyDate = new Date(); |
| String dummyString = new String(); |
| |
| // Add extra column. |
| TableMap tMap = Torque.getDatabaseMap().getTable(getTableUser()); |
| tMap.addColumn(getTitle(),dummyInteger); |
| } |
| } |
| |
| </code></pre> |
| |
| <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 any additional attibutes we are adding. |
| </p> |
| |
| <pre class="prettyprint"><code> |
| |
| package org.mycompany.sampleapp.om; |
| |
| import org.apache.turbine.om.security.TurbineUser; |
| import org.apache.torque.om.NumberKey; |
| import org.apache.turbine.util.ObjectUtils; |
| |
| /** |
| * This class extends TurbineUser for the purpose of adding get/set methods |
| * for accessing additional attributes. |
| */ |
| public class TurbineUserAdapter extends TurbineUser |
| { |
| /** Used as the key in the perm hashtable. */ |
| public static final String TITLE = "TITLE"; |
| |
| /** |
| * Gets the userId of the user. This is also the primary key |
| * of the TURBINE_USER table. The return type of Integer is |
| * valid only if the javaType for the ExtendedUser table |
| * is "object". If it is "primative", the return type |
| * should be changed to int. |
| * @return the user id |
| */ |
| public Integer getUserId() |
| { |
| return new Integer(((NumberKey)getPrimaryKey()).intValue()); |
| } |
| |
| /** |
| * Sets the title of the user. |
| * @param title the user's title |
| */ |
| public void setTitle(String title) |
| { |
| setPerm(TITLE, title); |
| } |
| |
| /** |
| * Gets the user's title |
| * @return the user's title |
| */ |
| public String getTitle() |
| { |
| String tmp = null; |
| try |
| { |
| tmp = (String) getPerm(TITLE); |
| if ( tmp.length() == 0 ) |
| tmp = null; |
| } |
| catch (Exception e) |
| { |
| } |
| return tmp; |
| } |
| } |
| |
| </code></pre> |
| |
| <p> |
| Note: This class uses the setPerm and getPerm methods to |
| access the data even though we are going to use the TURBINE_USER.TITLE |
| column for storage. As mentioned earlier, the data is removed from the |
| hashtable when the object is saved to the database and written to the |
| correct database column. Likewise, the when the object is retrieving |
| data from the database, the data from the TURBINE_USER.TITLE column is |
| added to the perm hashtable with the TITLE key. |
| </p> |
| |
| <p> |
| Next comes TurbineUserPeerAdapter to which we add details of the new |
| database columns. |
| </p> |
| |
| <pre class="prettyprint"><code> |
| |
| package org.mycompany.newapp.om; |
| |
| import org.mycompany.sampleapp.util.db.map.TurbineMapBuilderAdapter; |
| import org.apache.torque.om.ObjectKey; |
| import org.apache.torque.util.Criteria; |
| import org.apache.turbine.om.security.peer.TurbineUserPeer; |
| |
| /** |
| * This class extends TurbineUserPeer for the purpose of mapping additional |
| * database columns. You can implement this as an empty class if you are not |
| * using any additional database columns. |
| */ |
| public class TurbineUserPeerAdapter extends TurbineUserPeer |
| { |
| /** the default database name for this class */ |
| public static final String DATABASE_NAME = "default"; |
| |
| /** Used to build the map for the extended Turbine User */ |
| private static final TurbineMapBuilderAdapter mapBuilder = |
| (TurbineMapBuilderAdapter)getMapBuilder("org.mycompany.sampleapp.util.db.map.TurbineMapBuilderAdapter"); |
| |
| /** The fully qualified name of the database table */ |
| public static final String TITLE = mapBuilder.getUser_Title(); |
| |
| /** |
| * 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) |
| { |
| Criteria crit = new Criteria(); |
| crit.add(TurbineUserPeer.USER_ID, pk.getValue()); |
| |
| return crit; |
| } |
| } |
| </code></pre> |
| </section> |
| |
| <section><a id="Generating_the_OM_layer"></a> |
| <h1>Generating the OM layer</h1> |
| |
| <p> |
| Before generating the OM layer, see if you have a turbine-schema.xml |
| file in your WEB-INF/conf directory. If you do, rename this file to |
| turbine-schema.xml.nogenerate. Also, the only Turbine* classes that |
| you should have in your om package are the two adapters that you |
| created earlier. Any other Turbine* or BaseTurbine* class in your om |
| package should be removed. You should also remove any om.map.Turbine* |
| classes that might have been generated. |
| </p> |
| |
| <p> |
| |
| <b>Warning: Do not run the init ant task after doing this.</b> |
| That task will drop and recreate your database. Without the |
| turbine-schema.xml file present, the TURBINE_* tables will not |
| be recreated! |
| </p> |
| |
| <p> |
| These classes were generated from the turbine-schema.xml file. The |
| project-om ant task will process |
| any file in your WEB-INF/conf directory ending in <code>-schema.xml</code> |
| and generate the appropriate classes from that definition. Renaming the |
| turbine-schema.xml file stops these extra classes from being generated. |
| </p> |
| |
| <p> |
| Next, you will need to manually create any additional database columns |
| that you will be using in TURBINE_USER. Make sure that the name of the |
| columns match what you speificied in TurbineUserPeerAdapter. |
| </p> |
| |
| <p> |
| We can now use project-om ant task 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. |
| </p> |
| </section> |
| |
| <section><a id="Modifications_to_TurbineResources.properties"></a> |
| <h1>Modifications to TurbineResources.properties</h1> |
| |
| <p> |
| The last step is to tell Turbine about the new classes we are using for |
| Users and MapBuilder. To do this we need to update the following |
| entries in TurbineResources.properties: |
| </p> |
| |
| <pre class="prettyprint"><code> |
| |
| 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 |
| |
| </code></pre> |
| |
| <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 ExtendedUser we need to cast |
| from TurbineUser thus: |
| </p> |
| |
| <pre class="prettyprint"><code> |
| |
| ExtendedUser user = (ExtendedUser) data.getUser(); |
| |
| </code></pre> |
| |
| <p> |
| Enjoy. |
| </p> |
| </section> |
| |
| <section><a id="Additional_Information"></a> |
| <h1>Additional Information</h1> |
| |
| <p> |
| For those of you that are attempting to extend TurbineUser to make use of |
| TURBINE_USER.USER_ID as a foreign key in your application tables here is |
| one small problem. |
| </p> |
| |
| <p> |
| Torque generates some pretty useful code that enables you to add related |
| objects to a common parent object and then save them all to the database |
| in one transaction. You can do something like this: |
| </p> |
| |
| <pre class="prettyprint"><code> |
| |
| OrderDetail od1 = new OrderDetail(500, "item1"); |
| OrderDetail od2 = new OrderDetail(100, "item2"); |
| Order o = new Order(clientId); |
| o.addOrderDetail(od1); |
| o.addOrderDetail(od2); |
| o.save(); |
| |
| </code></pre> |
| |
| <p> |
| This is very helpful - you don't need to worry about the ids that connect |
| the child rows to the parent rows and you don't need to worry about the |
| transaction necessary to insert these into the database as one atomic |
| operation. It also provides: |
| </p> |
| |
| <pre class="prettyprint"><code> |
| |
| o.save(dbConn); |
| |
| </code></pre> |
| |
| <p> |
| which can be used when you have other data you want to commit in a |
| transaction you are managing yourself. |
| </p> |
| |
| <p> |
| Now here is the problem. After extending TurbineUser in the manner |
| described above, the methods are generated to add records related the |
| extended user class, but the data itself is ignored when |
| ExtendedUser.save() is invoked. Here is an example: |
| </p> |
| |
| <pre class="prettyprint"><code> |
| |
| Book book = new Book(); |
| data.getParameters().setProperties(book); |
| ExtendedUser user = (ExtendedUser) data.getUser(); |
| user.addBook(book); |
| user.save(); // !!!! book is not saved !!!! |
| |
| </code></pre> |
| |
| <p> |
| Of course replacing the last two lines with: |
| </p> |
| |
| <pre class="prettyprint"><code> |
| |
| book.setReviewedByUserId(user.getUserId()); |
| book.save(); |
| |
| </code></pre> |
| |
| <p> |
| 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 |
| to allow this update to be combined with others within a single database |
| transaction. |
| </p> |
| |
| <p> |
| There are a few solutions to this problem. One would be to fix the torque |
| template responsible for generating the code. Another would be to implement |
| the methods yourself. Before exploring either of these options, you need to |
| ask yourself if this problem will even affect you. If not, don't worry about |
| it. |
| </p> |
| |
| <p> |
| Implementing the methods yourself might be the simpliest route for someone |
| new to Turbine and Torque. This simply involves overriding the addBook() |
| method in the example above with the two lines shown previously. Of course, |
| You would have to do this for each and every one that Torque generates |
| for you. |
| </p> |
| |
| <p> |
| The same idea applies to the save(dbConn) method. Simply override that method |
| in your ExtendedTurbineUser class (or whatever you called your class) to perform |
| the operation correctly. You can get sample code from one of the other classes |
| that Torque generated for you. |
| </p> |
| |
| <p> |
| If you want Torque to generate to code for you, you will have to modify the |
| Object.vm template that Torque uses. |
| </p> |
| |
| <p> |
| The other solution involves altering a torque template so that the code that |
| generates the aspects of the save() method that handle related tables is |
| allowed to execute for the TurbineUserAlias class. You need to apply the |
| following patch (most likely to the version of Object.vm copied to the |
| WEB-INF/build/bin/torque/templates/om directory for your application): |
| </p> |
| |
| <pre class="prettyprint"><code> |
| |
| Index: jakarta-turbine-2/conf/torque/templates/om/Object.vm |
| =================================================================== |
| RCS file: /home/cvspublic/jakarta-turbine-2/conf/torque/templates/om/Object.vm,v |
| |
| retrieving revision 1.3 |
| diff -u -r1.3 Object.vm |
| --- jakarta-turbine-2/conf/torque/templates/om/Object.vm 24 Oct 2001 18:1 |
| 2:21 -0000 1.3 |
| +++ jakarta-turbine-2/conf/torque/templates/om/Object.vm 16 Jan 2002 14:0 |
| 0:43 -0000 |
| @@ -787,7 +787,7 @@ |
| #end ## ends the if(addGetByNameMethod) |
| |
| |
| -#if (!$table.isAlias() && $addSaveMethod) |
| +#if ((!$table.isAlias() || $table.Alias == "TurbineUser") && $addSaveMethod) |
| /** |
| * Stores the object in the database. If the object is new, |
| * it inserts it; otherwise an update is performed. |
| @@ -880,6 +880,9 @@ |
| { |
| alreadyInSave = true; |
| #end |
| + #if ($table.isAlias() && $table.Alias == "TurbineUser") |
| + super.save(); |
| + #else |
| if (isModified()) |
| { |
| if (isNew()) |
| @@ -892,6 +895,7 @@ |
| ${table.JavaName}Peer.doUpdate(($table.JavaName)this, dbCon); |
| } |
| } |
| + #end |
| |
| #if ($complexObjectModel) |
| #foreach ($fk in $table.Referrers) |
| |
| </code></pre> |
| |
| <p> |
| You will need to manually remove the line wrapping from the above |
| patch. This patch is only included here to give you an idea of what |
| would need to be changed in Torque. The patch can not be applied |
| to the current version of Torque simply because it is so outdated. |
| </p> |
| |
| <p> |
| Notice how although you can go <code>user.save(dbCon);</code> the |
| TurbineUser record will not be part of the transaction. |
| </p> |
| |
| <p> |
| I would suggest that you override the methods that do not |
| get generated correctly in your ExtendedTurbineUser class. Do so ONLY |
| if this problem will affect you. |
| </p> |
| |
| <p> |
| The real solution to this problem is in modifing Turbine in such a way to |
| allow Torque to generate the TurbineUser object. This would eliminate the |
| need to extend TurbineUser altogether. There would still be the need to add |
| additional columns and/or create FK references to the TURBINE_USER table. It |
| would would only involve modifing the schema files and letting Torque do |
| all of the work instead of creating the adapter classes and modifing the |
| map builder. |
| </p> |
| |
| <p> |
| Note: The last solution mentioned should be ready for Turbine 2.3. This |
| should make life easier for everyone!!! |
| </p> |
| |
| </section> |
| |
| |
| </main> |
| </div> |
| </div> |
| <hr/> |
| <footer> |
| <div class="container-fluid"> |
| <div class="row-fluid"> |
| <p>© 2000–2025 |
| <a href="https://www.apache.org/">The Apache Software Foundation</a> |
| </p> |
| </div> |
| </div> |
| </footer> |
| </body> |
| </html> |