You must provide every secondary database with a class that creates keys from primary records. You identify this class using the SecondaryConfig.setKeyCreator() method.
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.
You implement a key creator by writing a class that implements the SecondaryKeyCreator interface. This interface requires you to implement the SecondaryKeyCreator.createSecondaryKey() method.
One thing to remember when implementing this method is that you will need a way to extract the necessary information from the data DatabaseEntry and/or the key DatabaseEntry 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 EntryBinding or TupleBinding that you need to perform the conversion, and then provide this to your key creator's constructor. The Bind APIs are introduced in Using the BIND APIs.
Also, SecondaryKeyCreator.createSecondaryKey() returns a boolean. A return value of false 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.
For example, suppose your primary database uses the following class for its record data:
package com.sleepycat.je.examples; 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; } }
Also, suppose that you have created a custom tuple binding, PersonDataBinding, that you use to convert PersonData objects to and from DatabaseEntry objects. (Custom tuple bindings are described in Custom Tuple Bindings.)
Finally, suppose you want a secondary database that is keyed based on the person's full name.
Then in this case you might create a key creator as follows:
package com.sleepycat.je.examples; import java.io.IOException; import com.sleepycat.je.SecondaryKeyCreator; import com.sleepycat.je.DatabaseEntry; import com.sleepycat.je.DatabaseException; import com.sleepycat.je.SecondaryDatabase; import com.sleepycat.bind.tuple.TupleBinding; public class FullNameKeyCreator implements SecondaryKeyCreator { private TupleBinding theBinding; public FullNameKeyCreator(TupleBinding theBinding) { self.theBinding = theBinding; } public boolean createSecondaryKey(SecondaryDatabase secDb, DatabaseEntry keyEntry, DatabaseEntry dataEntry, DatabaseEntry resultEntry) { // If the dataEntry parameter is null, then we can // not create the key if (dataEntry == null) { return false; } else { // Create the key try { PersonData pd = (PersonData) theBinding.entryToObject(dataEntry); String fullName = pd.getFamiliarName() + " " + pd.getSurname(); resultEntry.setData(fullName.getBytes("UTF-8")); return true; } catch (IOException willNeverOccur) {} } } }
Finally, you use this key creator as follows:
import com.sleepycat.je.Database; import com.sleepycat.je.DatabaseException; import com.sleepycat.je.SecondaryDatabase; import com.sleepycat.je.SecondaryConfig; import com.sleepycat.bind.tuple.TupleBinding; ... // Environment and primary database open omitted for brevity ... TupleBinding myDataBinding = new PersonDataBinding(); ... FullNameKeyCreator fnkc = new FullNameKeyCreator(myDataBinding); SecondaryConfig mySecConfig = new SecondaryConfig(); mySecConfig.setKeyCreator(fnkc); try { //Perform the actual open String secDbName = "mySecondaryDatabase"; SecondaryDatabase mySecDb = myEnv.openSecondaryDatabase(null, secDbName, myDb, mySecConfig); } catch (DatabaseException de) { // Exception handling goes here }