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/src/test/org/apache/ojb/tutorials Product.java PBExample.java
Date Tue, 19 Aug 2003 15:35:57 GMT
arminw      2003/08/19 08:35:57

  Modified:    src/test/org/apache/ojb repository_user.xml
  Added:       xdocs    pb-tutorial.xml
               src/test/org/apache/ojb/tutorials Product.java
                        PBExample.java
  Log:
  add first version of new PB-api tutorial
  by Brain McCallister
  
  Revision  Changes    Path
  1.1                  db-ojb/xdocs/pb-tutorial.xml
  
  Index: pb-tutorial.xml
  ===================================================================
  <?xml version="1.0"?>
  <!-- @version $Id: pb-tutorial.xml,v 1.1 2003/08/19 15:35:57 arminw Exp $ -->
  <document>
      <properties>
          <author email="brian@skife.org">Brian McCallister</author>
          <title>ObJectRelationalBridge Tutorial - PersistenceBroker</title>
      </properties>
      <body>
          <section name="The PersistenceBroker API">
              <subsection name="Introduction">
                  <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;
  
      /* 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
                      XXXmetadata tutorialXXX.
                  </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>
              </subsection>
              <subsection name="A First Look - Persisting New Objects">
                  <p>
                      The most basic operation is to persist an object. This is handled very
easily
                      by just (1) obtaining a <code>PersistenceBroker</code>,
(2) storing the object
                      via the <code>PersistenceBroker</code>, and (3) closing
the
                      <code>PersistenceBroker</code>. 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.store(product);
          }
          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();
          }
          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>
              </subsection>
              <subsection name="Querying Persistent Objects">
                  <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;
          try
          {
              broker = PersistenceBrokerFactory.defaultPersistenceBroker();
              QueryByCriteria query = new QueryByCriteria(template);
              Product result = (Product) broker.getObjectByQuery(query);
              return result;
          }
          finally
          {
              if (broker != null) broker.close();
          }
      }
                  ]]></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;
          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);
              Collection results = broker.getCollectionByQuery(query);
  
              return results;
          }
          finally
          {
              if (broker != null) broker.close();
          }
      }
                  ]]></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>
              </subsection>
              <subsection name="Updating Persistent Objects">
                  <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;
          try
          {
              broker = PersistenceBrokerFactory.defaultPersistenceBroker();
              QueryByCriteria query = new QueryByCriteria(template);
  
              broker.beginTransaction();
              Product result = (Product) broker.getObjectByQuery(query);
              if (result == null) return false; // No product matched template
  
              result.setStock(new Integer(result.getStock().intValue() - 1));
              broker.store(result);
  
              broker.commitTransaction();
              return true;
          }
          finally
          {
              if (broker != null) broker.close();
          }
      }
                  ]]></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>
              </subsection>
              <subsection name="Deleting Persistent Objects">
                  <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
          {
              PersistenceBrokerFactory.defaultPersistenceBroker();
              broker.delete(product);
          }
          finally
          {
              if (broker != null) broker.close();
          }
      }
                  ]]></source>
                  <p>
                      This method simply deletes an object from the database.
                  </p>
              </subsection>
          </section>
          <section name="Notes on Using the PersistenceBroker API">
              <subsection name="Pooling PersistenceBrokers">
                  <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>
              </subsection>
              <subsection name="Transactions">
                  <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>
              </subsection>
              <subsection name="Exception Handling">
                  <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 <b>required</b> but does not mean that it should
not be used. This tutorial
                      specifically does not catch exceptions in order to focus more tightly
on the
                      specifics of the API, however, better usage would be to include a try/catch
                      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 lean 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;
          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);
              Collection results = broker.getCollectionByQuery(query);
  
              return results;
          }
          catch (PersistenceBrokerException e)
          {
              // Handle exception
          }
          finally
          {
              if (broker != null) broker.close();
          }
          return null;
      }
                  ]]></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>
              </subsection>
          </section>
      </body>
  </document>
  
  
  1.6       +27 -0     db-ojb/src/test/org/apache/ojb/repository_user.xml
  
  Index: repository_user.xml
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/test/org/apache/ojb/repository_user.xml,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- repository_user.xml	10 Feb 2003 18:15:05 -0000	1.5
  +++ repository_user.xml	19 Aug 2003 15:35:57 -0000	1.6
  @@ -64,5 +64,32 @@
         />
      </class-descriptor>
   
  +   <class-descriptor
  +   	  class="org.apache.ojb.tutorials.Product"
  +   	  table="PRODUCT"
  +   >
  +      <field-descriptor
  +         name="id"
  +         column="ID"
  +         jdbc-type="INTEGER"
  +         primarykey="true"
  +         autoincrement="true"
  +      />
  +      <field-descriptor
  +         name="name"
  +         column="NAME"
  +         jdbc-type="VARCHAR"
  +      />
  +      <field-descriptor
  +         name="price"
  +         column="PRICE"
  +         jdbc-type="DOUBLE"
  +      />
  +      <field-descriptor
  +         name="stock"
  +         column="STOCK"
  +         jdbc-type="INTEGER"
  +      />
  +   </class-descriptor>
   
   <!-- Mapping of User defined classes ends here -->
  
  
  
  1.1                  db-ojb/src/test/org/apache/ojb/tutorials/Product.java
  
  Index: Product.java
  ===================================================================
  package org.apache.ojb.tutorials;
  
  /**
   * represents product objects in the tutorial system
   */
  public class Product
  {
  
      /** price per item*/
      private Double price;
  
      /** stock of currently available items*/
      private Integer stock;
  
      /** product name*/
      private String name;
  
      /**artificial primary key atribute*/
      private Integer id;
  
      /**
       * Insert the method's description here.
       * @return int
       */
      public Integer getId()
      {
          return id;
      }
  
      /**
       * Insert the method's description here.
       * @return java.lang.String
       */
      public String getName()
      {
          return name;
      }
  
      /**
       * Insert the method's description here.
       * @return double
       */
      public Double getPrice()
      {
          return price;
      }
  
      /**
       * Insert the method's description here.
       * @return int
       */
      public Integer getStock()
      {
          return stock;
      }
  
      /**
       * Insert the method's description here.
       * @param new_id int
       */
      public void setId(Integer new_id)
      {
          id = new_id;
      }
  
      /**
       * Insert the method's description here.
       * @param newName java.lang.String
       */
      public void setName(String newName)
      {
          name = newName;
      }
  
      /**
       * Insert the method's description here.
       * @param newPrice double
       */
      public void setPrice(Double newPrice)
      {
          price = newPrice;
      }
  
      /**
       * Insert the method's description here.
       * @param newStock int
       */
      public void setStock(Integer newStock)
      {
          stock = newStock;
      }
  
      public String toString()
      {
          return "[" + id + "] " + name + "\t\t\t price: " + price + "\t\t stock: " + stock;
      }
  }
  
  
  
  1.1                  db-ojb/src/test/org/apache/ojb/tutorials/PBExample.java
  
  Index: PBExample.java
  ===================================================================
  package org.apache.ojb.tutorials;
  
  import org.apache.ojb.broker.PersistenceBroker;
  import org.apache.ojb.broker.PersistenceBrokerFactory;
  import org.apache.ojb.broker.PersistenceBrokerException;
  import org.apache.ojb.broker.query.QueryByCriteria;
  import org.apache.ojb.broker.query.Criteria;
  
  import java.util.Collection;
  
  /**
   * PB-api usage examples.
   *
   * @version $Id: PBExample.java,v 1.1 2003/08/19 15:35:57 arminw Exp $
   */
  public class PBExample
  {
  
      public static void storeProduct(Product product)
      {
          PersistenceBroker broker = null;
          try
          {
              broker = PersistenceBrokerFactory.defaultPersistenceBroker();
              broker.store(product);
          }
          finally
          {
              if (broker != null) broker.close();
          }
      }
  
      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();
          }
          finally
          {
              if (broker != null) broker.close();
          }
      }
  
      public static Product findByTemplate(Product template)
      {
          PersistenceBroker broker = null;
          try
          {
              broker = PersistenceBrokerFactory.defaultPersistenceBroker();
              QueryByCriteria query = new QueryByCriteria(template);
              Product result = (Product) broker.getObjectByQuery(query);
              return result;
          }
          finally
          {
              if (broker != null) broker.close();
          }
      }
  
      public static Collection getExpensiveLowStockProducts()
      {
          PersistenceBroker broker = 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);
              Collection results = broker.getCollectionByQuery(query);
  
              return results;
          }
          finally
          {
              if (broker != null) broker.close();
          }
      }
  
      public static Collection betterGetExpensiveLowStockProducts()
      {
          PersistenceBroker broker = 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);
              Collection results = broker.getCollectionByQuery(query);
  
              return results;
          }
          catch (PersistenceBrokerException e)
          {
              // Handle exception
          }
          finally
          {
              if (broker != null) broker.close();
          }
          return null;
      }
  
      public static boolean sellOneProduct(Product template)
      {
          PersistenceBroker broker = null;
          try
          {
              broker = PersistenceBrokerFactory.defaultPersistenceBroker();
              QueryByCriteria query = new QueryByCriteria(template);
  
              broker.beginTransaction();
              Product result = (Product) broker.getObjectByQuery(query);
              if (result == null) return false; // No product matched template
  
              result.setStock(new Integer(result.getStock().intValue() - 1));
              broker.store(result);
  
              broker.commitTransaction();
              return true;
          }
          finally
          {
              if (broker != null) broker.close();
          }
      }
  
      public static boolean findAndDeleteProduct(Product template)
      {
          PersistenceBroker broker = null;
          try
          {
              broker = PersistenceBrokerFactory.defaultPersistenceBroker();
  
              QueryByCriteria query = new QueryByCriteria(template);
  
              broker.beginTransaction();
              Product result = (Product) broker.getObjectByQuery(query);
              if (result == null) return false; // No product matched template
  
              broker.delete(result);
  
              broker.commitTransaction();
              return true;
          }
          finally
          {
              if (broker != null) broker.close();
          }
      }
  
      public static void deleteProduct(Product product)
      {
          PersistenceBroker broker = null;
          try
          {
              PersistenceBrokerFactory.defaultPersistenceBroker();
              broker.delete(product);
          }
          finally
          {
              if (broker != null) broker.close();
          }
      }
  
      public static void main(String[] args)
      {
          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 aProduct = findByTemplate(template);
  
          sellOneProduct(template);
      }
  }
  
  
  

---------------------------------------------------------------------
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