db-ojb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From arm...@apache.org
Subject cvs commit: db-ojb/forrest/src/documentation/content/xdocs/docu ojb-properties.xml otm-tutorial.xml pb-tutorial.xml
Date Fri, 23 Apr 2004 22:32:48 GMT
arminw      2004/04/23 15:32:48

  Added:       forrest/src/documentation/content/xdocs/docu
                        ojb-properties.xml otm-tutorial.xml pb-tutorial.xml
  Log:
  adapted docs
  
  Revision  Changes    Path
  1.1                  db-ojb/forrest/src/documentation/content/xdocs/docu/ojb-properties.xml
  
  Index: ojb-properties.xml
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  <!--
    Copyright 2002-2004 The Apache Software Foundation
  
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
  
        http://www.apache.org/licenses/LICENSE-2.0
  
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
  -->
  <!-- @version $Id: ojb-properties.xml,v 1.1 2004/04/23 22:32:48 arminw Exp $ -->
  <!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.2//EN" "document-v12.dtd">
  
  <document>
      <header>
          <title>OJB.properties Configuration File</title>
          <authors>
              <person name="Thomas Mahler" email="thma@apache.org"/>
              <person name="Armin Waibel" email="arminw@apache.org"/>
          </authors>
      </header>
  
      <body>
          <section>
              <title>OJB Configuration</title>
              <p>
                  OJB provides two different configuration
                  mechanisms:
              </p>
              <ol>
                  <li>
                      An XML based
                      <strong>
                          <code>repository.xml</code>
                      </strong> is used to
                      define the Object/Relational Mapping. This Mapping is translated
                      into a metadata dictionary at runtime. The metadata layer may also be
                      manipulated at runtime through OJB API calls.
                      <link href="site:repository">Follow
                          this link to learn more about the XML repository</link>.
                  </li>
                  <li>
                      A properties file
                      <link href="ext:ojb.properties">
                          <strong>
                              <code>OJB.properties</code>
                          </strong>
                      </link>
                      that is responsible for the configuration of the OJB runtime
                      environment. It contains information that does not
                      change at runtime and does not contain O/R mapping
                      related information.
                  </li>
              </ol>
              <p>
                  The rest of this document details on this properties file.
              </p>
          </section>
  
          <section>
              <title>OJB.properties File</title>
              <p>
                  By default this file is named
                  <strong>
                      <code>OJB.properties</code>
                  </strong> and is loaded from the
                  <strong>classpath</strong>
                  by a J2EE compliant resource lookup:
              </p>
              <source><![CDATA[
  Thread.currentThread().getContextClassLoader().getResource(getFilename());]]></source>
              <p>
                  The  filename of
                  the properties file can be changed by setting a Java system property.
                  This can be done programmatically:
              </p>
              <source><![CDATA[
  System.setProperty("OJB.properties","myOwnPropertiesFile.props");]]></source>
              <p>
                  or by setting a -D option to the JVM:
              </p>
              <source><![CDATA[
   java -DOJB.properties=myOwnPropertiesFile.props my.own.ojb.Application]]></source>
              <p>
                  All things that can be configured by OJB.properties are commented
                  in the file itself.
                  <link href="ext:ojb.properties">Have a look at the default version of this file</link>.
              </p>
          </section>
      </body>
  </document>
  
  
  
  
  
  
  
  
  
  1.1                  db-ojb/forrest/src/documentation/content/xdocs/docu/otm-tutorial.xml
  
  Index: otm-tutorial.xml
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  <!--
    Copyright 2002-2004 The Apache Software Foundation
  
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
  
        http://www.apache.org/licenses/LICENSE-2.0
  
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
  -->
  <!-- @version $Id: otm-tutorial.xml,v 1.1 2004/04/23 22:32:48 arminw Exp $ -->
  <!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.2//EN" "document-v12.dtd">
  
  <document>
      <header>
          <title>Object Transaction Manager Tutorial</title>
          <authors>
              <person name="Brian McCallister" email="brianm@apache.org"/>
          </authors>
      </header>
  
      <body>
          <section><title>The OTM API</title>
                      <section><title>Introduction</title>
                          <p>
                              The Object Transaction Manager (OTM) is written as a tool on
                              which to implement other high-level object persistence APIs. It
                              is, however, very usable directly. It supports API's similar to the
                              <link href="site:odmg-tutorial">ODMG</link> and
                              <link href="site:pb-tutorial">
                                  PersistenceBroker</link> API's in OJB. Several of its idioms are designed
                              around the fact that it is meant to have additional, client-oriented,
                              API's built on top of it, however.
                          </p>
                          <p>
                              The
                              <code>OTMKit</code> is the initial access point to the OTM interfaces.
                              The kit provides basic configuration information to the OTM components
                              used in your system. This tutorial will use the
                              <code>SimpleKit</code>
                              which will work well under most circumstances for local transaction
                              implementations.
                          </p>
                          <p>
                              This tutorial operates on a simple example class:
                          </p>
                          <source><![CDATA[
  package org.apache.ojb.tutorials;
  
  public class Product
  {
      /* Instance Properties */
  
      private Double price;
      private Integer stock;
      private String name;
  
      /* artificial property used as primary key */
  
      private Integer id;
  
      /* Getters and Setters */
      ...
  }]]></source>
                          <p>
                              The metadata descriptor for mapping this class is described in the
                              <link href="site:mapping-tutorial">mapping tutorial</link>.
                          </p>
                          <p>
                              The source code for this tutorial is available with the source distribution
                              of OJB in the
                              <code>src/test/org/apache/ojb/tutorials/</code> directory.
                          </p>
                      </section>
  
  
                      <section><title>Persisting New Objects</title>
                          <p>
                              The starting point for using the OTM directly is to look at
                              making a transient object persistent. This code will use three
                              things, an
                              <code>OTMKit</code>, an
                              <code>OTMConnection</code>,
                              and a
                              <code>Transaction</code>. The connection and transaction
                              objects are obtained from the kit.
                          </p>
                          <p>
                              Initial access to the OTM client API's is through the
                              <code>OTMKit</code>
                              interface. We'll use the
                              <code>SimpleKit</code>, an implementation of the
                              <code>OTMkit</code> suitable for most circumstances using local transactions.
                          </p>
                          <source><![CDATA[
  public static void storeProduct(Product product) throws LockingException
  {
      OTMKit kit = SimpleKit.getInstance();
      OTMConnection conn = null;
      Transaction tx = null;
      try
      {
          conn = kit.acquireConnection(PersistenceBrokerFactory.getDefaultKey());
          tx = kit.getTransaction(conn);
          tx.begin();
          conn.makePersistent(product);
          tx.commit();
      }
      catch (LockingException e)
      {
          if (tx.isInProgress()) tx.rollback();
          throw e;
      }
      finally
      {
          conn.close();
      }
  }
          ]]></source>
                          <p>
                              A kit is obtained and is used to obtain a connection. Connections are against
                              a specific JCD alias. In this case we use the default, but a named
                              datasource could also be used, as configured in the metadata repository. A transaction
                              is obtained from the kit for the specific connection. Because multiple
                              connections can be bound to the same transaction in the OTM, the transaction
                              needs to be acquired from the kit instead of the connection itself. The
                              <code>SimpleKit</code> uses the commonly seen transaction-per-thread idiom, but
                              other kits do not need to do this.
                          </p>
                          <p>
                              Every persistence operation within the OTM needs to be executed within
                              the context of a transaction. The JDBC concept of implicit transactions
                              doesn't exist in the OTM -- transactions must be explicit.
                          </p>
                          <p>
                              Locks, on the other hand, are implicit in the OTM (though explicit locks
                              are available).
                              The
                              <code>conn.makePersistent(..)</code> call obtains a write lock on
                              <code>product</code> and will commit (insert) the object when the transaction
                              is committed.
                          </p>
                          <p>
                              The
                              <code>LockingException</code> will be thrown if the object cannot be
                              write-locked in this transaction. As it is a transient object to begin
                              with, this will probably only ever happen if it has been write-locked
                              in another transaction already -- but this depends on the transaction
                              semantics configured in the repository metadata.
                          </p>
                          <p>
                              Finally, connections maintain resources so it is important to make
                              sure they are closed when no longer needed.
                          </p>
                      </section>
  
  
                      <section><title>Deleting Persistent Objects</title>
                          <p>
                              Deleting a persistent object from the backing store (making
                              a persistent object transient) is almost identical to
                              making it persistent -- the difference is just in the
                              <code>conn.deletePersistent(product)</code> call instead of the
                              <code>conn.makePersistent(product)</code> call. The same notes
                              about transactions and resources apply here.
                          </p>
                          <source><![CDATA[
  public static void storeProduct(Product product) throws LockingException
  {
     OTMKit kit = SimpleKit.getInstance();
     OTMConnection conn = null;
     Transaction tx = null;
     try
     {
         conn = kit.acquireConnection(PersistenceBrokerFactory.getDefaultKey());
         tx = kit.getTransaction(conn);
         tx.begin();
         conn.deletePersistent(product);
         tx.commit();
     }
     catch (LockingException e)
     {
         if (tx.isInProgress()) tx.rollback();
         throw e;
     }
     finally
     {
         conn.close();
     }
  }
         ]]></source>
                      </section>
  
  
                      <section><title>Querying for Objects</title>
                          <p>
                              The OTM implements a transaction system, not a new client API. As such
                              it supports two styles of query at present -- an PersistenceBroker like
                              query-by-criteria style querying system, and an ODMG OQL query system.
                          </p>
                          <p>
                              Information on constructing these types of queries is available in the
                              <link href="site:pb-tutorial">PersistenceBroker</link> and
                              <link href="site:odmg-tutorial">ODMG</link> tutorials respectively. Using
                              those queries with the OTM is examined here.
                          </p>
                          <p>
                              A PB style query can be handled as follows:
                          </p>
                          <source><![CDATA[
  public Iterator findByCriteria(Query query)
  {
      OTMKit kit = SimpleKit.getInstance();
      OTMConnection conn = null;
      Transaction tx = null;
      try
      {
          conn = kit.acquireConnection(PersistenceBrokerFactory.getDefaultKey());
          tx = kit.getTransaction(conn);
          tx.begin();
          Iterator results = conn.getIteratorByQuery(query);
          tx.commit();
          return results;
      }
      finally
      {
          conn.close();
      }
  }]]></source>
                          <p>
                              Where, by default, a read lock is obtained on the returned objects.
                              If a different lock is required it may be specified specifically:
                          </p>
                          <source><![CDATA[
  public Iterator findByCriteriaWithLock(Query query, int lock)
  {
      OTMKit kit = SimpleKit.getInstance();
      OTMConnection conn = null;
      Transaction tx = null;
      try
      {
          conn = kit.acquireConnection(PersistenceBrokerFactory.getDefaultKey());
          tx = kit.getTransaction(conn);
          tx.begin();
          Iterator results = conn.getIteratorByQuery(query, lock);
          tx.commit();
          return results;
      }
      finally
      {
          conn.close();
      }
  }]]></source>
                          <p>
                              The int
                              <code>lock</code> argument is one of the integer constants on
                              <code>org.apache.ojb.otm.lock.LockType</code>:
                          </p>
                          <source><![CDATA[
  LockType.NO_LOCK
  LockType.READ_LOCK
  LockType.WRITE_LOCK]]></source>
                          <p>
                              OQL queries are also supported, as this somewhat more complex
                              example demonstrates:
                          </p>
                          <source><![CDATA[
  public Iterator findByOQL(String query, Object[] bindings) throws Exception
  {
      OTMKit kit = SimpleKit.getInstance();
      OTMConnection conn = null;
      Transaction tx = null;
      try
      {
          conn = kit.acquireConnection(PersistenceBrokerFactory.getDefaultKey());
          tx = kit.getTransaction(conn);
          OQLQuery oql = conn.newOQLQuery();
          oql.create(query);
          for (int i = 0; i < bindings.length; ++i)
          {
              oql.bind(bindings[i]);
          }
          tx.begin();
          Iterator results = conn.getIteratorByOQLQuery(oql);
          tx.commit();
          return results;
      }
      catch (QueryInvalidException e)
      {
          if (tx.isInProgress()) tx.rollback();
          throw new Exception("Invalid OQL expression given", e);
      }
      catch (QueryParameterCountInvalidException e)
      {
          if (tx.isInProgress()) tx.rollback();
          throw new Exception("Incorrect number of bindings given", e);
      }
      catch (QueryParameterTypeInvalidException e)
      {
          if (tx.isInProgress()) tx.rollback();
          throw new Exception("Incorrect type of object given as binding", e);
      }
      finally
      {
          conn.close();
      }
  }]]></source>
                          <p>
                              This function is, at its core, doing the same thing as the PB style
                              queries, except that it constructs the OQL query, which supports
                              binding values in a manner similar to JDBC prepared statements.
                          </p>
                          <p>
                              The OQL style queries also support specifying the lock level the same way:
                          </p>
                          <source><![CDATA[
  Iterator results = conn.getIteratorByOQLQuery(query, lock);]]></source>
                      </section>
  
  
                      <section><title>More Sophisticated Transaction Handling</title>
                          <p>
                              These examples are a bit simplistic as they begin and commit their
                              transactions all in one go -- they are only good for retrieving data.
                              More often data will need to be retrieved, used, and committed back.
                          </p>
                          <p>
                              Only changes to persistent objects made within the bounds of a
                              transaction are persisted. This means that frequently a query will
                              be executed within the bounds of an already established transaction,
                              data will be changed on the objects obtained, and the transaction will then
                              be committed back.
                          </p>
                          <p>
                              A very convenient way to handle transactions in many applications
                              is to start a transaction and then let any downstream code be executed
                              within the bounds of the transaction automatically. This is straightforward
                              to do with the OTM using the
                              <code>SimpleKit</code>! Take a look at a very slightly modified version
                              of the query by criteria function:
                          </p>
                          <source><![CDATA[
  public Iterator moreRealisticQueryByCriteria(Query query, int lock)
  {
       OTMKit kit = SimpleKit.getInstance();
       OTMConnection conn = null;
       Transaction tx = null;
       try
       {
           conn = kit.acquireConnection(PersistenceBrokerFactory.getDefaultKey());
           tx = kit.getTransaction(conn);
           boolean auto = ! tx.isInProgress();
           if (auto) tx.begin();
           Iterator results = conn.getIteratorByQuery(query, lock);
           if (auto) tx.commit();
           return results;
       }
       finally
       {
           conn.close();
       }
  }]]></source>
                          <p>
                              In this case the function looks to see if a transaction is already in
                              progress and sets a boolean flag if it is, <code>auto</code>. It then
                              handles transactions itself, or allows the already opened transaction
                              to maintain control.
                          </p>
                          <p>
                              Because connections can be attached to existing transactions the
                              <code>SimpleKit</code> can attach the new connection to the
                              already established transaction, allowing this function to work
                              as expected whether there is a transaction in progress or not!
                          </p>
                          <p>
                              Client code using this function could then open a transaction,
                              query for products, change them, and commit the changes back. For
                              example:
                          </p>
                          <source><![CDATA[
  public void renameWidgetExample()
  {
      OTMKit kit = SimpleKit.getInstance();
      OTMConnection conn = null;
      Transaction tx = null;
      try
      {
          conn = kit.acquireConnection(PersistenceBrokerFactory.getDefaultKey());
          tx = kit.getTransaction(conn);
          tx.begin();
          Product sample = new Product();
          sample.setName("Wonder Widget");
          Query query = QueryFactory.newQueryByExample(sample);
          Iterator wonderWidgets
                      = moreRealisticQueryByCriteria(query, LockType.WRITE_LOCK);
          while (wonderWidgets.hasNext())
          {
              Product widget = (Product) wonderWidgets.next();
              widget.setName("Improved Wonder Widget");
          }
          tx.commit();
      }
      finally
      {
          conn.close();
      }
  }]]></source>
                          <p>
                              This sample renames a whole bunch of products from "Wonder Widget" to
                              "Improved Wonder Widget" and stores them back. It must makes the changes
                              within the context of the transaction it obtained for those changes
                              to be stored back to the database. If the same iterator were obtained
                              outside of a transaction, and the changes made, the changes would be
                              made on the objects in memory, but not in the database. You can think of
                              non-transaction objects as free immutable transfer objects.
                          </p>
                          <p>
                              This example also demonstrates two connections bound to the same
                              transaction, as the <code>renameWidgetExample(...)</code> function
                              obtains a connection, and the <code>moreRealisticQueryByCriteria(...)</code>
                              function obtains an additional connection to the same transaction!
                          </p>
                      </section>
                  </section>
  
  
                  <section><title>Notes on the Object Transaction Manager</title>
  
                      <section><title>Transactions</title>
                          <p>
                              The Object Transaction Manager (OTM) is a transaction management layer for
                              Java objects. It typically maps 1:1 to database transactions behind the scenes,
                              but this is not actually required for the OTM to work correctly.
                          </p>
                          <p>
                              The OTM supports a wide range of transactional options, delimited in the
                              <link href="site:lock-manager">LockManager</link> documentation. While the lock
                              manager is writte to the ODMG API, the same locking rules apply at the
                              OTM layer.
                          </p>
                      </section>
                  </section>
      </body>
  </document>
  
  
  
  1.1                  db-ojb/forrest/src/documentation/content/xdocs/docu/pb-tutorial.xml
  
  Index: pb-tutorial.xml
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  <!--
    Copyright 2002-2004 The Apache Software Foundation
  
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
  
        http://www.apache.org/licenses/LICENSE-2.0
  
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
  -->
  <!-- @version $Id: pb-tutorial.xml,v 1.1 2004/04/23 22:32:48 arminw Exp $ -->
  <!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.2//EN" "document-v12.dtd">
  
  <document>
      <header>
          <title>Persistence Broker Tutorial</title>
          <authors>
              <person name="Brian McCallister" email="brian@skife.org"/>
          </authors>
      </header>
  
      <body>
          <section>
              <title>The PersistenceBroker API</title>
              <section>
                  <title>Introduction</title>
                  <p>
                      The PersistenceBroker API provides the lowest level access to OJB's persistence engine.
                      While it is a low-level API compared to the OTM, ODMG, or JDO API's it is still very
                      straightforward to use.
                  </p>
                  <p>
                      The core class in the PersistenceBroker API is the
                      <code>org.apache.ojb.broker.PersistenceBroker</code> class. This class provides the
                      point of access for all persistence operations in this API.
                  </p>
                  <p>
                      This tutorial operates on a simple example class:
                  </p>
                  <source><![CDATA[
  package org.apache.ojb.tutorials;
  
  public class Product
  {
      /* Instance Properties */
  
      private Double price;
      private Integer stock;
      private String name;lean
  
      /* artificial property used as primary key */
  
      private Integer id;
  
      /* Getters and Setters */
      ...
  }]]></source>
                  <p>
                      The metadata descriptor for mapping this class is described in the
                      <link href="site:mapping-tutorial">mapping tutorial</link>
                  </p>
                  <p>
                      The source code for this tutorial is available with the source distribution
                      of OJB in the
                      <link href="ext:PBExamples">
                          <code>src/test/org/apache/ojb/tutorials/</code>
                      </link> directory.
                  </p>
              </section>
  
  
              <section>
                  <title>A First Look - Persisting New Objects</title>
                  <p>
                      The most basic operation is to persist an object. This is handled very easily
                      by just
                      </p>
                      <ol>
                          <li>obtaining a <code>PersistenceBroker</code></li>
                          <li>begin the PB-transaction</li>
                          <li>storing the object via the <code>PersistenceBroker</code></li>
                          <li>commit transaction</li>
                          <li>closing the <code>PersistenceBroker</code></li>
                      </ol>
                      <p>
                          For example, the following function stores
                      a single object of type
                      <code>Product</code>.
                  </p>
                  <source><![CDATA[
  public static void storeProduct(Product product)
  {
      PersistenceBroker broker = null;
      try
      {
          broker = PersistenceBrokerFactory.defaultPersistenceBroker();
          broker.beginTransaction();
          broker.store(product);
          broker.commitTransaction();
      }
      catch(PersistenceBrokerException e)
      {
          if(broker != null) broker.abortTransaction();
          // do more exception handling
      }
      finally
      {
          if (broker != null) broker.close();
      }
  }]]></source>
                  <p>
                      Two OJB classes are used here, the
                      <code>PersistenceBrokerFactory</code> and
                      the
                      <code>PersistenceBroker</code>. The
                      <code>PersistenceBrokerFactory</code>
                      class manages the lifecycles of
                      <code>PersistenceBroker</code> instances: it creates them,
                      pools them, and destroys them as needed. The exact behavior is very configurable.
                  </p>
                  <p>
                      In this case we used the static
                      <code>PersistenceBrokerFactory.defaultPersistenceBroker()</code> method to obtain an
                      instance of a
                      <code>PersistenceBroker</code> to the default data source. This is most
                      often how it is used if there is only one database for an application. If there
                      are multiple data sources, a broker may be obtained by name.
                  </p>
                  <p>
                      It is worth noting that the
                      <code>broker.close()</code> call is made within a
                      <code>finally {...}</code> block. This ensures that the broker will be closed,
                      and returned to the broker pool, even if the function throws an exception.
                  </p>
                  <p>
                      To use this function, we just create a
                      <code>Product</code> and pass it
                      to the function:
                  </p>
                  <source><![CDATA[
  Product product = new Product();
  product.setName("Sprocket");
  product.setPrice(1.99);
  product.setStock(10);
  storeProduct(product);]]></source>
                  <p>
                      Once a
                      <code>PersistenceBroker</code> has been obtained, its
                      <code>PersistenceBroker.store(Object)</code> method is used to make an object
                      persistent. If several objects need to be stored, this can be done within
                      a transaction, as follows.
                  </p>
                  <source><![CDATA[
  public static void storeProducts(Product[] products)
  {
      PersistenceBroker broker = null;
      try
      {
          broker = PersistenceBrokerFactory.defaultPersistenceBroker();
          broker.beginTransaction();
          for (int i = 0; i < products.length; i++)
          {
              broker.store(products[i]);
          }
          broker.commitTransaction();
      }
      catch(PersistenceBrokerException e)
      {
          if(broker != null) broker.abortTransaction();
          // do more exception handling
      }
      finally
      {
          if (broker != null) broker.close();
      }
  }]]></source>
                  <p>
                      This contrived example stores all of the passed Product instances within
                      a single transaction via the
                      <code>PersistenceBroker.beginTransaction()</code>
                      and
                      <code>PersistenceBroker.commitTransaction()</code>. These are database
                      level transactions, not object level transactions.
                  </p>
              </section>
  
  
              <section>
                  <title>Querying Persistent Objects</title>
                  <p>
                      Once objects have been stored to the database, it is important to be able to get them
                      back. The PersistenceBroker API provides two mechanisms for building queries, by
                      using a template object, or by using specific criteria.
                  </p>
                  <source><![CDATA[
  public static Product findByTemplate(Product template)
  {
      PersistenceBroker broker = null;
      Product result = null;
      try
      {
          broker = PersistenceBrokerFactory.defaultPersistenceBroker();
          QueryByCriteria query = new QueryByCriteria(template);
          result = (Product) broker.getObjectByQuery(query);
      }
      finally
      {
          if (broker != null) broker.close();
      }
      return result;
  }]]></source>
                  <p>
                      This function finds a
                      <code>Product</code> by building a query against a template
                      <code>Product</code>. The template should have any properties set which should
                      be matched by the query. Building on the previous example where a product
                      was stored, we can now query for that same product:
                  </p>
                  <source><![CDATA[
  Product product = new Product();
  product.setName("Sprocket");
  product.setPrice(new Double(1.99));
  product.setStock(new Integer(10));
  storeProduct(product);
  
  Product template = new Product();
  template.setName("Sprocket");
  Product sameProduct = findByTemplate(template);]]></source>
                  <p>
                      In the above code snippet,
                      <code>product</code> and
                      <code>sameProduct</code>
                      will reference the same object (assuming there are no additional products in the
                      database with the name "Sprocket").
                  </p>
                  <p>
                      The template
                      <code>Product</code> has only one of its properties set, the
                      <code>name</code> property. The others are all null. Properties with null values
                      are not used to match.
                  </p>
                  <p>
                      An alternate, and more flexible, way to have specified a query via the
                      PersistenceBroker API is by constructing the criteria on the query
                      by hand. The following function does this.
                  </p>
                  <source><![CDATA[
  public static Collection getExpensiveLowStockProducts()
  {
      PersistenceBroker broker = null;
      Collection results = null;
      try
      {
          broker = PersistenceBrokerFactory.defaultPersistenceBroker();
  
          Criteria criteria = new Criteria();
          criteria.addLessOrEqualThan("stock", new Integer(20));
          criteria.addGreaterOrEqualThan("price", new Double(100000.0));
  
          QueryByCriteria query = new QueryByCriteria(Product.class, criteria);
          results = broker.getCollectionByQuery(query);
      }
      finally
      {
          if (broker != null) broker.close();
      }
      return results;
  }]]></source>
                  <p>
                      This function builds a
                      <code>Criteria</code> object and uses it to set more complex
                      query parameters - in this case greater-than and less-than contraints. Looking at the
                      first constraint put on the criteria,
                      <code>criteria.addLessOrEqualThan("stock", new Integer(10));</code> notice the arguments.
                      The first is the property name on the object being queried for. The second is an
                      <code>Integer</code> instance to be used for the comparison.
                  </p>
                  <p>
                      After the
                      <code>Criteria</code> has been built, the
                      <code>QueryByCriteria</code> constructor
                      used is also different from the previous example. In this case the criteria does not know
                      the type of the object it is being used against, so the
                      <code>Class</code> must be specified
                      to the query.
                  </p>
                  <p>
                      Finally, notice that this example uses the
                      <code>PersistenceBroker.getCollectionByQuery(...)</code>
                      method instead of the
                      <code>PersistenceBroker.getObjectByQuery(...)</code> method used
                      previously. This is used because we want all of the results. Either form can be used
                      with either method of constructing queries. In the case of the
                      <code>PersistenceBroker.getObjectByQuery(...)</code> style query, the first matching
                      object is returned, even if there are multiple matching objects.
                  </p>
              </section>
  
  
              <section>
                  <title>Updating Persistent Objects</title>
                  <p>
                      The same mechanism, and method, is used for updating persistent objects as for inserting
                      persistent objects. The same
                      <code>PersistenceBroker.store(Object)</code> method
                      is used to store a modified object as to insert a new one - the difference
                      between new and modified objects is irrelevent to OJB.
                  </p>
                  <p>
                      This can cause some confusion for people who are very used to working in the
                      stricter confines of SQL inserts and updates. Basically, OJB will insert a new
                      object into the relational store if the primary key, as specified in the
                      O/R metadata is not in use. If it is in use, it will update the existing
                      object rather than create a new one.
                  </p>
                  <p>
                      This allows programmers to treat every object the same way in an object
                      model, whether it has been newly created and made persistent, or materialized
                      from the database.
                  </p>
                  <p>
                      Typically, making changes to a peristent object first requires retrieving a reference
                      to the object, so the typical update cycle, unless the application caches objects,
                      is to query for the object to modify, modify the object, and then store the object.
                      The following function demonstrates this behavior by "selling" a Product.
                  </p>
                  <source><![CDATA[
  public static boolean sellOneProduct(Product template)
  {
      PersistenceBroker broker = null;
      boolean isSold = false;
      try
      {
          broker = PersistenceBrokerFactory.defaultPersistenceBroker();
          QueryByCriteria query = new QueryByCriteria(template);
          Product result = (Product) broker.getObjectByQuery(query);
  
          if (result != null)
          {
              broker.beginTransaction();
              result.setStock(new Integer(result.getStock().intValue() - 1));
              broker.store(result);
              // alternative, more performant
              // broker.store(result, ObjectModificationDefaultImpl.UPDATE);
              broker.commitTransaction();
              isSold = true;
          }
      }
      catch(PersistenceBrokerException e)
      {
          if(broker != null) broker.abortTransaction();
          // do more exception handling
      }
      finally
      {
          if (broker != null) broker.close();
      }
      return isSold;
  }]]></source>
                  <p>
                      This function uses the same query-by-template and
                      <code>PersistenceBroker.store()</code>
                      API's examined previously, but it uses the store method to store changes to the object
                      it retrieved. It is worth noting that the entire operation took place within a transaction.
                  </p>
              </section>
  
  
              <section>
                  <title>Deleting Persistent Objects</title>
                  <p>
                      Deleting persistent objects from the repository is accomplished via
                      the
                      <code>PersistenceBroker.delete()</code> method. This removes the
                      persistent object from the repository, but does not affect any change
                      on the object itself. For example:
                  </p>
                  <source><![CDATA[
  public static void deleteProduct(Product product)
  {
      PersistenceBroker broker = null;
      try
      {
          broker = PersistenceBrokerFactory.defaultPersistenceBroker();
          broker.beginTransaction();
          broker.delete(product);
          broker.commitTransaction();
      }
      catch(PersistenceBrokerException e)
      {
          if(broker != null) broker.abortTransaction();
          // do more exception handling
      }
      finally
      {
          if (broker != null) broker.close();
      }
  }]]></source>
                  <p>
                      This method simply deletes an object from the database.
                  </p>
              </section>
          </section>
  
  
          <section>
              <title>Notes on Using the PersistenceBroker API</title>
              <section>
                  <title>Pooling PersistenceBrokers</title>
                  <p>
                      The
                      <code>PersistenceBrokerFactory</code> pools
                      <code>PersistenceBroker</code>
                      instances. Using the
                      <code>PersistenceBroker.close()</code> method releases
                      the broker back to the pool under the default implementation. For this reason
                      the examples in this tutorial all retrieve, use, and close a new broker
                      for each logical transaction.
                  </p>
              </section>
  
              <section>
                  <title>Transactions</title>
                  <p>
                      Transactions in the PeristenceBroker API are database level transactions.
                      This differs from object level transactions. The broker does not maintain
                      a collection of modified, created, or deleted objects until a commit is called --
                      it operates on the database using the databases transaction mechanism. If object
                      level transactions are required, one ofthe higher level API's (ODMG, JDO, or OTM)
                      should be used.
                  </p>
              </section>
  
              <section>
                  <title>Exception Handling</title>
                  <p>
                      Most
                      <code>PersistenceBroker</code> operations throw a
                      <code>org.apache.ojb.broker.PersistenceBrokerException</code>, which is derived from
                      <code>java.lang.RuntimeException</code> if an error occurs. This means that no try/catch
                      block is
                      <strong>required</strong> but does not mean that it should not be used. This tutorial
                      specifically does not catch exceptions all in order to focus more tightly on the
                      specifics of the API, however, best usage would be to include a try/catch/finally
                      block around persistence operations using the PeristenceBroker API.
                  </p>
                  <p>
                      Additionally, the closing of
                      <code>PersistenceBroker</code> instances is best
                      handled in
                      <code>finally</code> blocks in order to guarantee that it is run,
                      even if an exception occurs. If the
                      <code>PersistenceBroker.close()</code> is not
                      called then the application will leak broker instances. The best way to ensure that
                      it is always called is to always retrieve and use
                      <code>PersistenceBroker</code>
                      instances within a
                      <code>try {...}</code> block, and always close the broker
                      in a
                      <code>finally {...}</code> block attached to the
                      <code>try {...}</code> block.
                  </p>
                  <p>
                      A better designed
                      <code>getExpensiveLowStockProducts()</code> method is presented
                      here.
                  </p>
                  <source><![CDATA[
  public static Collection betterGetExpensiveLowStockProducts()
  {
      PersistenceBroker broker = null;
      Collection results = null;
      try
      {
          broker = PersistenceBrokerFactory.defaultPersistenceBroker();
  
          Criteria criteria = new Criteria();
          criteria.addLessOrEqualThan("stock", new Integer(20));
          criteria.addGreaterOrEqualThan("price", new Double(100000.0));
  
          QueryByCriteria query = new QueryByCriteria(Product.class, criteria);
          results = broker.getCollectionByQuery(query);
      }
      catch (PersistenceBrokerException e)
      {
          // Handle exception
      }
      finally
      {
          if (broker != null) broker.close();
      }
      return results;
  }]]></source>
                  <p>
                      Notice first that the
                      <code>PersistenceBroker</code> is retrieved and used
                      within the confines of a
                      <code>try {...}</code> block. Assuming nothing goes wrong
                      the entire operation will execute there, all the way to the
                      <code>return results;</code>
                      line. Java guarantees that
                      <code>finally {...}</code> blocks will be called before a
                      method returns, so the
                      <code>broker.close()</code> method is only included once, in the
                      <code>finally</code> block. As an exception may have occured while attempting to
                      retrieve the broker, a not-null test is first performed before closing the broker.
                  </p>
              </section>
          </section>
      </body>
  </document>
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org


Mime
View raw message