dbtJavaUsage.html   [plain text]


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Database Usage Example</title>
    <link rel="stylesheet" href="gettingStarted.css" type="text/css" />
    <meta name="generator" content="DocBook XSL Stylesheets V1.62.4" />
    <link rel="home" href="index.html" title="Getting Started with Berkeley DB" />
    <link rel="up" href="DBEntry.html" title="Chapter 8. Database Records" />
    <link rel="previous" href="bindAPI.html" title="Using the BIND APIs" />
    <link rel="next" href="Cursors.html" title="Chapter 9. Using Cursors" />
  </head>
  <body>
    <div class="navheader">
      <table width="100%" summary="Navigation header">
        <tr>
          <th colspan="3" align="center">Database Usage Example</th>
        </tr>
        <tr>
          <td width="20%" align="left"><a accesskey="p" href="bindAPI.html">Prev</a> </td>
          <th width="60%" align="center">Chapter 8. Database Records</th>
          <td width="20%" align="right"> <a accesskey="n" href="Cursors.html">Next</a></td>
        </tr>
      </table>
      <hr />
    </div>
    <div class="sect1" lang="en" xml:lang="en">
      <div class="titlepage">
        <div>
          <div>
            <h2 class="title" style="clear: both"><a id="dbtJavaUsage"></a>Database Usage Example</h2>
          </div>
        </div>
        <div></div>
      </div>
      <p>
        In <a href="CoreJavaUsage.html#MyDb">MyDbs Class</a> we created 
        a class that opens and closes databases for us.
        We now make use of that class to load inventory data into
        two databases that we will use for our inventory system.
    </p>
      <p>
        Again, remember that you can find the complete implementation for these functions
        in:
    </p>
      <pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_java/db/GettingStarted</pre>
      <p>
        where <tt class="literal"><span class="emphasis"><em>DB_INSTALL</em></span></tt> is the location where you
        placed your DB distribution.
    </p>
      <p>Note that in this example, we are going to save two types of
    information. First there are a series of inventory records that identify
    information about some food items (fruits, vegetables, and desserts).
    These records identify particulars about each item such as the vendor that
    the item can be obtained from, how much the vendor has in stock, the price
    per unit, and so forth.</p>
      <p>
        We also want to manage vendor contact information, such as the
        vendor's address and phone number, the sales representative's name
        and his phone number, and so forth.
    </p>
      <div class="example">
        <a id="inventoryjava"></a>
        <p class="title">
          <b>Example 8.1 Inventory.java</b>
        </p>
        <p>
      All Inventory data is encapsulated in an instance of the following
      class. Note that because this class is not serializable, we need a
      custom tuple binding in order to place it on a <tt class="classname">DatabaseEntry</tt>
      object. Because the <tt class="classname">TupleInput</tt> and
      <tt class="classname">TupleOutput</tt> classes used by custom tuple bindings
      support Java numerical types and not Java numerical classes, we use
      <tt class="literal">int</tt> and <tt class="literal">float</tt> here instead of the
      corresponding <tt class="classname">Integer</tt> and <tt class="classname">Float</tt>
      classes.
      
      </p>
        <a id="java_dbt16"></a>
        <pre class="programlisting">// File Inventory.java
package db.GettingStarted;

public class Inventory {

    private String sku;
    private String itemName;
    private String category;
    private String vendor;
    private int vendorInventory;
    private float vendorPrice;

    public void setSku(String data) {
            sku = data;
    }

    public void setItemName(String data) {
            itemName = data;
    }

    public void setCategory(String data) {
            category = data;
    }

    public void setVendorInventory(int data) {
            vendorInventory = data;
    }

    public void setVendor(String data) {
            vendor = data;
    }

    public void setVendorPrice(float data) {
            vendorPrice = data;
    }

    public String getSku() { return sku; }
    public String getItemName() { return itemName; }
    public String getCategory() { return category; }
    public int getVendorInventory() { return vendorInventory; }
    public String getVendor() { return vendor; }
    public float getVendorPrice() { return vendorPrice; }

} </pre>
      </div>
      <div class="example">
        <a id="vendorjava"></a>
        <p class="title">
          <b>Example 8.2 Vendor.java</b>
        </p>
        <p>
        The data for vendor records are stored in instances of the following
        class.  Notice that we are using serialization with this class for no
        other reason than to demonstrate serializing a class instance.
      </p>
        <a id="java_dbt17"></a>
        <pre class="programlisting">// File Vendor.java
package db.GettingStarted;

import java.io.Serializable;

public class Vendor implements Serializable {

    private String repName;
    private String address;
    private String city;
    private String state;
    private String zipcode;
    private String bizPhoneNumber;
    private String repPhoneNumber;
    private String vendor;

    public void setRepName(String data) {
        repName = data;
    }

    public void setAddress(String data) {
        address = data;
    }

    public void setCity(String data) {
        city = data;
    }

    public void setState(String data) {
        state = data;
    }

    public void setZipcode(String data) {
        zipcode = data;
    }

    public void setBusinessPhoneNumber(String data) {
        bizPhoneNumber = data;
    }

    public void setRepPhoneNumber(String data) {
        repPhoneNumber = data;
    }

    public void setVendorName(String data) {
        vendor = data;
    }

    ...
    // Corresponding getter methods omitted for brevity.
    // See examples/je/gettingStarted/Vendor.java
    // for a complete implementation of this class.

} </pre>
      </div>
      <p>
        Because we will not be using serialization to convert our
        <tt class="classname">Inventory</tt> objects to a <tt class="classname">DatabaseEntry</tt>
        object, we need a custom tuple binding:
    </p>
      <div class="example">
        <a id="InventoryJavaBinding"></a>
        <p class="title">
          <b>Example 8.3 InventoryBinding.java</b>
        </p>
        <a id="java_dbt18"></a>
        <pre class="programlisting">// File InventoryBinding.java
package db.GettingStarted;

import com.sleepycat.bind.tuple.TupleBinding;
import com.sleepycat.bind.tuple.TupleInput;
import com.sleepycat.bind.tuple.TupleOutput;

public class InventoryBinding extends TupleBinding {

    // Implement this abstract method. Used to convert
    // a DatabaseEntry to an Inventory object.
    public Object entryToObject(TupleInput ti) {

        String sku = ti.readString();
        String itemName = ti.readString();
        String category = ti.readString();
        String vendor = ti.readString();
        int vendorInventory = ti.readInt();
        float vendorPrice = ti.readFloat();

        Inventory inventory = new Inventory();
        inventory.setSku(sku);
        inventory.setItemName(itemName);
        inventory.setCategory(category);
        inventory.setVendor(vendor);
        inventory.setVendorInventory(vendorInventory);
        inventory.setVendorPrice(vendorPrice);

        return inventory;
    }

    // Implement this abstract method. Used to convert a
    // Inventory object to a DatabaseEntry object.
    public void objectToEntry(Object object, TupleOutput to) {

        Inventory inventory = (Inventory)object;

        to.writeString(inventory.getSku());
        to.writeString(inventory.getItemName());
        to.writeString(inventory.getCategory());
        to.writeString(inventory.getVendor());
        to.writeInt(inventory.getVendorInventory());
        to.writeFloat(inventory.getVendorPrice());
    }
} </pre>
      </div>
      <p>
        In order to store the data identified above, we write the
        <tt class="classname">ExampleDatabaseLoad</tt> application. This application
        loads the inventory and vendor databases for you.
    </p>
      <p>
        Inventory information is stored in a <tt class="classname">Database</tt>
        dedicated for that purpose. The key for each such record is a product
        SKU.  The inventory data stored in this database are objects of the
        <tt class="classname">Inventory</tt> class (see <a href="dbtJavaUsage.html#inventoryjava">Inventory.java</a> for more information).
        <tt class="classname">ExampleDatabaseLoad</tt> loads the inventory database
        as follows:
    </p>
      <div class="orderedlist">
        <ol type="1">
          <li>
            <p>
            Reads the inventory data from a flat text file prepared in
            advance for this purpose.
        </p>
          </li>
          <li>
            <p>
            Uses <tt class="classname">java.lang.String</tt> to create a key based
            on the item's SKU.
        </p>
          </li>
          <li>
            <p>Uses an <tt class="classname">Inventory</tt> class instance for the
        record data. This object is stored on a <tt class="classname">DatabaseEntry</tt>
        object using <tt class="classname">InventoryBinding</tt>, a custom tuple
        binding that we implemented above.</p>
          </li>
          <li>
            <p>Saves each record to the inventory database.</p>
          </li>
        </ol>
      </div>
      <p>Vendor information is also stored in a <tt class="classname">Database</tt>
    dedicated for that purpose.  The vendor data stored in this database are objects of the
    <tt class="classname">Vendor</tt> class (see <a href="dbtJavaUsage.html#vendorjava">Vendor.java</a> for more information). To load this
    <tt class="classname">Database</tt>, <tt class="classname">ExampleDatabaseLoad</tt>
    does the following:</p>
      <div class="orderedlist">
        <ol type="1">
          <li>
            <p>Reads the vendor data from a flat text file prepared in advance
        for this purpose.</p>
          </li>
          <li>
            <p>Uses the vendor's name as the record's key.</p>
          </li>
          <li>
            <p>Uses a <tt class="classname">Vendor</tt> class instance for the
        record data. This object is stored on a <tt class="classname">DatabaseEntry</tt>
        object using <tt class="classname">com.sleepycat.bind.serial.SerialBinding</tt>.</p>
          </li>
        </ol>
      </div>
      <div class="example">
        <a id="dbsStoredClass"></a>
        <p class="title">
          <b>Example 8.4 Stored Class Catalog Management with MyDbs</b>
        </p>
        <p>
            Before we can write <tt class="classname">ExampleDatabaseLoad</tt>, we need to update 
            <tt class="filename">MyDbs.java</tt> to support the class catalogs that we need for this application.
        </p>
        <p>
            To do this, we start by importing an additional class to support stored class catalogs:
        </p>
        <a id="java_dbt19"></a>
        <pre class="programlisting">// File: MyDbs.java
package db.GettingStarted;
                                                                                                                                  
<b class="userinput"><tt>import com.sleepycat.bind.serial.StoredClassCatalog;</tt></b>

import com.sleepycat.db.Database;
import com.sleepycat.db.DatabaseConfig;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.DatabaseType;

import java.io.FileNotFoundException; </pre>
        <p>
    We also need to add two additional private data members to this class. One
    supports the database used for the class catalog, and the other is used as a
    handle for the class catalog itself.
</p>
        <a id="java_dbt20"></a>
        <pre class="programlisting">public class MyDbs {

    // The databases that our application uses
    private Database vendorDb = null;
    private Database inventoryDb = null;
    <b class="userinput"><tt>private Database classCatalogDb = null;

    // Needed for object serialization
    private StoredClassCatalog classCatalog;</tt></b>

    private String vendordb = "VendorDB.db";
    private String inventorydb = "InventoryDB.db";
    <b class="userinput"><tt>private String classcatalogdb = "ClassCatalogDB.db";</tt></b>

    // Our constructor does nothing
    public MyDbs() {} </pre>
        <p>
        Next we need to update the <tt class="methodname">MyDbs.setup()</tt> method 
        to open the class catalog database and create the class catalog.
    </p>
        <a id="java_dbt21"></a>
        <pre class="programlisting">    // The setup() method opens all our databases
    // for us.
    public void setup(String databasesHome)
        throws DatabaseException {

        DatabaseConfig myDbConfig = new DatabaseConfig();

        ...
        // Database configuration omitted for brevity
        ...

        // Now open, or create and open, our databases
        // Open the vendors and inventory databases
        try {
            vendordb = databasesHome + "/" + vendordb;
            vendorDb = new Database(vendordb,
                                    null,
                                    myDbConfig);

            inventorydb = databasesHome + "/" + inventorydb;
            inventoryDb = new Database(inventorydb,
                                        null,
                                        myDbConfig);

            <b class="userinput"><tt>// Open the class catalog db. This is used to
            // optimize class serialization.
            classcatalogdb = databasesHome + "/" + classcatalogdb;
            classCatalogDb = new Database(classcatalogdb,
                                          null,
                                          myDbConfig); </tt></b>

        } catch(FileNotFoundException fnfe) {
            System.err.println("MyDbs: " + fnfe.toString());
            System.exit(-1);
        }
    } </pre>
        <p>
        Finally we need a getter method to return the class catalog. Note that we do not provide a getter for
        the catalog database itself – our application has no need for that.
    </p>
        <p>
        We also update our <tt class="methodname">close()</tt> to close our class catalog.
    </p>
        <a id="java_dbt22"></a>
        <pre class="programlisting">   // getter methods
    public Database getVendorDB() {
        return vendorDb;
    }

    public Database getInventoryDB() {
        return inventoryDb;
    }

    <b class="userinput"><tt>public StoredClassCatalog getClassCatalog() {
        return classCatalog;
    }</tt></b>
</pre>
        <p>
    Finally, we need our <tt class="methodname">close()</tt> method:
</p>
        <a id="java_dbt23"></a>
        <pre class="programlisting">

    // Close the databases
    public void close() {
        try {
            if (vendorDb != null) {
                vendorDb.close();
            }

            if (inventoryDb != null) {
                inventoryDb.close();
            }

            <b class="userinput"><tt>if (classCatalogDb != null) {
                classCatalogDb.close();
            }</tt></b>
        } catch(DatabaseException dbe) {
            System.err.println("Error closing MyDbs: " +
                                dbe.toString());
            System.exit(-1);
        }
    }
} </pre>
      </div>
      <p>
        So far we have identified the data that we want to store in our
        databases and how we will convert that data in and out of
        <tt class="classname">DatabaseEntry</tt> objects for database storage. We
        have also updated <tt class="classname">MyDbs</tt> to manage our databases
        for us. Now we write <tt class="classname">ExampleDatabaseLoad</tt> to
        actually put the inventory and vendor data into their respective
        databases. Because of the work that we have done so far, this
        application is actually fairly simple to write.
    </p>
      <div class="example">
        <a id="EDL"></a>
        <p class="title">
          <b>Example 8.5 ExampleDatabaseLoad.java</b>
        </p>
        <p>First we need the usual series of import statements:</p>
        <a id="java_dbt24"></a>
        <pre class="programlisting">// File: ExampleDatabaseLoad.java
package db.GettingStarted;
                                                                                                                                       
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import com.sleepycat.bind.EntryBinding;
import com.sleepycat.bind.serial.SerialBinding;
import com.sleepycat.bind.tuple.TupleBinding;
import com.sleepycat.db.DatabaseEntry;
import com.sleepycat.db.DatabaseException; </pre>
        <p>Next comes the class declaration and the private data members that
      we need for this class. Most of these are setting up default values for
      the program.</p>
        <p>Note that two <tt class="classname">DatabaseEntry</tt> objects are
      instantiated here. We will reuse these for every database operation that
      this program performs. Also a <tt class="classname">MyDbEnv</tt> object is
      instantiated here. We can do this because its constructor never throws
      an exception. See <a href="dbtJavaUsage.html#dbsStoredClass">Stored Class Catalog Management with MyDbs</a> for
      its implementation details.</p>
        <p>Finally, the <tt class="filename">inventory.txt</tt> and
      <tt class="filename">vendors.txt</tt> file can be found in the GettingStarted
      examples directory along with the classes described in this extended
      example.</p>
        <a id="java_dbt25"></a>
        <pre class="programlisting">public class ExampleDatabaseLoad {

    private static String myDbsPath = "./";
    private static File inventoryFile = new File("./inventory.txt");
    private static File vendorsFile = new File("./vendors.txt");

    // DatabaseEntries used for loading records
    private static DatabaseEntry theKey = new DatabaseEntry();
    private static DatabaseEntry theData = new DatabaseEntry();

    // Encapsulates the databases.
    private static MyDbs myDbs = new MyDbs(); </pre>
        <p>
            Next comes the <tt class="methodname">usage()</tt> and
            <tt class="methodname">main()</tt> methods. Notice the exception handling
            in the <tt class="methodname">main()</tt> method. This is the only place in the application where we
            catch exceptions. For this reason, we must catch
            <tt class="classname">DatabaseException</tt> which is thrown by the
            <tt class="literal">com.sleepycat.db.*</tt> classes.
      </p>
        <p>Also notice the call to <tt class="methodname">MyDbs.close()</tt>
      in the <tt class="literal">finally</tt> block. This is the only place in the
      application where <tt class="methodname">MyDbs.close()</tt> is called.
      <tt class="methodname">MyDbs.close()</tt> is responsible for closing
      all open <tt class="classname">Database</tt>
      handles for you.</p>
        <a id="java_dbt26"></a>
        <pre class="programlisting">    private static void usage() {
        System.out.println("ExampleDatabaseLoad [-h &lt;database home&gt;]");
        System.out.println("      [-s &lt;selections file&gt;] [-v &lt;vendors file&gt;]");
        System.exit(-1);
    }

    public static void main(String args[]) {
        ExampleDatabaseLoad edl = new ExampleDatabaseLoad();
        try {
            edl.run(args);
        } catch (DatabaseException dbe) {
            System.err.println("ExampleDatabaseLoad: " + dbe.toString());
            dbe.printStackTrace();
        } catch (Exception e) {
            System.out.println("Exception: " + e.toString());
            e.printStackTrace();
        } finally {
            myDbs.close();
        }
        System.out.println("All done.");
    } </pre>
        <p>Next we write the <tt class="methodname">ExampleDatabaseLoad.run()</tt>
      method. This method is responsible for initializing all objects. 
      Because our environment and databases are all opened using the 
      <tt class="methodname">MyDbs.setup()</tt> method, <tt class="methodname">ExampleDatabaseLoad.run()</tt>
      method is only responsible for calling <tt class="methodname">MyDbs.setup()</tt> and then calling 
      the <tt class="classname">ExampleDatabaseLoad</tt> methods that actually load the databases. 
      </p>
        <a id="java_dbt27"></a>
        <pre class="programlisting">    private void run(String args[]) throws DatabaseException {
        // Parse the arguments list
        parseArgs(args);

        myDbs.setup(myDbsPath); // path to the environment home

        System.out.println("loading vendors db.");
        loadVendorsDb();
        System.out.println("loading inventory db.");
        loadInventoryDb();
    } </pre>
        <p>This next method loads the vendor database. This method
      uses serialization to convert the <tt class="classname">Vendor</tt> object
      to a <tt class="classname">DatabaseEntry</tt> object.</p>
        <a id="java_dbt28"></a>
        <pre class="programlisting">   private void loadVendorsDb() 
            throws DatabaseException {

        // loadFile opens a flat-text file that contains our data
        // and loads it into a list for us to work with. The integer
        // parameter represents the number of fields expected in the
        // file.
        List vendors = loadFile(vendorsFile, 8);

        // Now load the data into the database. The vendor's name is the
        // key, and the data is a Vendor class object.

        // Need a serial binding for the data
        EntryBinding dataBinding =
            new SerialBinding(myDbs.getClassCatalog(), Vendor.class);

        for (int i = 0; i &lt; vendors.size(); i++) {
            String[] sArray = (String[])vendors.get(i);
            Vendor theVendor = new Vendor();
            theVendor.setVendorName(sArray[0]);
            theVendor.setAddress(sArray[1]);
            theVendor.setCity(sArray[2]);
            theVendor.setState(sArray[3]);
            theVendor.setZipcode(sArray[4]);
            theVendor.setBusinessPhoneNumber(sArray[5]);
            theVendor.setRepName(sArray[6]);
            theVendor.setRepPhoneNumber(sArray[7]);

            // The key is the vendor's name.
            // ASSUMES THE VENDOR'S NAME IS UNIQUE!
            String vendorName = theVendor.getVendorName();
            try {
                theKey = new DatabaseEntry(vendorName.getBytes("UTF-8"));
            } catch (IOException willNeverOccur) {}

            // Convert the Vendor object to a DatabaseEntry object
            // using our SerialBinding
            dataBinding.objectToEntry(theVendor, theData);

            // Put it in the database.
            myDbs.getVendorDB().put(null, theKey, theData);
        }
    } </pre>
        <p>Now load the inventory database. This method uses our
      custom tuple binding (see <a href="dbtJavaUsage.html#InventoryJavaBinding">InventoryBinding.java</a>) to convert the <tt class="classname">Inventory</tt>
      object to a <tt class="classname">DatabaseEntry</tt> object.</p>
        <a id="java_dbt29"></a>
        <pre class="programlisting">    private void loadInventoryDb() 
        throws DatabaseException {

        // loadFile opens a flat-text file that contains our data
        // and loads it into a list for us to work with. The integer
        // parameter represents the number of fields expected in the
        // file.
        List inventoryArray = loadFile(inventoryFile, 6);

        // Now load the data into the database. The item's sku is the
        // key, and the data is an Inventory class object.

        // Need a tuple binding for the Inventory class.
        TupleBinding inventoryBinding = new InventoryBinding();

        for (int i = 0; i &lt; inventoryArray.size(); i++) {
            String[] sArray = (String[])inventoryArray.get(i);
            String sku = sArray[1];
            try {
                theKey = new DatabaseEntry(sku.getBytes("UTF-8"));
            } catch (IOException willNeverOccur) {}

            Inventory theInventory = new Inventory();
            theInventory.setItemName(sArray[0]);
            theInventory.setSku(sArray[1]);
            Float price = new Float(sArray[2]);
            theInventory.setVendorPrice(price.floatValue());
            Integer vInventory = new Integer(sArray[3]);
            theInventory.setVendorInventory(vInventory.intValue());
            theInventory.setCategory(sArray[4]);
            theInventory.setVendor(sArray[5]);

            // Place the Vendor object on the DatabaseEntry object using 
            // our the tuple binding we implemented in 
            // InventoryBinding.java
            inventoryBinding.objectToEntry(theInventory, theData);

            // Put it in the database. Note that this causes our 
            // secondary database to be automatically updated for us.
            myDbs.getInventoryDB().put(null, theKey, theData);
        }
    }</pre>
        <p>
        The remainder of this application provides utility methods to 
        read a flat text file into an array of strings and parse the
        command line options: 
      </p>
        <a id="java_dbt30"></a>
        <pre class="programlisting">    private static void parseArgs(String args[]) {
        // Implementation omitted for brevity.
    }

    private List loadFile(File theFile, int numFields) {
        List records = new ArrayList();
        // Implementation omitted for brevity.
        return records;
    }

    protected ExampleDatabaseLoad() {}
} </pre>
        <p>
        From the perspective of this document, these
        things are relatively uninteresting. You can see how they are
        implemented by looking at <tt class="filename">ExampleDatabaseLoad.java</tt>
        in:
      </p>
        <pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_java/db/GettingStarted</pre>
        <p>
        where <tt class="literal"><span class="emphasis"><em>DB_INSTALL</em></span></tt> is the location where you
        placed your DB distribution.
    </p>
      </div>
    </div>
    <div class="navfooter">
      <hr />
      <table width="100%" summary="Navigation footer">
        <tr>
          <td width="40%" align="left"><a accesskey="p" href="bindAPI.html">Prev</a> </td>
          <td width="20%" align="center">
            <a accesskey="u" href="DBEntry.html">Up</a>
          </td>
          <td width="40%" align="right"> <a accesskey="n" href="Cursors.html">Next</a></td>
        </tr>
        <tr>
          <td width="40%" align="left" valign="top">Using the BIND APIs </td>
          <td width="20%" align="center">
            <a accesskey="h" href="index.html">Home</a>
          </td>
          <td width="40%" align="right" valign="top"> Chapter 9. Using Cursors</td>
        </tr>
      </table>
    </div>
  </body>
</html>