<?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>Implementing Key Creators </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="indexes.html" title="Chapter 10. Secondary Databases" /> <link rel="previous" href="indexes.html" title="Chapter 10. Secondary Databases" /> <link rel="next" href="secondaryProps.html" title="Secondary Database Properties" /> </head> <body> <div class="navheader"> <table width="100%" summary="Navigation header"> <tr> <th colspan="3" align="center">Implementing Key Creators </th> </tr> <tr> <td width="20%" align="left"><a accesskey="p" href="indexes.html">Prev</a> </td> <th width="60%" align="center">Chapter 10. Secondary Databases</th> <td width="20%" align="right"> <a accesskey="n" href="secondaryProps.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="keyCreator"></a>Implementing Key <span>Creators</span> </h2> </div> </div> <div></div> </div> <p> You must provide every secondary database with a <span>class</span> that creates keys from primary records. You identify this <span>class</span> <span> using the <tt class="methodname">SecondaryConfig.setKeyCreator()</tt> method. </span> </p> <p> You can create keys using whatever data you want. Typically you will base your key on some information found in a record's data, but you can also use information found in the primary record's key. How you build your keys is entirely dependent upon the nature of the index that you want to maintain. </p> <p> You implement a key creator by writing a class that implements the <tt class="classname">SecondaryKeyCreator</tt> interface. This interface requires you to implement the <tt class="methodname">SecondaryKeyCreator.createSecondaryKey()</tt> method. </p> <p> One thing to remember when implementing this method is that you will need a way to extract the necessary information from the data's <tt class="classname">DatabaseEntry</tt> and/or the key's <tt class="classname">DatabaseEntry</tt> that are provided on calls to this method. If you are using complex objects, then you are probably using the Bind APIs to perform this conversion. The easiest thing to do is to instantiate the <tt class="classname">EntryBinding</tt> or <tt class="classname">TupleBinding</tt> that you need to perform the conversion, and then provide this to your key creator's constructor. The Bind APIs are introduced in <a href="bindAPI.html">Using the BIND APIs</a>. </p> <p> <tt class="methodname">SecondaryKeyCreator.createSecondaryKey()</tt> returns a boolean. A return value of <tt class="literal">false</tt> indicates that no secondary key exists, and therefore no record should be added to the secondary database for that primary record. If a record already exists in the secondary database, it is deleted. </p> <p> For example, suppose your primary database uses the following class for its record data: </p> <a id="java_index3"></a> <pre class="programlisting">package db.GettingStarted; public class PersonData { private String userID; private String surname; private String familiarName; public PersonData(String userID, String surname, String familiarName) { this.userID = userID; this.surname = surname; this.familiarName = familiarName; } public String getUserID() { return userID; } public String getSurname() { return surname; } public String getFamiliarName() { return familiarName; } } </pre> <p> Also, suppose that you have created a custom tuple binding, <tt class="classname">PersonDataBinding</tt>, that you use to convert <tt class="classname">PersonData</tt> objects to and from <tt class="classname">DatabaseEntry</tt> objects. (Custom tuple bindings are described in <a href="bindAPI.html#customTuple">Custom Tuple Bindings</a>.) </p> <p> Finally, suppose you want a secondary database that is keyed based on the person's full name. </p> <p> Then in this case you might create a key creator as follows: </p> <a id="java_index4"></a> <pre class="programlisting">package db.GettingStarted; import com.sleepycat.bind.tuple.TupleBinding; import com.sleepycat.db.SecondaryKeyCreator; import com.sleepycat.db.DatabaseEntry; import com.sleepycat.db.DatabaseException; import com.sleepycat.db.SecondaryDatabase; import java.io.IOException; public class FullNameKeyCreator implements SecondaryKeyCreator { private TupleBinding theBinding; public FullNameKeyCreator(TupleBinding theBinding1) { theBinding = theBinding1; } public boolean createSecondaryKey(SecondaryDatabase secDb, DatabaseEntry keyEntry, DatabaseEntry dataEntry, DatabaseEntry resultEntry) { try { PersonData pd = (PersonData) theBinding.entryToObject(dataEntry); String fullName = pd.getFamiliarName() + " " + pd.getSurname(); resultEntry.setData(fullName.getBytes("UTF-8")); } catch (IOException willNeverOccur) {} return true; } } </pre> <p>Finally, you use this key creator as follows:</p> <a id="java_index5"></a> <pre class="programlisting">package db.GettingStarted; import com.sleepycat.bind.tuple.TupleBinding; import com.sleepycat.db.Database; import com.sleepycat.db.DatabaseException; import com.sleepycat.db.DatabaseType; import com.sleepycat.db.SecondaryDatabase; import com.sleepycat.db.SecondaryConfig; import java.io.FileNotFoundException; ... Database myDb = null; SecondaryDatabase mySecDb = null; try { // Primary database open omitted for brevity ... TupleBinding myDataBinding = new MyTupleBinding(); FullNameKeyCreator fnkc = new FullNameKeyCreator(myDataBinding); SecondaryConfig mySecConfig = new SecondaryConfig(); mySecConfig.setKeyCreator(fnkc); mySecConfig.setType(DatabaseType.BTREE); //Perform the actual open String secDbName = "mySecondaryDatabase"; mySecDb = new SecondaryDatabase(secDbName, null, myDb, mySecConfig); } catch (DatabaseException de) { // Exception handling goes here } catch (FileNotFoundException fnfe) { // Exception handling goes here } finally { try { if (mySecDb != null) { mySecDb.close(); } if (myDb != null) { myDb.close(); } } catch (DatabaseException dbe) { // Exception handling goes here } }</pre> <div class="sect2" lang="en" xml:lang="en"> <div class="titlepage"> <div> <div> <h3 class="title"><a id="multikeys"></a>Working with Multiple Keys</h3> </div> </div> <div></div> </div> <p> Until now we have only discussed indexes as if there is a one-to-one relationship between the secondary key and the primary database record. In fact, it is possible to generate multiple keys for any given record, provided that you take appropriate steps in your key creator to do so. </p> <p> For example, suppose you had a database that contained information about books. Suppose further that you sometimes want to look up books by author. Because sometimes books have multiple authors, you may want to return multiple secondary keys for every book that you index. </p> <p> To do this, you write a key creator that implements <tt class="classname">SecondaryMultiKeyCreator</tt> instead of <tt class="classname">SecondaryKeyCreator</tt>. The key difference between the two is that <tt class="classname">SecondaryKeyCreator</tt> uses a single <tt class="classname">DatabaseEntry</tt> object as the result, while <tt class="classname">SecondaryMultiKeyCreator</tt> returns a set of <tt class="classname">DatabaseEntry</tt> objects (using <tt class="classname">java.util.Set</tt>). Also, you assign the <tt class="classname">SecondaryMultiKeyCreator</tt> implementation using <tt class="methodname">SecondaryConfig.setMultiKeyCreator()</tt> instead of <tt class="methodname">SecondaryConfig.setKeyCreator()</tt>. </p> <p> For example: </p> <pre class="programlisting">package db.GettingStarted; import com.sleepycat.db.DatabaseEntry; import com.sleepycat.db.DatabaseException; import com.sleepycat.db.SecondaryDatabase; import com.sleepycat.db.SecondaryMultiKeyCreator; import java.util.HashSet; import java.util.Set; public class MyMultiKeyCreator implements SecondaryMultiKeyCreator { // Constructor not implemented. How this is implemented depends on // how you want to extract the data for your keys. MyMultiKeyCreator() { ... } // Abstract method that we must implement public void createSecondaryKeys(SecondaryDatabase secDb, DatabaseEntry keyEntry, // From the primary DatabaseEntry dataEntry, // From the primary Set results) // Results set throws DatabaseException { try { // Create your keys, adding each to the set // Creation of key 'a' not shown results.add(a) // Creation of key 'b' not shown results.add(b) } catch (IOException willNeverOccur) {} } } </pre> </div> </div> <div class="navfooter"> <hr /> <table width="100%" summary="Navigation footer"> <tr> <td width="40%" align="left"><a accesskey="p" href="indexes.html">Prev</a> </td> <td width="20%" align="center"> <a accesskey="u" href="indexes.html">Up</a> </td> <td width="40%" align="right"> <a accesskey="n" href="secondaryProps.html">Next</a></td> </tr> <tr> <td width="40%" align="left" valign="top">Chapter 10. Secondary Databases </td> <td width="20%" align="center"> <a accesskey="h" href="index.html">Home</a> </td> <td width="40%" align="right" valign="top"> Secondary Database Properties</td> </tr> </table> </div> </body> </html>