1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3<html xmlns="http://www.w3.org/1999/xhtml">
4  <head>
5    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6    <title>Secondary Database Example</title>
7    <link rel="stylesheet" href="gettingStarted.css" type="text/css" />
8    <meta name="generator" content="DocBook XSL Stylesheets V1.73.2" />
9    <link rel="start" href="index.html" title="Getting Started with Berkeley DB" />
10    <link rel="up" href="indexes.html" title="Chapter��10.��Secondary Databases" />
11    <link rel="prev" href="joins.html" title="Database Joins" />
12    <link rel="next" href="dbconfig.html" title="Chapter��11.��Database Configuration" />
13  </head>
14  <body>
15    <div class="navheader">
16      <table width="100%" summary="Navigation header">
17        <tr>
18          <th colspan="3" align="center">Secondary Database Example</th>
19        </tr>
20        <tr>
21          <td width="20%" align="left"><a accesskey="p" href="joins.html">Prev</a>��</td>
22          <th width="60%" align="center">Chapter��10.��Secondary Databases</th>
23          <td width="20%" align="right">��<a accesskey="n" href="dbconfig.html">Next</a></td>
24        </tr>
25      </table>
26      <hr />
27    </div>
28    <div class="sect1" lang="en" xml:lang="en">
29      <div class="titlepage">
30        <div>
31          <div>
32            <h2 class="title" style="clear: both"><a id="javaindexusage"></a>Secondary Database Example</h2>
33          </div>
34        </div>
35      </div>
36      <div class="toc">
37        <dl>
38          <dt>
39            <span class="sect2">
40              <a href="javaindexusage.html#secondaryMyDbs">Opening Secondary Databases with MyDbs</a>
41            </span>
42          </dt>
43          <dt>
44            <span class="sect2">
45              <a href="javaindexusage.html#exampleReadJavaSecondaries">Using Secondary Databases with ExampleDatabaseRead</a>
46            </span>
47          </dt>
48        </dl>
49      </div>
50      <p>In previous chapters in this book, we built applications that load
51    and display several DB databases. In this example, we will extend those
52    examples to use secondary databases. Specifically:</p>
53      <div class="itemizedlist">
54        <ul type="disc">
55          <li>
56            <p>In <a class="xref" href="dbtJavaUsage.html#dbsStoredClass" title="Example 8.4 Stored Class Catalog Management with MyDbs">Stored Class Catalog Management with MyDbs</a> we built a
57        class that we can use to open several <code class="classname">Database</code> objects.
58        In <a class="xref" href="javaindexusage.html#secondaryMyDbs" title="Opening Secondary Databases with MyDbs">Opening Secondary Databases with MyDbs</a> we will extend 
59        that class to also open and manage a <code class="classname">SecondaryDatabase</code>.
60        </p>
61          </li>
62          <li>
63            <p>In <a class="xref" href="cursorJavaUsage.html" title="Cursor Example">Cursor Example</a> we
64        built an application to display our inventory database (and related
65        vendor information). In <a class="xref" href="javaindexusage.html#exampleReadJavaSecondaries" title="Using Secondary Databases with ExampleDatabaseRead">Using Secondary Databases with ExampleDatabaseRead</a> we will extend that application to
66        show inventory records based on the index we cause to be loaded using
67        <code class="classname">ExampleDatabaseLoad</code>.
68        </p>
69          </li>
70        </ul>
71      </div>
72      <p>
73            Before we can use a secondary database, we must implement a class to extract secondary keys for us. 
74            We use <code class="classname">ItemNameKeyCreator</code> for this purpose.
75        </p>
76      <div class="example">
77        <a id="ItemNameKeyCreator-Java"></a>
78        <p class="title">
79          <b>Example 10.1 ItemNameKeyCreator.java</b>
80        </p>
81        <div class="example-contents">
82          <p>
83        This class assumes the primary database
84        uses <code class="classname">Inventory</code> objects for the record data. The
85        <code class="classname">Inventory</code> class is described in <a class="xref" href="dbtJavaUsage.html#inventoryjava" title="Example 8.1 Inventory.java">Inventory.java</a>.</p>
86          <p>In our key creator class, we make use of a custom tuple binding
87        called <code class="classname">InventoryBinding</code>. This class is described in <a class="xref" href="dbtJavaUsage.html#InventoryJavaBinding" title="Example 8.3 InventoryBinding.java">InventoryBinding.java</a>.</p>
88          <p>You can find <code class="filename">InventoryBinding.java</code> in: </p>
89          <pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_java/db/GettingStarted</pre>
90          <p>
91        where <code class="literal"><span class="emphasis"><em>DB_INSTALL</em></span></code> is the location where you
92        placed your DB distribution.
93    </p>
94          <a id="java_index11"></a>
95          <pre class="programlisting">package db.GettingStarted;
96
97import com.sleepycat.db.DatabaseEntry;
98import com.sleepycat.db.DatabaseException;
99import com.sleepycat.db.SecondaryDatabase;
100import com.sleepycat.db.SecondaryKeyCreator;
101import com.sleepycat.bind.tuple.TupleBinding;
102
103import java.io.IOException;
104
105public class ItemNameKeyCreator implements SecondaryKeyCreator {
106
107    private TupleBinding theBinding;
108
109    // Use the constructor to set the tuple binding
110    ItemNameKeyCreator(TupleBinding binding) {
111        theBinding = binding;
112    }
113
114    // Abstract method that we must implement
115    public boolean createSecondaryKey(SecondaryDatabase secDb,
116        DatabaseEntry keyEntry,    // From the primary
117        DatabaseEntry dataEntry,   // From the primary
118        DatabaseEntry resultEntry) // set the key data on this.
119        throws DatabaseException {
120
121        try {
122            // Convert dataEntry to an Inventory object
123            Inventory inventoryItem = 
124                (Inventory) theBinding.entryToObject(dataEntry);
125            // Get the item name and use that as the key
126            String theItem = inventoryItem.getItemName();
127            resultEntry.setData(theItem.getBytes("UTF-8"));
128        } catch (IOException willNeverOccur) {}
129
130        return true;
131    }
132} </pre>
133        </div>
134      </div>
135      <br class="example-break" />
136      <p>
137            Now that we have a key creator, we can use it to generate keys for a
138            secondary database. We will now extend <code class="classname">MyDbs</code>
139            to manage a secondary database, and to use
140            <code class="classname">ItemNameKeyCreator</code> to generate keys for that
141            secondary database.
142      </p>
143      <div class="sect2" lang="en" xml:lang="en">
144        <div class="titlepage">
145          <div>
146            <div>
147              <h3 class="title"><a id="secondaryMyDbs"></a>Opening Secondary Databases with MyDbs</h3>
148            </div>
149          </div>
150        </div>
151        <p>In <a class="xref" href="dbtJavaUsage.html#dbsStoredClass" title="Example 8.4 Stored Class Catalog Management with MyDbs">Stored Class Catalog Management with MyDbs</a> we built
152      <code class="classname">MyDbs</code> as an example of a class that
153      encapsulates 
154      <code class="classname">Database</code> opens and closes. We will now extend
155      that class to manage a <code class="classname">SecondaryDatabase</code>.</p>
156        <div class="example">
157          <a id="mydbsSecondary"></a>
158          <p class="title">
159            <b>Example 10.2 SecondaryDatabase Management with MyDbs</b>
160          </p>
161          <div class="example-contents">
162            <p>
163            We start by importing two additional classes needed to support secondary databases. 
164            We also add a global variable to use as a handle for our secondary database.
165        </p>
166            <a id="java_index12"></a>
167            <pre class="programlisting">// File MyDbs.java
168package db.GettingStarted;
169                                                                                                                                       
170import java.io.FileNotFoundException;
171                                                                                                                                       
172import com.sleepycat.bind.serial.StoredClassCatalog;
173import com.sleepycat.bind.tuple.TupleBinding;
174import com.sleepycat.db.Database;
175import com.sleepycat.db.DatabaseConfig;
176import com.sleepycat.db.DatabaseException;
177import com.sleepycat.db.DatabaseType;
178<strong class="userinput"><code>import com.sleepycat.db.SecondaryConfig;
179import com.sleepycat.db.SecondaryDatabase;</code></strong>
180
181public class MyDbs {
182
183    // The databases that our application uses
184    private Database vendorDb = null;
185    private Database inventoryDb = null;
186    private Database classCatalogDb = null;
187    <strong class="userinput"><code>private SecondaryDatabase itemNameIndexDb = null;</code></strong>
188
189    private String vendordb = "VendorDB.db";
190    private String inventorydb = "InventoryDB.db";
191    private String classcatalogdb = "ClassCatalogDB.db";
192    <strong class="userinput"><code>private String itemnameindexdb = "ItemNameIndexDB.db";</code></strong>
193
194    // Needed for object serialization
195    private StoredClassCatalog classCatalog;
196
197    // Our constructor does nothing
198    public MyDbs() {} </pre>
199            <p>
200        Next we update the <code class="methodname">MyDbs.setup()</code> method to open the 
201		secondary database. As a part of this, we have to pass an 
202		<code class="classname">ItemNameKeyCreator</code> object on the call to open the secondary
203        database. Also, in order to instantiate <code class="classname">ItemNameKeyCreator</code>, we need an
204        <code class="classname">InventoryBinding</code> object (we described this class in 
205            <a class="xref" href="dbtJavaUsage.html#InventoryJavaBinding" title="Example 8.3 InventoryBinding.java">InventoryBinding.java</a>). 
206        We do all this work together inside of <code class="methodname">MyDbs.setup()</code>.
207    </p>
208            <a id="java_index13"></a>
209            <pre class="programlisting">    public void setup(String databasesHome)
210        throws DatabaseException {
211        DatabaseConfig myDbConfig = new DatabaseConfig();
212        <strong class="userinput"><code>SecondaryConfig mySecConfig = new SecondaryConfig();</code></strong>
213
214        myDbConfig.setErrorStream(System.err);
215        <strong class="userinput"><code>mySecConfig.setErrorStream(System.err);</code></strong>
216        myDbConfig.setErrorPrefix("MyDbs");
217        <strong class="userinput"><code>mySecConfig.setErrorPrefix("MyDbs");</code></strong>
218        myDbConfig.setType(DatabaseType.BTREE);
219        <strong class="userinput"><code>mySecConfig.setType(DatabaseType.BTREE);</code></strong>
220        myDbConfig.setAllowCreate(true);
221        <strong class="userinput"><code>mySecConfig.setAllowCreate(true);</code></strong>
222
223        // Now open, or create and open, our databases
224        // Open the vendors and inventory databases
225        try {
226            vendordb = databasesHome + "/" + vendordb;
227            vendorDb = new Database(vendordb,
228                                    null,
229                                    myDbConfig);
230
231            inventorydb = databasesHome + "/" + inventorydb;
232            inventoryDb = new Database(inventorydb,
233                                        null,
234                                        myDbConfig);
235
236            // Open the class catalog db. This is used to
237            // optimize class serialization.
238            classcatalogdb = databasesHome + "/" + classcatalogdb;
239            classCatalogDb = new Database(classcatalogdb,
240                                          null,
241                                          myDbConfig);
242        } catch(FileNotFoundException fnfe) {
243            System.err.println("MyDbs: " + fnfe.toString());
244            System.exit(-1);
245        }
246
247        // Create our class catalog
248        classCatalog = new StoredClassCatalog(classCatalogDb);
249
250        // Need a tuple binding for the Inventory class.
251        // We use the InventoryBinding class
252        // that we implemented for this purpose.
253        TupleBinding inventoryBinding = new InventoryBinding();
254
255        <strong class="userinput"><code>// Open the secondary database. We use this to create a
256        // secondary index for the inventory database
257
258        // We want to maintain an index for the inventory entries based
259        // on the item name. So, instantiate the appropriate key creator
260        // and open a secondary database.
261        ItemNameKeyCreator keyCreator =
262            new ItemNameKeyCreator(new InventoryBinding());
263
264        // Set up additional secondary properties
265        // Need to allow duplicates for our secondary database
266        mySecConfig.setSortedDuplicates(true);
267        mySecConfig.setAllowPopulate(true); // Allow autopopulate
268        mySecConfig.setKeyCreator(keyCreator);
269        // Now open it
270        try {
271            itemnameindexdb = databasesHome + "/" + itemnameindexdb;
272            itemNameIndexDb = new SecondaryDatabase(itemnameindexdb,
273                                                    null,
274                                                    inventoryDb,
275                                                    mySecConfig);
276        } catch(FileNotFoundException fnfe) {
277            System.err.println("MyDbs: " + fnfe.toString());
278            System.exit(-1);
279        }</code></strong>
280    }
281    </pre>
282            <p>
283        Next we need an additional getter method for returning the secondary database.
284    </p>
285            <a id="java_index14"></a>
286            <pre class="programlisting">    public SecondaryDatabase getNameIndexDB() {
287        return itemNameIndexDb;
288    } </pre>
289            <p>Finally, we need to update the <code class="methodname">MyDbs.close()</code>
290        method to close the new secondary database. We want to make sure that
291        the secondary is closed before the primaries. While
292        this is not necessary for this example because our
293        closes are single-threaded, it is still a good habit to adopt.</p>
294            <a id="java_index15"></a>
295            <pre class="programlisting">    public void close() {
296        try {
297            <strong class="userinput"><code>if (itemNameIndexDb != null) {
298                itemNameIndexDb.close();
299            }</code></strong>
300
301            if (vendorDb != null) {
302                vendorDb.close();
303            }
304
305            if (inventoryDb != null) {
306                inventoryDb.close();
307            }
308
309            if (classCatalogDb != null) {
310                classCatalogDb.close();
311            }
312
313        } catch(DatabaseException dbe) {
314            System.err.println("Error closing MyDbs: " +
315                                dbe.toString());
316            System.exit(-1);
317        }
318    }
319} </pre>
320            <p>That completes our update to <code class="classname">MyDbs</code>. You
321        can find the complete class implementation in:
322        </p>
323            <pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_java/db/GettingStarted</pre>
324            <p>
325        where <code class="literal"><span class="emphasis"><em>DB_INSTALL</em></span></code> is the location where you
326        placed your DB distribution.
327    </p>
328          </div>
329        </div>
330        <br class="example-break" />
331      </div>
332      <div class="sect2" lang="en" xml:lang="en">
333        <div class="titlepage">
334          <div>
335            <div>
336              <h3 class="title"><a id="exampleReadJavaSecondaries"></a>Using Secondary Databases with ExampleDatabaseRead</h3>
337            </div>
338          </div>
339        </div>
340        <p>Because we performed all our secondary database configuration management in
341        <code class="classname">MyDbs</code>, we do not need to modify <code class="classname">ExampleDatabaseLoad</code> at all in
342        order to create our secondary indices. When <code class="classname">ExampleDatabaseLoad</code> calls 
343        <code class="methodname">MyDbs.setup()</code>, all of the necessary work is performed for us.
344        </p>
345        <p>
346            However, we still need to take advantage of the new secondary indices. We do this by updating 
347            <code class="classname">ExampleDatabaseRead</code> to allow us to query for an inventory record based on its name.
348            Remember that the primary key for an inventory record is the item's SKU. The item's name is contained in the 
349            <code class="classname">Inventory</code> object that is stored as each record's data in the inventory database. But
350            our new secondary index now allows us to easily query based on the item's name.
351        </p>
352        <p>
353        For this update, we modify
354        <code class="classname">ExampleDatabaseRead</code> to accept a new command line switch,
355        <code class="literal">-s</code>, whose argument is the name of an inventory item.
356        If the switch is present on the command line call to
357        <code class="classname">ExampleDatabaseRead</code>, then the application will
358        use the secondary database to look up and display all the inventory
359        records with that item name. Note that we use a <code class="classname">SecondaryCursor</code>
360        to seek to the item name key and then display all matching records.
361      </p>
362        <p>Remember that you can find <code class="filename">ExampleDatabaseRead.java</code> in: </p>
363        <pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_java/db/GettingStarted</pre>
364        <p>
365        where <code class="literal"><span class="emphasis"><em>DB_INSTALL</em></span></code> is the location where you
366        placed your DB distribution.
367    </p>
368        <div class="example">
369          <a id="secondaryWithEDR"></a>
370          <p class="title">
371            <b>Example 10.3 SecondaryDatabase usage with ExampleDatabaseRead</b>
372          </p>
373          <div class="example-contents">
374            <p>
375            First we need to import an additional class in order to use the secondary cursor:
376        </p>
377            <a id="java_index16"></a>
378            <pre class="programlisting">package db.GettingStarted;
379
380import java.io.IOException;
381
382import com.sleepycat.bind.EntryBinding;
383import com.sleepycat.bind.serial.SerialBinding;
384import com.sleepycat.bind.tuple.TupleBinding;
385import com.sleepycat.db.Cursor;
386import com.sleepycat.db.DatabaseEntry;
387import com.sleepycat.db.DatabaseException;
388import com.sleepycat.db.LockMode;
389import com.sleepycat.db.OperationStatus;
390<strong class="userinput"><code>import com.sleepycat.db.SecondaryCursor;</code></strong> </pre>
391            <p>Next we add a single global variable:</p>
392            <a id="java_index17"></a>
393            <pre class="programlisting">    public class ExampleDatabaseRead {
394
395    private static String myDbsPath = "./";
396
397    // Encapsulates the database environment and databases.
398    private static MyDbs myDbs = new MyDbs();
399
400    private static TupleBinding inventoryBinding;
401    private static EntryBinding vendorBinding;
402
403    <strong class="userinput"><code>// The item to locate if the -s switch is used
404    private static String locateItem;</code></strong> </pre>
405            <p>Next we update <code class="methodname">ExampleDatabaseRead.run()</code> to
406        check to see if the <code class="literal">locateItem</code> global variable has a
407        value. If it does, then we show just those records related to the item
408        name passed on the <code class="literal">-s</code> switch.</p>
409            <a id="java_index18"></a>
410            <pre class="programlisting">    private void run(String args[]) 
411        throws DatabaseException {
412        // Parse the arguments list
413        parseArgs(args);
414
415        myDbs.setup(myDbsPath);
416
417        // Setup our bindings.
418        inventoryBinding = new InventoryBinding();
419        vendorBinding =
420             new SerialBinding(myDbs.getClassCatalog(),
421                               Vendor.class);
422
423            <strong class="userinput"><code>if (locateItem != null) {
424                showItem();
425            } else {</code></strong>
426                showAllInventory();
427            <strong class="userinput"><code>}</code></strong>
428    } </pre>
429            <p>
430            Finally, we need to implement <code class="methodname">ExampleDatabaseRead.showItem()</code>. 
431            This is a fairly simple method that opens a secondary cursor,
432            and then displays every primary record that is related to the secondary
433            key identified by the <code class="literal">locateItem</code> global variable.
434        </p>
435            <a id="java_index19"></a>
436            <pre class="programlisting">    private void showItem() throws DatabaseException {
437        SecondaryCursor secCursor = null;
438        try {
439            // searchKey is the key that we want to find in the
440            // secondary db.
441            DatabaseEntry searchKey =
442                new DatabaseEntry(locateItem.getBytes("UTF-8"));
443
444            // foundKey and foundData are populated from the primary
445            // entry that is associated with the secondary db key.
446            DatabaseEntry foundKey = new DatabaseEntry();
447            DatabaseEntry foundData = new DatabaseEntry();
448
449            // open a secondary cursor
450            secCursor =
451                myDbs.getNameIndexDB().openSecondaryCursor(null, null);
452
453            // Search for the secondary database entry.
454            OperationStatus retVal =
455                secCursor.getSearchKey(searchKey, foundKey,
456                    foundData, LockMode.DEFAULT);
457
458            // Display the entry, if one is found. Repeat until no more
459            // secondary duplicate entries are found
460            while(retVal == OperationStatus.SUCCESS) {
461                Inventory theInventory =
462                    (Inventory)inventoryBinding.entryToObject(foundData);
463                displayInventoryRecord(foundKey, theInventory);
464                retVal = secCursor.getNextDup(searchKey, foundKey,
465                    foundData, LockMode.DEFAULT);
466            }
467        } catch (Exception e) {
468            System.err.println("Error on inventory secondary cursor:");
469            System.err.println(e.toString());
470            e.printStackTrace();
471        } finally {
472            if (secCursor != null) {
473                secCursor.close();
474            }
475        }
476
477    }</pre>
478            <p>The only other thing left to do is to update 
479        <code class="methodname">ExampleDatabaseRead.parseArgs()</code> to support the <code class="literal">-s</code> command
480        line switch. To see how this is done, see
481        <code class="filename">ExampleDatabaseRead.java</code> in:
482        </p>
483            <pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_java/db/GettingStarted</pre>
484            <p>
485        where <code class="literal"><span class="emphasis"><em>DB_INSTALL</em></span></code> is the location where you
486        placed your DB distribution.
487    </p>
488          </div>
489        </div>
490        <br class="example-break" />
491      </div>
492    </div>
493    <div class="navfooter">
494      <hr />
495      <table width="100%" summary="Navigation footer">
496        <tr>
497          <td width="40%" align="left"><a accesskey="p" href="joins.html">Prev</a>��</td>
498          <td width="20%" align="center">
499            <a accesskey="u" href="indexes.html">Up</a>
500          </td>
501          <td width="40%" align="right">��<a accesskey="n" href="dbconfig.html">Next</a></td>
502        </tr>
503        <tr>
504          <td width="40%" align="left" valign="top">Database Joins��</td>
505          <td width="20%" align="center">
506            <a accesskey="h" href="index.html">Home</a>
507          </td>
508          <td width="40%" align="right" valign="top">��Chapter��11.��Database Configuration</td>
509        </tr>
510      </table>
511    </div>
512  </body>
513</html>
514