summaryrefslogtreecommitdiff
path: root/examples_java/src/collections/ship
diff options
context:
space:
mode:
authorZhang Qiang <qiang.z.zhang@intel.com>2012-05-29 12:22:00 +0800
committerZhang Qiang <qiang.z.zhang@intel.com>2012-05-29 12:22:00 +0800
commit02f0634ac29e19c68279e5544cac963e7f1203b8 (patch)
treeb983472f94ef063cedf866d8ecfb55939171779d /examples_java/src/collections/ship
parente776056ea09ba0b6d9505ced6913c9190a12d632 (diff)
downloaddb4-2.0alpha.tar.gz
db4-2.0alpha.tar.bz2
db4-2.0alpha.zip
Sync source code from Tizen:BaseHEAD2.0_alphamaster2.0alpha1.0_post
Diffstat (limited to 'examples_java/src/collections/ship')
-rw-r--r--examples_java/src/collections/ship/basic/PartData.java64
-rw-r--r--examples_java/src/collections/ship/basic/PartKey.java40
-rw-r--r--examples_java/src/collections/ship/basic/Sample.java254
-rw-r--r--examples_java/src/collections/ship/basic/SampleDatabase.java134
-rw-r--r--examples_java/src/collections/ship/basic/SampleViews.java122
-rw-r--r--examples_java/src/collections/ship/basic/ShipmentData.java41
-rw-r--r--examples_java/src/collections/ship/basic/ShipmentKey.java48
-rw-r--r--examples_java/src/collections/ship/basic/SupplierData.java57
-rw-r--r--examples_java/src/collections/ship/basic/SupplierKey.java40
-rw-r--r--examples_java/src/collections/ship/basic/Weight.java49
-rw-r--r--examples_java/src/collections/ship/entity/Part.java72
-rw-r--r--examples_java/src/collections/ship/entity/PartData.java65
-rw-r--r--examples_java/src/collections/ship/entity/PartKey.java40
-rw-r--r--examples_java/src/collections/ship/entity/Sample.java236
-rw-r--r--examples_java/src/collections/ship/entity/SampleDatabase.java331
-rw-r--r--examples_java/src/collections/ship/entity/SampleViews.java306
-rw-r--r--examples_java/src/collections/ship/entity/Shipment.java55
-rw-r--r--examples_java/src/collections/ship/entity/ShipmentData.java42
-rw-r--r--examples_java/src/collections/ship/entity/ShipmentKey.java48
-rw-r--r--examples_java/src/collections/ship/entity/Supplier.java63
-rw-r--r--examples_java/src/collections/ship/entity/SupplierData.java58
-rw-r--r--examples_java/src/collections/ship/entity/SupplierKey.java40
-rw-r--r--examples_java/src/collections/ship/entity/Weight.java49
-rw-r--r--examples_java/src/collections/ship/factory/Part.java106
-rw-r--r--examples_java/src/collections/ship/factory/PartKey.java60
-rw-r--r--examples_java/src/collections/ship/factory/Sample.java234
-rw-r--r--examples_java/src/collections/ship/factory/SampleDatabase.java226
-rw-r--r--examples_java/src/collections/ship/factory/SampleViews.java142
-rw-r--r--examples_java/src/collections/ship/factory/Shipment.java102
-rw-r--r--examples_java/src/collections/ship/factory/ShipmentKey.java70
-rw-r--r--examples_java/src/collections/ship/factory/Supplier.java108
-rw-r--r--examples_java/src/collections/ship/factory/SupplierKey.java60
-rw-r--r--examples_java/src/collections/ship/factory/Weight.java49
-rw-r--r--examples_java/src/collections/ship/index/PartData.java64
-rw-r--r--examples_java/src/collections/ship/index/PartKey.java40
-rw-r--r--examples_java/src/collections/ship/index/Sample.java278
-rw-r--r--examples_java/src/collections/ship/index/SampleDatabase.java331
-rw-r--r--examples_java/src/collections/ship/index/SampleViews.java161
-rw-r--r--examples_java/src/collections/ship/index/ShipmentData.java41
-rw-r--r--examples_java/src/collections/ship/index/ShipmentKey.java48
-rw-r--r--examples_java/src/collections/ship/index/SupplierData.java57
-rw-r--r--examples_java/src/collections/ship/index/SupplierKey.java40
-rw-r--r--examples_java/src/collections/ship/index/Weight.java49
-rw-r--r--examples_java/src/collections/ship/marshal/MarshalledEnt.java42
-rw-r--r--examples_java/src/collections/ship/marshal/MarshalledKey.java36
-rw-r--r--examples_java/src/collections/ship/marshal/Part.java116
-rw-r--r--examples_java/src/collections/ship/marshal/PartKey.java59
-rw-r--r--examples_java/src/collections/ship/marshal/Sample.java236
-rw-r--r--examples_java/src/collections/ship/marshal/SampleDatabase.java260
-rw-r--r--examples_java/src/collections/ship/marshal/SampleViews.java276
-rw-r--r--examples_java/src/collections/ship/marshal/Shipment.java113
-rw-r--r--examples_java/src/collections/ship/marshal/ShipmentKey.java69
-rw-r--r--examples_java/src/collections/ship/marshal/Supplier.java118
-rw-r--r--examples_java/src/collections/ship/marshal/SupplierKey.java59
-rw-r--r--examples_java/src/collections/ship/marshal/Weight.java49
-rw-r--r--examples_java/src/collections/ship/sentity/Part.java90
-rw-r--r--examples_java/src/collections/ship/sentity/PartKey.java38
-rw-r--r--examples_java/src/collections/ship/sentity/Sample.java249
-rw-r--r--examples_java/src/collections/ship/sentity/SampleDatabase.java323
-rw-r--r--examples_java/src/collections/ship/sentity/SampleViews.java419
-rw-r--r--examples_java/src/collections/ship/sentity/Shipment.java75
-rw-r--r--examples_java/src/collections/ship/sentity/ShipmentKey.java46
-rw-r--r--examples_java/src/collections/ship/sentity/Supplier.java82
-rw-r--r--examples_java/src/collections/ship/sentity/SupplierKey.java38
-rw-r--r--examples_java/src/collections/ship/sentity/Weight.java49
-rw-r--r--examples_java/src/collections/ship/tuple/Part.java72
-rw-r--r--examples_java/src/collections/ship/tuple/PartData.java65
-rw-r--r--examples_java/src/collections/ship/tuple/PartKey.java38
-rw-r--r--examples_java/src/collections/ship/tuple/Sample.java235
-rw-r--r--examples_java/src/collections/ship/tuple/SampleDatabase.java323
-rw-r--r--examples_java/src/collections/ship/tuple/SampleViews.java396
-rw-r--r--examples_java/src/collections/ship/tuple/Shipment.java55
-rw-r--r--examples_java/src/collections/ship/tuple/ShipmentData.java42
-rw-r--r--examples_java/src/collections/ship/tuple/ShipmentKey.java46
-rw-r--r--examples_java/src/collections/ship/tuple/Supplier.java63
-rw-r--r--examples_java/src/collections/ship/tuple/SupplierData.java58
-rw-r--r--examples_java/src/collections/ship/tuple/SupplierKey.java38
-rw-r--r--examples_java/src/collections/ship/tuple/Weight.java49
78 files changed, 8842 insertions, 0 deletions
diff --git a/examples_java/src/collections/ship/basic/PartData.java b/examples_java/src/collections/ship/basic/PartData.java
new file mode 100644
index 0000000..316a56d
--- /dev/null
+++ b/examples_java/src/collections/ship/basic/PartData.java
@@ -0,0 +1,64 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.basic;
+
+import java.io.Serializable;
+
+/**
+ * A PartData serves as the data in the key/data pair for a part entity.
+ *
+ * <p> In this sample, PartData is used both as the storage entry for the
+ * data as well as the object binding to the data. Because it is used
+ * directly as storage data using serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class PartData implements Serializable {
+
+ private String name;
+ private String color;
+ private Weight weight;
+ private String city;
+
+ public PartData(String name, String color, Weight weight, String city) {
+
+ this.name = name;
+ this.color = color;
+ this.weight = weight;
+ this.city = city;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final String getColor() {
+
+ return color;
+ }
+
+ public final Weight getWeight() {
+
+ return weight;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[PartData: name=" + name +
+ " color=" + color +
+ " weight=" + weight +
+ " city=" + city + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/basic/PartKey.java b/examples_java/src/collections/ship/basic/PartKey.java
new file mode 100644
index 0000000..851362f
--- /dev/null
+++ b/examples_java/src/collections/ship/basic/PartKey.java
@@ -0,0 +1,40 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.basic;
+
+import java.io.Serializable;
+
+/**
+ * A PartKey serves as the key in the key/data pair for a part entity.
+ *
+ * <p> In this sample, PartKey is used both as the storage entry for the key as
+ * well as the object binding to the key. Because it is used directly as
+ * storage data using serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class PartKey implements Serializable {
+
+ private String number;
+
+ public PartKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public String toString() {
+
+ return "[PartKey: number=" + number + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/basic/Sample.java b/examples_java/src/collections/ship/basic/Sample.java
new file mode 100644
index 0000000..7413cf8
--- /dev/null
+++ b/examples_java/src/collections/ship/basic/Sample.java
@@ -0,0 +1,254 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.basic;
+
+import java.io.FileNotFoundException;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.sleepycat.collections.TransactionRunner;
+import com.sleepycat.collections.TransactionWorker;
+import com.sleepycat.db.DatabaseException;
+
+/**
+ * Sample is the main entry point for the sample program and may be run as
+ * follows:
+ *
+ * <pre>
+ * java collections.ship.basic.Sample
+ * [-h <home-directory> ]
+ * </pre>
+ *
+ * <p> The default for the home directory is ./tmp -- the tmp subdirectory of
+ * the current directory where the sample is run. The home directory must exist
+ * before running the sample. To recreate the sample database from scratch,
+ * delete all files in the home directory before running the sample. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Sample {
+
+ private SampleDatabase db;
+ private SampleViews views;
+
+ /**
+ * Run the sample program.
+ */
+ public static void main(String[] args) {
+
+ System.out.println("\nRunning sample: " + Sample.class);
+
+ // Parse the command line arguments.
+ //
+ String homeDir = "./tmp";
+ for (int i = 0; i < args.length; i += 1) {
+ if (args[i].equals("-h") && i < args.length - 1) {
+ i += 1;
+ homeDir = args[i];
+ } else {
+ System.err.println("Usage:\n java " + Sample.class.getName() +
+ "\n [-h <home-directory>]");
+ System.exit(2);
+ }
+ }
+
+ // Run the sample.
+ //
+ Sample sample = null;
+ try {
+ sample = new Sample(homeDir);
+ sample.run();
+ } catch (Exception e) {
+ // If an exception reaches this point, the last transaction did not
+ // complete. If the exception is RunRecoveryException, follow
+ // the Berkeley DB recovery procedures before running again.
+ e.printStackTrace();
+ } finally {
+ if (sample != null) {
+ try {
+ // Always attempt to close the database cleanly.
+ sample.close();
+ } catch (Exception e) {
+ System.err.println("Exception during database close:");
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Open the database and views.
+ */
+ private Sample(String homeDir)
+ throws DatabaseException, FileNotFoundException {
+
+ db = new SampleDatabase(homeDir);
+ views = new SampleViews(db);
+ }
+
+ /**
+ * Close the database cleanly.
+ */
+ private void close()
+ throws DatabaseException {
+
+ db.close();
+ }
+
+ /**
+ * Run two transactions to populate and print the database. A
+ * TransactionRunner is used to ensure consistent handling of transactions,
+ * including deadlock retries. But the best transaction handling mechanism
+ * to use depends on the application.
+ */
+ private void run()
+ throws Exception {
+
+ TransactionRunner runner = new TransactionRunner(db.getEnvironment());
+ runner.run(new PopulateDatabase());
+ runner.run(new PrintDatabase());
+ }
+
+ /**
+ * Populate the database in a single transaction.
+ */
+ private class PopulateDatabase implements TransactionWorker {
+
+ public void doWork()
+ throws Exception {
+ addSuppliers();
+ addParts();
+ addShipments();
+ }
+ }
+
+ /**
+ * Print the database in a single transaction. All entities are printed.
+ */
+ private class PrintDatabase implements TransactionWorker {
+
+ public void doWork()
+ throws Exception {
+ printEntries("Parts",
+ views.getPartEntrySet().iterator());
+ printEntries("Suppliers",
+ views.getSupplierEntrySet().iterator());
+ printEntries("Shipments",
+ views.getShipmentEntrySet().iterator());
+ }
+ }
+
+ /**
+ * Populate the part entities in the database. If the part map is not
+ * empty, assume that this has already been done.
+ */
+ private void addParts() {
+
+ Map parts = views.getPartMap();
+ if (parts.isEmpty()) {
+ System.out.println("Adding Parts");
+ parts.put(new PartKey("P1"),
+ new PartData("Nut", "Red",
+ new Weight(12.0, Weight.GRAMS),
+ "London"));
+ parts.put(new PartKey("P2"),
+ new PartData("Bolt", "Green",
+ new Weight(17.0, Weight.GRAMS),
+ "Paris"));
+ parts.put(new PartKey("P3"),
+ new PartData("Screw", "Blue",
+ new Weight(17.0, Weight.GRAMS),
+ "Rome"));
+ parts.put(new PartKey("P4"),
+ new PartData("Screw", "Red",
+ new Weight(14.0, Weight.GRAMS),
+ "London"));
+ parts.put(new PartKey("P5"),
+ new PartData("Cam", "Blue",
+ new Weight(12.0, Weight.GRAMS),
+ "Paris"));
+ parts.put(new PartKey("P6"),
+ new PartData("Cog", "Red",
+ new Weight(19.0, Weight.GRAMS),
+ "London"));
+ }
+ }
+
+ /**
+ * Populate the supplier entities in the database. If the supplier map is
+ * not empty, assume that this has already been done.
+ */
+ private void addSuppliers() {
+
+ Map suppliers = views.getSupplierMap();
+ if (suppliers.isEmpty()) {
+ System.out.println("Adding Suppliers");
+ suppliers.put(new SupplierKey("S1"),
+ new SupplierData("Smith", 20, "London"));
+ suppliers.put(new SupplierKey("S2"),
+ new SupplierData("Jones", 10, "Paris"));
+ suppliers.put(new SupplierKey("S3"),
+ new SupplierData("Blake", 30, "Paris"));
+ suppliers.put(new SupplierKey("S4"),
+ new SupplierData("Clark", 20, "London"));
+ suppliers.put(new SupplierKey("S5"),
+ new SupplierData("Adams", 30, "Athens"));
+ }
+ }
+
+ /**
+ * Populate the shipment entities in the database. If the shipment map
+ * is not empty, assume that this has already been done.
+ */
+ private void addShipments() {
+
+ Map shipments = views.getShipmentMap();
+ if (shipments.isEmpty()) {
+ System.out.println("Adding Shipments");
+ shipments.put(new ShipmentKey("P1", "S1"),
+ new ShipmentData(300));
+ shipments.put(new ShipmentKey("P2", "S1"),
+ new ShipmentData(200));
+ shipments.put(new ShipmentKey("P3", "S1"),
+ new ShipmentData(400));
+ shipments.put(new ShipmentKey("P4", "S1"),
+ new ShipmentData(200));
+ shipments.put(new ShipmentKey("P5", "S1"),
+ new ShipmentData(100));
+ shipments.put(new ShipmentKey("P6", "S1"),
+ new ShipmentData(100));
+ shipments.put(new ShipmentKey("P1", "S2"),
+ new ShipmentData(300));
+ shipments.put(new ShipmentKey("P2", "S2"),
+ new ShipmentData(400));
+ shipments.put(new ShipmentKey("P2", "S3"),
+ new ShipmentData(200));
+ shipments.put(new ShipmentKey("P2", "S4"),
+ new ShipmentData(200));
+ shipments.put(new ShipmentKey("P4", "S4"),
+ new ShipmentData(300));
+ shipments.put(new ShipmentKey("P5", "S4"),
+ new ShipmentData(400));
+ }
+ }
+
+ /**
+ * Print the key/value objects returned by an iterator of Map.Entry
+ * objects.
+ */
+ private void printEntries(String label, Iterator iterator) {
+
+ System.out.println("\n--- " + label + " ---");
+ while (iterator.hasNext()) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ System.out.println(entry.getKey().toString());
+ System.out.println(entry.getValue().toString());
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/basic/SampleDatabase.java b/examples_java/src/collections/ship/basic/SampleDatabase.java
new file mode 100644
index 0000000..47fff2c
--- /dev/null
+++ b/examples_java/src/collections/ship/basic/SampleDatabase.java
@@ -0,0 +1,134 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.basic;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import com.sleepycat.bind.serial.StoredClassCatalog;
+import com.sleepycat.db.Database;
+import com.sleepycat.db.DatabaseConfig;
+import com.sleepycat.db.DatabaseException;
+import com.sleepycat.db.DatabaseType;
+import com.sleepycat.db.Environment;
+import com.sleepycat.db.EnvironmentConfig;
+
+/**
+ * SampleDatabase defines the storage containers, indices and foreign keys
+ * for the sample database.
+ *
+ * @author Mark Hayes
+ */
+public class SampleDatabase {
+
+ private static final String CLASS_CATALOG = "java_class_catalog";
+ private static final String SUPPLIER_STORE = "supplier_store";
+ private static final String PART_STORE = "part_store";
+ private static final String SHIPMENT_STORE = "shipment_store";
+
+ private Environment env;
+ private Database partDb;
+ private Database supplierDb;
+ private Database shipmentDb;
+ private StoredClassCatalog javaCatalog;
+
+ /**
+ * Open all storage containers, indices, and catalogs.
+ */
+ public SampleDatabase(String homeDirectory)
+ throws DatabaseException, FileNotFoundException {
+
+ // Open the Berkeley DB environment in transactional mode.
+ //
+ System.out.println("Opening environment in: " + homeDirectory);
+ EnvironmentConfig envConfig = new EnvironmentConfig();
+ envConfig.setTransactional(true);
+ envConfig.setAllowCreate(true);
+ envConfig.setInitializeCache(true);
+ envConfig.setInitializeLocking(true);
+ env = new Environment(new File(homeDirectory), envConfig);
+
+ // Set the Berkeley DB config for opening all stores.
+ //
+ DatabaseConfig dbConfig = new DatabaseConfig();
+ dbConfig.setTransactional(true);
+ dbConfig.setAllowCreate(true);
+ dbConfig.setType(DatabaseType.BTREE);
+
+ // Create the Serial class catalog. This holds the serialized class
+ // format for all database records of serial format.
+ //
+ Database catalogDb = env.openDatabase(null, CLASS_CATALOG, null,
+ dbConfig);
+ javaCatalog = new StoredClassCatalog(catalogDb);
+
+ // Open the Berkeley DB database for the part, supplier and shipment
+ // stores. The stores are opened with no duplicate keys allowed.
+ //
+ partDb = env.openDatabase(null, PART_STORE, null, dbConfig);
+
+ supplierDb = env.openDatabase(null, SUPPLIER_STORE, null, dbConfig);
+
+ shipmentDb = env.openDatabase(null, SHIPMENT_STORE, null, dbConfig);
+ }
+
+ /**
+ * Return the storage environment for the database.
+ */
+ public final Environment getEnvironment() {
+
+ return env;
+ }
+
+ /**
+ * Return the class catalog.
+ */
+ public final StoredClassCatalog getClassCatalog() {
+
+ return javaCatalog;
+ }
+
+ /**
+ * Return the part storage container.
+ */
+ public final Database getPartDatabase() {
+
+ return partDb;
+ }
+
+ /**
+ * Return the supplier storage container.
+ */
+ public final Database getSupplierDatabase() {
+
+ return supplierDb;
+ }
+
+ /**
+ * Return the shipment storage container.
+ */
+ public final Database getShipmentDatabase() {
+
+ return shipmentDb;
+ }
+
+ /**
+ * Close all databases and the environment.
+ */
+ public void close()
+ throws DatabaseException {
+
+ partDb.close();
+ supplierDb.close();
+ shipmentDb.close();
+ // And don't forget to close the catalog and the environment.
+ javaCatalog.close();
+ env.close();
+ }
+}
diff --git a/examples_java/src/collections/ship/basic/SampleViews.java b/examples_java/src/collections/ship/basic/SampleViews.java
new file mode 100644
index 0000000..97c1192
--- /dev/null
+++ b/examples_java/src/collections/ship/basic/SampleViews.java
@@ -0,0 +1,122 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.basic;
+
+import com.sleepycat.bind.EntryBinding;
+import com.sleepycat.bind.serial.ClassCatalog;
+import com.sleepycat.bind.serial.SerialBinding;
+import com.sleepycat.collections.StoredEntrySet;
+import com.sleepycat.collections.StoredMap;
+
+/**
+ * SampleViews defines the data bindings and collection views for the sample
+ * database.
+ *
+ * @author Mark Hayes
+ */
+public class SampleViews {
+
+ private StoredMap partMap;
+ private StoredMap supplierMap;
+ private StoredMap shipmentMap;
+
+ /**
+ * Create the data bindings and collection views.
+ */
+ public SampleViews(SampleDatabase db) {
+
+ // In this sample, the stored key and data entries are used directly
+ // rather than mapping them to separate objects. Therefore, no binding
+ // classes are defined here and the SerialBinding class is used.
+ //
+ ClassCatalog catalog = db.getClassCatalog();
+ EntryBinding partKeyBinding =
+ new SerialBinding(catalog, PartKey.class);
+ EntryBinding partDataBinding =
+ new SerialBinding(catalog, PartData.class);
+ EntryBinding supplierKeyBinding =
+ new SerialBinding(catalog, SupplierKey.class);
+ EntryBinding supplierDataBinding =
+ new SerialBinding(catalog, SupplierData.class);
+ EntryBinding shipmentKeyBinding =
+ new SerialBinding(catalog, ShipmentKey.class);
+ EntryBinding shipmentDataBinding =
+ new SerialBinding(catalog, ShipmentData.class);
+
+ // Create map views for all stores and indices.
+ // StoredSortedMap is not used since the stores and indices are
+ // ordered by serialized key objects, which do not provide a very
+ // useful ordering.
+ //
+ partMap =
+ new StoredMap(db.getPartDatabase(),
+ partKeyBinding, partDataBinding, true);
+ supplierMap =
+ new StoredMap(db.getSupplierDatabase(),
+ supplierKeyBinding, supplierDataBinding, true);
+ shipmentMap =
+ new StoredMap(db.getShipmentDatabase(),
+ shipmentKeyBinding, shipmentDataBinding, true);
+ }
+
+ // The views returned below can be accessed using the java.util.Map or
+ // java.util.Set interfaces, or using the StoredMap and StoredEntrySet
+ // classes, which provide additional methods. The entry sets could be
+ // obtained directly from the Map.entrySet() method, but convenience
+ // methods are provided here to return them in order to avoid down-casting
+ // elsewhere.
+
+ /**
+ * Return a map view of the part storage container.
+ */
+ public final StoredMap getPartMap() {
+
+ return partMap;
+ }
+
+ /**
+ * Return a map view of the supplier storage container.
+ */
+ public final StoredMap getSupplierMap() {
+
+ return supplierMap;
+ }
+
+ /**
+ * Return a map view of the shipment storage container.
+ */
+ public final StoredMap getShipmentMap() {
+
+ return shipmentMap;
+ }
+
+ /**
+ * Return an entry set view of the part storage container.
+ */
+ public final StoredEntrySet getPartEntrySet() {
+
+ return (StoredEntrySet) partMap.entrySet();
+ }
+
+ /**
+ * Return an entry set view of the supplier storage container.
+ */
+ public final StoredEntrySet getSupplierEntrySet() {
+
+ return (StoredEntrySet) supplierMap.entrySet();
+ }
+
+ /**
+ * Return an entry set view of the shipment storage container.
+ */
+ public final StoredEntrySet getShipmentEntrySet() {
+
+ return (StoredEntrySet) shipmentMap.entrySet();
+ }
+}
diff --git a/examples_java/src/collections/ship/basic/ShipmentData.java b/examples_java/src/collections/ship/basic/ShipmentData.java
new file mode 100644
index 0000000..96f3336
--- /dev/null
+++ b/examples_java/src/collections/ship/basic/ShipmentData.java
@@ -0,0 +1,41 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.basic;
+
+import java.io.Serializable;
+
+/**
+ * A ShipmentData serves as the data in the key/data pair for a shipment
+ * entity.
+ *
+ * <p> In this sample, ShipmentData is used both as the storage entry for the
+ * data as well as the object binding to the data. Because it is used
+ * directly as storage data using serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class ShipmentData implements Serializable {
+
+ private int quantity;
+
+ public ShipmentData(int quantity) {
+
+ this.quantity = quantity;
+ }
+
+ public final int getQuantity() {
+
+ return quantity;
+ }
+
+ public String toString() {
+
+ return "[ShipmentData: quantity=" + quantity + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/basic/ShipmentKey.java b/examples_java/src/collections/ship/basic/ShipmentKey.java
new file mode 100644
index 0000000..2dab3dc
--- /dev/null
+++ b/examples_java/src/collections/ship/basic/ShipmentKey.java
@@ -0,0 +1,48 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.basic;
+
+import java.io.Serializable;
+
+/**
+ * A ShipmentKey serves as the key in the key/data pair for a shipment entity.
+ *
+ * <p> In this sample, ShipmentKey is used both as the storage entry for the
+ * key as well as the object binding to the key. Because it is used directly
+ * as storage data using serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class ShipmentKey implements Serializable {
+
+ private String partNumber;
+ private String supplierNumber;
+
+ public ShipmentKey(String partNumber, String supplierNumber) {
+
+ this.partNumber = partNumber;
+ this.supplierNumber = supplierNumber;
+ }
+
+ public final String getPartNumber() {
+
+ return partNumber;
+ }
+
+ public final String getSupplierNumber() {
+
+ return supplierNumber;
+ }
+
+ public String toString() {
+
+ return "[ShipmentKey: supplier=" + supplierNumber +
+ " part=" + partNumber + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/basic/SupplierData.java b/examples_java/src/collections/ship/basic/SupplierData.java
new file mode 100644
index 0000000..0853f23
--- /dev/null
+++ b/examples_java/src/collections/ship/basic/SupplierData.java
@@ -0,0 +1,57 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.basic;
+
+import java.io.Serializable;
+
+/**
+ * A SupplierData serves as the data in the key/data pair for a supplier
+ * entity.
+ *
+ * <p> In this sample, SupplierData is used both as the storage entry for the
+ * data as well as the object binding to the data. Because it is used
+ * directly as storage data using serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class SupplierData implements Serializable {
+
+ private String name;
+ private int status;
+ private String city;
+
+ public SupplierData(String name, int status, String city) {
+
+ this.name = name;
+ this.status = status;
+ this.city = city;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final int getStatus() {
+
+ return status;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[SupplierData: name=" + name +
+ " status=" + status +
+ " city=" + city + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/basic/SupplierKey.java b/examples_java/src/collections/ship/basic/SupplierKey.java
new file mode 100644
index 0000000..6f16a1b
--- /dev/null
+++ b/examples_java/src/collections/ship/basic/SupplierKey.java
@@ -0,0 +1,40 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.basic;
+
+import java.io.Serializable;
+
+/**
+ * A SupplierKey serves as the key in the key/data pair for a supplier entity.
+ *
+ * <p>In this sample, SupplierKey is used both as the storage entry for the key
+ * as well as the object binding to the key. Because it is used directly as
+ * storage data using serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class SupplierKey implements Serializable {
+
+ private String number;
+
+ public SupplierKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public String toString() {
+
+ return "[SupplierKey: number=" + number + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/basic/Weight.java b/examples_java/src/collections/ship/basic/Weight.java
new file mode 100644
index 0000000..f5303fa
--- /dev/null
+++ b/examples_java/src/collections/ship/basic/Weight.java
@@ -0,0 +1,49 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.basic;
+
+import java.io.Serializable;
+
+/**
+ * Weight represents a weight amount and unit of measure.
+ *
+ * <p> In this sample, Weight is embedded in part data values which are stored
+ * as Serial serialized objects; therefore Weight must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Weight implements Serializable {
+
+ public final static String GRAMS = "grams";
+ public final static String OUNCES = "ounces";
+
+ private double amount;
+ private String units;
+
+ public Weight(double amount, String units) {
+
+ this.amount = amount;
+ this.units = units;
+ }
+
+ public final double getAmount() {
+
+ return amount;
+ }
+
+ public final String getUnits() {
+
+ return units;
+ }
+
+ public String toString() {
+
+ return "[" + amount + ' ' + units + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/entity/Part.java b/examples_java/src/collections/ship/entity/Part.java
new file mode 100644
index 0000000..68051fa
--- /dev/null
+++ b/examples_java/src/collections/ship/entity/Part.java
@@ -0,0 +1,72 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.entity;
+
+/**
+ * A Part represents the combined key/data pair for a part entity.
+ *
+ * <p>In this sample, Part is created from the stored key/data entry using a
+ * SerialSerialBinding. See {@link SampleViews.PartBinding} for details.
+ * Since this class is not used directly for data storage, it does not need to
+ * be Serializable.</p>
+ *
+ * @author Mark Hayes
+ */
+public class Part {
+
+ private String number;
+ private String name;
+ private String color;
+ private Weight weight;
+ private String city;
+
+ public Part(String number, String name, String color, Weight weight,
+ String city) {
+
+ this.number = number;
+ this.name = name;
+ this.color = color;
+ this.weight = weight;
+ this.city = city;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final String getColor() {
+
+ return color;
+ }
+
+ public final Weight getWeight() {
+
+ return weight;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[Part: number=" + number +
+ " name=" + name +
+ " color=" + color +
+ " weight=" + weight +
+ " city=" + city + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/entity/PartData.java b/examples_java/src/collections/ship/entity/PartData.java
new file mode 100644
index 0000000..b61bb0a
--- /dev/null
+++ b/examples_java/src/collections/ship/entity/PartData.java
@@ -0,0 +1,65 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.entity;
+
+import java.io.Serializable;
+
+/**
+ * A PartData serves as the value in the key/value pair for a part entity.
+ *
+ * <p> In this sample, PartData is used only as the storage data for the
+ * value, while the Part object is used as the value's object representation.
+ * Because it is used directly as storage data using serial format, it must be
+ * Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class PartData implements Serializable {
+
+ private String name;
+ private String color;
+ private Weight weight;
+ private String city;
+
+ public PartData(String name, String color, Weight weight, String city) {
+
+ this.name = name;
+ this.color = color;
+ this.weight = weight;
+ this.city = city;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final String getColor() {
+
+ return color;
+ }
+
+ public final Weight getWeight() {
+
+ return weight;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[PartData: name=" + name +
+ " color=" + color +
+ " weight=" + weight +
+ " city=" + city + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/entity/PartKey.java b/examples_java/src/collections/ship/entity/PartKey.java
new file mode 100644
index 0000000..b37fc40
--- /dev/null
+++ b/examples_java/src/collections/ship/entity/PartKey.java
@@ -0,0 +1,40 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.entity;
+
+import java.io.Serializable;
+
+/**
+ * A PartKey serves as the key in the key/data pair for a part entity.
+ *
+ * <p> In this sample, PartKey is used both as the storage entry for the key as
+ * well as the object binding to the key. Because it is used directly as
+ * storage data using serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class PartKey implements Serializable {
+
+ private String number;
+
+ public PartKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public String toString() {
+
+ return "[PartKey: number=" + number + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/entity/Sample.java b/examples_java/src/collections/ship/entity/Sample.java
new file mode 100644
index 0000000..207a5e1
--- /dev/null
+++ b/examples_java/src/collections/ship/entity/Sample.java
@@ -0,0 +1,236 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.entity;
+
+import java.io.FileNotFoundException;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.sleepycat.collections.TransactionRunner;
+import com.sleepycat.collections.TransactionWorker;
+import com.sleepycat.db.DatabaseException;
+
+/**
+ * Sample is the main entry point for the sample program and may be run as
+ * follows:
+ *
+ * <pre>
+ * java collections.ship.entity.Sample
+ * [-h <home-directory> ]
+ * </pre>
+ *
+ * <p> The default for the home directory is ./tmp -- the tmp subdirectory of
+ * the current directory where the sample is run. The home directory must exist
+ * before running the sample. To recreate the sample database from scratch,
+ * delete all files in the home directory before running the sample. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Sample {
+
+ private SampleDatabase db;
+ private SampleViews views;
+
+ /**
+ * Run the sample program.
+ */
+ public static void main(String[] args) {
+
+ System.out.println("\nRunning sample: " + Sample.class);
+
+ // Parse the command line arguments.
+ //
+ String homeDir = "./tmp";
+ for (int i = 0; i < args.length; i += 1) {
+ if (args[i].equals("-h") && i < args.length - 1) {
+ i += 1;
+ homeDir = args[i];
+ } else {
+ System.err.println("Usage:\n java " + Sample.class.getName() +
+ "\n [-h <home-directory>]");
+ System.exit(2);
+ }
+ }
+
+ // Run the sample.
+ //
+ Sample sample = null;
+ try {
+ sample = new Sample(homeDir);
+ sample.run();
+ } catch (Exception e) {
+ // If an exception reaches this point, the last transaction did not
+ // complete. If the exception is RunRecoveryException, follow
+ // the Berkeley DB recovery procedures before running again.
+ e.printStackTrace();
+ } finally {
+ if (sample != null) {
+ try {
+ // Always attempt to close the database cleanly.
+ sample.close();
+ } catch (Exception e) {
+ System.err.println("Exception during database close:");
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Open the database and views.
+ */
+ private Sample(String homeDir)
+ throws DatabaseException, FileNotFoundException {
+
+ db = new SampleDatabase(homeDir);
+ views = new SampleViews(db);
+ }
+
+ /**
+ * Close the database cleanly.
+ */
+ private void close()
+ throws DatabaseException {
+
+ db.close();
+ }
+
+ /**
+ * Run two transactions to populate and print the database. A
+ * TransactionRunner is used to ensure consistent handling of transactions,
+ * including deadlock retries. But the best transaction handling mechanism
+ * to use depends on the application.
+ */
+ private void run()
+ throws Exception {
+
+ TransactionRunner runner = new TransactionRunner(db.getEnvironment());
+ runner.run(new PopulateDatabase());
+ runner.run(new PrintDatabase());
+ }
+
+ /**
+ * Populate the database in a single transaction.
+ */
+ private class PopulateDatabase implements TransactionWorker {
+
+ public void doWork()
+ throws Exception {
+ addSuppliers();
+ addParts();
+ addShipments();
+ }
+ }
+
+ /**
+ * Print the database in a single transaction. All entities are printed
+ * and the indices are used to print the entities for certain keys.
+ *
+ * <p> Note the use of special iterator() methods. These are used here
+ * with indices to find the shipments for certain keys.</p>
+ */
+ private class PrintDatabase implements TransactionWorker {
+
+
+ public void doWork()
+ throws Exception {
+ printValues("Parts",
+ views.getPartSet().iterator());
+ printValues("Suppliers",
+ views.getSupplierSet().iterator());
+ printValues("Suppliers for City Paris",
+ views.getSupplierByCityMap().duplicates(
+ "Paris").iterator());
+ printValues("Shipments",
+ views.getShipmentSet().iterator());
+ printValues("Shipments for Part P1",
+ views.getShipmentByPartMap().duplicates(
+ new PartKey("P1")).iterator());
+ printValues("Shipments for Supplier S1",
+ views.getShipmentBySupplierMap().duplicates(
+ new SupplierKey("S1")).iterator());
+ }
+ }
+
+ /**
+ * Populate the part entities in the database. If the part set is not
+ * empty, assume that this has already been done.
+ */
+ private void addParts() {
+
+ Set parts = views.getPartSet();
+ if (parts.isEmpty()) {
+ System.out.println("Adding Parts");
+ parts.add(new Part("P1", "Nut", "Red",
+ new Weight(12.0, Weight.GRAMS), "London"));
+ parts.add(new Part("P2", "Bolt", "Green",
+ new Weight(17.0, Weight.GRAMS), "Paris"));
+ parts.add(new Part("P3", "Screw", "Blue",
+ new Weight(17.0, Weight.GRAMS), "Rome"));
+ parts.add(new Part("P4", "Screw", "Red",
+ new Weight(14.0, Weight.GRAMS), "London"));
+ parts.add(new Part("P5", "Cam", "Blue",
+ new Weight(12.0, Weight.GRAMS), "Paris"));
+ parts.add(new Part("P6", "Cog", "Red",
+ new Weight(19.0, Weight.GRAMS), "London"));
+ }
+ }
+
+ /**
+ * Populate the supplier entities in the database. If the supplier set is
+ * not empty, assume that this has already been done.
+ */
+ private void addSuppliers() {
+
+ Set suppliers = views.getSupplierSet();
+ if (suppliers.isEmpty()) {
+ System.out.println("Adding Suppliers");
+ suppliers.add(new Supplier("S1", "Smith", 20, "London"));
+ suppliers.add(new Supplier("S2", "Jones", 10, "Paris"));
+ suppliers.add(new Supplier("S3", "Blake", 30, "Paris"));
+ suppliers.add(new Supplier("S4", "Clark", 20, "London"));
+ suppliers.add(new Supplier("S5", "Adams", 30, "Athens"));
+ }
+ }
+
+ /**
+ * Populate the shipment entities in the database. If the shipment set
+ * is not empty, assume that this has already been done.
+ */
+ private void addShipments() {
+
+ Set shipments = views.getShipmentSet();
+ if (shipments.isEmpty()) {
+ System.out.println("Adding Shipments");
+ shipments.add(new Shipment("P1", "S1", 300));
+ shipments.add(new Shipment("P2", "S1", 200));
+ shipments.add(new Shipment("P3", "S1", 400));
+ shipments.add(new Shipment("P4", "S1", 200));
+ shipments.add(new Shipment("P5", "S1", 100));
+ shipments.add(new Shipment("P6", "S1", 100));
+ shipments.add(new Shipment("P1", "S2", 300));
+ shipments.add(new Shipment("P2", "S2", 400));
+ shipments.add(new Shipment("P2", "S3", 200));
+ shipments.add(new Shipment("P2", "S4", 200));
+ shipments.add(new Shipment("P4", "S4", 300));
+ shipments.add(new Shipment("P5", "S4", 400));
+ }
+ }
+
+ /**
+ * Print the objects returned by an iterator of entity value objects.
+ */
+ private void printValues(String label, Iterator iterator) {
+
+ System.out.println("\n--- " + label + " ---");
+ while (iterator.hasNext()) {
+ System.out.println(iterator.next().toString());
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/entity/SampleDatabase.java b/examples_java/src/collections/ship/entity/SampleDatabase.java
new file mode 100644
index 0000000..870b16a
--- /dev/null
+++ b/examples_java/src/collections/ship/entity/SampleDatabase.java
@@ -0,0 +1,331 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.entity;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import com.sleepycat.bind.serial.ClassCatalog;
+import com.sleepycat.bind.serial.SerialSerialKeyCreator;
+import com.sleepycat.bind.serial.StoredClassCatalog;
+import com.sleepycat.db.Database;
+import com.sleepycat.db.DatabaseConfig;
+import com.sleepycat.db.DatabaseException;
+import com.sleepycat.db.DatabaseType;
+import com.sleepycat.db.Environment;
+import com.sleepycat.db.EnvironmentConfig;
+import com.sleepycat.db.ForeignKeyDeleteAction;
+import com.sleepycat.db.SecondaryConfig;
+import com.sleepycat.db.SecondaryDatabase;
+
+/**
+ * SampleDatabase defines the storage containers, indices and foreign keys
+ * for the sample database.
+ *
+ * @author Mark Hayes
+ */
+public class SampleDatabase {
+
+ private static final String CLASS_CATALOG = "java_class_catalog";
+ private static final String SUPPLIER_STORE = "supplier_store";
+ private static final String PART_STORE = "part_store";
+ private static final String SHIPMENT_STORE = "shipment_store";
+ private static final String SHIPMENT_PART_INDEX = "shipment_part_index";
+ private static final String SHIPMENT_SUPPLIER_INDEX =
+ "shipment_supplier_index";
+ private static final String SUPPLIER_CITY_INDEX = "supplier_city_index";
+
+ private Environment env;
+ private Database partDb;
+ private Database supplierDb;
+ private Database shipmentDb;
+ private SecondaryDatabase supplierByCityDb;
+ private SecondaryDatabase shipmentByPartDb;
+ private SecondaryDatabase shipmentBySupplierDb;
+ private StoredClassCatalog javaCatalog;
+
+ /**
+ * Open all storage containers, indices, and catalogs.
+ */
+ public SampleDatabase(String homeDirectory)
+ throws DatabaseException, FileNotFoundException {
+
+ // Open the Berkeley DB environment in transactional mode.
+ //
+ System.out.println("Opening environment in: " + homeDirectory);
+ EnvironmentConfig envConfig = new EnvironmentConfig();
+ envConfig.setTransactional(true);
+ envConfig.setAllowCreate(true);
+ envConfig.setInitializeCache(true);
+ envConfig.setInitializeLocking(true);
+ env = new Environment(new File(homeDirectory), envConfig);
+
+ // Set the Berkeley DB config for opening all stores.
+ //
+ DatabaseConfig dbConfig = new DatabaseConfig();
+ dbConfig.setTransactional(true);
+ dbConfig.setAllowCreate(true);
+ dbConfig.setType(DatabaseType.BTREE);
+
+ // Create the Serial class catalog. This holds the serialized class
+ // format for all database records of serial format.
+ //
+ Database catalogDb = env.openDatabase(null, CLASS_CATALOG, null,
+ dbConfig);
+ javaCatalog = new StoredClassCatalog(catalogDb);
+
+ // Open the Berkeley DB database for the part, supplier and shipment
+ // stores. The stores are opened with no duplicate keys allowed.
+ //
+ partDb = env.openDatabase(null, PART_STORE, null, dbConfig);
+
+ supplierDb = env.openDatabase(null, SUPPLIER_STORE, null, dbConfig);
+
+ shipmentDb = env.openDatabase(null, SHIPMENT_STORE, null, dbConfig);
+
+ // Open the SecondaryDatabase for the city index of the supplier store,
+ // and for the part and supplier indices of the shipment store.
+ // Duplicate keys are allowed since more than one supplier may be in
+ // the same city, and more than one shipment may exist for the same
+ // supplier or part. A foreign key constraint is defined for the
+ // supplier and part indices to ensure that a shipment only refers to
+ // existing part and supplier keys. The CASCADE delete action means
+ // that shipments will be deleted if their associated part or supplier
+ // is deleted.
+ //
+ SecondaryConfig secConfig = new SecondaryConfig();
+ secConfig.setTransactional(true);
+ secConfig.setAllowCreate(true);
+ secConfig.setType(DatabaseType.BTREE);
+ secConfig.setSortedDuplicates(true);
+
+ secConfig.setKeyCreator(
+ new SupplierByCityKeyCreator(javaCatalog,
+ SupplierKey.class,
+ SupplierData.class,
+ String.class));
+ supplierByCityDb = env.openSecondaryDatabase(null, SUPPLIER_CITY_INDEX,
+ null, supplierDb,
+ secConfig);
+
+ secConfig.setForeignKeyDatabase(partDb);
+ secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE);
+ secConfig.setKeyCreator(
+ new ShipmentByPartKeyCreator(javaCatalog,
+ ShipmentKey.class,
+ ShipmentData.class,
+ PartKey.class));
+ shipmentByPartDb = env.openSecondaryDatabase(null, SHIPMENT_PART_INDEX,
+ null, shipmentDb,
+ secConfig);
+
+ secConfig.setForeignKeyDatabase(supplierDb);
+ secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE);
+ secConfig.setKeyCreator(
+ new ShipmentBySupplierKeyCreator(javaCatalog,
+ ShipmentKey.class,
+ ShipmentData.class,
+ SupplierKey.class));
+ shipmentBySupplierDb = env.openSecondaryDatabase(null,
+ SHIPMENT_SUPPLIER_INDEX,
+ null, shipmentDb,
+ secConfig);
+ }
+
+ /**
+ * Return the storage environment for the database.
+ */
+ public final Environment getEnvironment() {
+
+ return env;
+ }
+
+ /**
+ * Return the class catalog.
+ */
+ public final StoredClassCatalog getClassCatalog() {
+
+ return javaCatalog;
+ }
+
+ /**
+ * Return the part storage container.
+ */
+ public final Database getPartDatabase() {
+
+ return partDb;
+ }
+
+ /**
+ * Return the supplier storage container.
+ */
+ public final Database getSupplierDatabase() {
+
+ return supplierDb;
+ }
+
+ /**
+ * Return the shipment storage container.
+ */
+ public final Database getShipmentDatabase() {
+
+ return shipmentDb;
+ }
+
+ /**
+ * Return the shipment-by-part index.
+ */
+ public final SecondaryDatabase getShipmentByPartDatabase() {
+
+ return shipmentByPartDb;
+ }
+
+ /**
+ * Return the shipment-by-supplier index.
+ */
+ public final SecondaryDatabase getShipmentBySupplierDatabase() {
+
+ return shipmentBySupplierDb;
+ }
+
+ /**
+ * Return the supplier-by-city index.
+ */
+ public final SecondaryDatabase getSupplierByCityDatabase() {
+
+ return supplierByCityDb;
+ }
+
+ /**
+ * Close all stores (closing a store automatically closes its indices).
+ */
+ public void close()
+ throws DatabaseException {
+
+ // Close secondary databases, then primary databases.
+ supplierByCityDb.close();
+ shipmentByPartDb.close();
+ shipmentBySupplierDb.close();
+ partDb.close();
+ supplierDb.close();
+ shipmentDb.close();
+ // And don't forget to close the catalog and the environment.
+ javaCatalog.close();
+ env.close();
+ }
+
+ /**
+ * The SecondaryKeyCreator for the SupplierByCity index. This is an
+ * extension of the abstract class SerialSerialKeyCreator, which implements
+ * SecondaryKeyCreator for the case where the data keys and value are all
+ * of the serial format.
+ */
+ private static class SupplierByCityKeyCreator
+ extends SerialSerialKeyCreator {
+
+ /**
+ * Construct the city key extractor.
+ * @param catalog is the class catalog.
+ * @param primaryKeyClass is the supplier key class.
+ * @param valueClass is the supplier value class.
+ * @param indexKeyClass is the city key class.
+ */
+ private SupplierByCityKeyCreator(ClassCatalog catalog,
+ Class primaryKeyClass,
+ Class valueClass,
+ Class indexKeyClass) {
+
+ super(catalog, primaryKeyClass, valueClass, indexKeyClass);
+ }
+
+ /**
+ * Extract the city key from a supplier key/value pair. The city key
+ * is stored in the supplier value, so the supplier key is not used.
+ */
+ public Object createSecondaryKey(Object primaryKeyInput,
+ Object valueInput) {
+
+ SupplierData supplierData = (SupplierData) valueInput;
+ return supplierData.getCity();
+ }
+ }
+
+ /**
+ * The SecondaryKeyCreator for the ShipmentByPart index. This is an
+ * extension of the abstract class SerialSerialKeyCreator, which implements
+ * SecondaryKeyCreator for the case where the data keys and value are all
+ * of the serial format.
+ */
+ private static class ShipmentByPartKeyCreator
+ extends SerialSerialKeyCreator {
+
+ /**
+ * Construct the part key extractor.
+ * @param catalog is the class catalog.
+ * @param primaryKeyClass is the shipment key class.
+ * @param valueClass is the shipment value class.
+ * @param indexKeyClass is the part key class.
+ */
+ private ShipmentByPartKeyCreator(ClassCatalog catalog,
+ Class primaryKeyClass,
+ Class valueClass,
+ Class indexKeyClass) {
+
+ super(catalog, primaryKeyClass, valueClass, indexKeyClass);
+ }
+
+ /**
+ * Extract the part key from a shipment key/value pair. The part key
+ * is stored in the shipment key, so the shipment value is not used.
+ */
+ public Object createSecondaryKey(Object primaryKeyInput,
+ Object valueInput) {
+
+ ShipmentKey shipmentKey = (ShipmentKey) primaryKeyInput;
+ return new PartKey(shipmentKey.getPartNumber());
+ }
+ }
+
+ /**
+ * The SecondaryKeyCreator for the ShipmentBySupplier index. This is an
+ * extension of the abstract class SerialSerialKeyCreator, which implements
+ * SecondaryKeyCreator for the case where the data keys and value are all
+ * of the serial format.
+ */
+ private static class ShipmentBySupplierKeyCreator
+ extends SerialSerialKeyCreator {
+
+ /**
+ * Construct the supplier key extractor.
+ * @param catalog is the class catalog.
+ * @param primaryKeyClass is the shipment key class.
+ * @param valueClass is the shipment value class.
+ * @param indexKeyClass is the supplier key class.
+ */
+ private ShipmentBySupplierKeyCreator(ClassCatalog catalog,
+ Class primaryKeyClass,
+ Class valueClass,
+ Class indexKeyClass) {
+
+ super(catalog, primaryKeyClass, valueClass, indexKeyClass);
+ }
+
+ /**
+ * Extract the supplier key from a shipment key/value pair. The part
+ * key is stored in the shipment key, so the shipment value is not
+ * used.
+ */
+ public Object createSecondaryKey(Object primaryKeyInput,
+ Object valueInput) {
+
+ ShipmentKey shipmentKey = (ShipmentKey) primaryKeyInput;
+ return new SupplierKey(shipmentKey.getSupplierNumber());
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/entity/SampleViews.java b/examples_java/src/collections/ship/entity/SampleViews.java
new file mode 100644
index 0000000..4ccd1c6
--- /dev/null
+++ b/examples_java/src/collections/ship/entity/SampleViews.java
@@ -0,0 +1,306 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.entity;
+
+import com.sleepycat.bind.EntityBinding;
+import com.sleepycat.bind.serial.ClassCatalog;
+import com.sleepycat.bind.serial.SerialBinding;
+import com.sleepycat.bind.serial.SerialSerialBinding;
+import com.sleepycat.collections.StoredSortedMap;
+import com.sleepycat.collections.StoredValueSet;
+
+/**
+ * SampleViews defines the data bindings and collection views for the sample
+ * database.
+ *
+ * @author Mark Hayes
+ */
+public class SampleViews {
+
+ private StoredSortedMap partMap;
+ private StoredSortedMap supplierMap;
+ private StoredSortedMap shipmentMap;
+ private StoredSortedMap shipmentByPartMap;
+ private StoredSortedMap shipmentBySupplierMap;
+ private StoredSortedMap supplierByCityMap;
+
+ /**
+ * Create the data bindings and collection views.
+ */
+ public SampleViews(SampleDatabase db) {
+
+ // Create the data bindings.
+ // In this sample, EntityBinding classes are used to bind the stored
+ // key/data entry pair to a combined data object. For keys, however,
+ // the stored entry is used directly via a SerialBinding and no
+ // special binding class is needed.
+ //
+ ClassCatalog catalog = db.getClassCatalog();
+ SerialBinding partKeyBinding =
+ new SerialBinding(catalog, PartKey.class);
+ EntityBinding partDataBinding =
+ new PartBinding(catalog, PartKey.class, PartData.class);
+ SerialBinding supplierKeyBinding =
+ new SerialBinding(catalog, SupplierKey.class);
+ EntityBinding supplierDataBinding =
+ new SupplierBinding(catalog, SupplierKey.class,
+ SupplierData.class);
+ SerialBinding shipmentKeyBinding =
+ new SerialBinding(catalog, ShipmentKey.class);
+ EntityBinding shipmentDataBinding =
+ new ShipmentBinding(catalog, ShipmentKey.class,
+ ShipmentData.class);
+ SerialBinding cityKeyBinding =
+ new SerialBinding(catalog, String.class);
+
+ // Create map views for all stores and indices.
+ // StoredSortedMap is not used since the stores and indices are
+ // ordered by serialized key objects, which do not provide a very
+ // useful ordering.
+ //
+ partMap =
+ new StoredSortedMap(db.getPartDatabase(),
+ partKeyBinding, partDataBinding, true);
+ supplierMap =
+ new StoredSortedMap(db.getSupplierDatabase(),
+ supplierKeyBinding, supplierDataBinding, true);
+ shipmentMap =
+ new StoredSortedMap(db.getShipmentDatabase(),
+ shipmentKeyBinding, shipmentDataBinding, true);
+ shipmentByPartMap =
+ new StoredSortedMap(db.getShipmentByPartDatabase(),
+ partKeyBinding, shipmentDataBinding, true);
+ shipmentBySupplierMap =
+ new StoredSortedMap(db.getShipmentBySupplierDatabase(),
+ supplierKeyBinding, shipmentDataBinding, true);
+ supplierByCityMap =
+ new StoredSortedMap(db.getSupplierByCityDatabase(),
+ cityKeyBinding, supplierDataBinding, true);
+ }
+
+ // The views returned below can be accessed using the java.util.Map or
+ // java.util.Set interfaces, or using the StoredSortedMap and
+ // StoredValueSet classes, which provide additional methods. The entity
+ // sets could be obtained directly from the Map.values() method but
+ // convenience methods are provided here to return them in order to avoid
+ // down-casting elsewhere.
+
+ /**
+ * Return a map view of the part storage container.
+ */
+ public StoredSortedMap getPartMap() {
+
+ return partMap;
+ }
+
+ /**
+ * Return a map view of the supplier storage container.
+ */
+ public StoredSortedMap getSupplierMap() {
+
+ return supplierMap;
+ }
+
+ /**
+ * Return a map view of the shipment storage container.
+ */
+ public StoredSortedMap getShipmentMap() {
+
+ return shipmentMap;
+ }
+
+ /**
+ * Return an entity set view of the part storage container.
+ */
+ public StoredValueSet getPartSet() {
+
+ return (StoredValueSet) partMap.values();
+ }
+
+ /**
+ * Return an entity set view of the supplier storage container.
+ */
+ public StoredValueSet getSupplierSet() {
+
+ return (StoredValueSet) supplierMap.values();
+ }
+
+ /**
+ * Return an entity set view of the shipment storage container.
+ */
+ public StoredValueSet getShipmentSet() {
+
+ return (StoredValueSet) shipmentMap.values();
+ }
+
+ /**
+ * Return a map view of the shipment-by-part index.
+ */
+ public StoredSortedMap getShipmentByPartMap() {
+
+ return shipmentByPartMap;
+ }
+
+ /**
+ * Return a map view of the shipment-by-supplier index.
+ */
+ public StoredSortedMap getShipmentBySupplierMap() {
+
+ return shipmentBySupplierMap;
+ }
+
+ /**
+ * Return a map view of the supplier-by-city index.
+ */
+ public final StoredSortedMap getSupplierByCityMap() {
+
+ return supplierByCityMap;
+ }
+
+ /**
+ * PartBinding is used to bind the stored key/data entry pair for a part
+ * to a combined data object (entity).
+ */
+ private static class PartBinding extends SerialSerialBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private PartBinding(ClassCatalog classCatalog,
+ Class keyClass,
+ Class dataClass) {
+
+ super(classCatalog, keyClass, dataClass);
+ }
+
+ /**
+ * Create the entity by combining the stored key and data.
+ */
+ public Object entryToObject(Object keyInput, Object dataInput) {
+
+ PartKey key = (PartKey) keyInput;
+ PartData data = (PartData) dataInput;
+ return new Part(key.getNumber(), data.getName(), data.getColor(),
+ data.getWeight(), data.getCity());
+ }
+
+ /**
+ * Create the stored key from the entity.
+ */
+ public Object objectToKey(Object object) {
+
+ Part part = (Part) object;
+ return new PartKey(part.getNumber());
+ }
+
+ /**
+ * Create the stored data from the entity.
+ */
+ public Object objectToData(Object object) {
+
+ Part part = (Part) object;
+ return new PartData(part.getName(), part.getColor(),
+ part.getWeight(), part.getCity());
+ }
+ }
+
+ /**
+ * SupplierBinding is used to bind the stored key/data entry pair for a
+ * supplier to a combined data object (entity).
+ */
+ private static class SupplierBinding extends SerialSerialBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private SupplierBinding(ClassCatalog classCatalog,
+ Class keyClass,
+ Class dataClass) {
+
+ super(classCatalog, keyClass, dataClass);
+ }
+
+ /**
+ * Create the entity by combining the stored key and data.
+ */
+ public Object entryToObject(Object keyInput, Object dataInput) {
+
+ SupplierKey key = (SupplierKey) keyInput;
+ SupplierData data = (SupplierData) dataInput;
+ return new Supplier(key.getNumber(), data.getName(),
+ data.getStatus(), data.getCity());
+ }
+
+ /**
+ * Create the stored key from the entity.
+ */
+ public Object objectToKey(Object object) {
+
+ Supplier supplier = (Supplier) object;
+ return new SupplierKey(supplier.getNumber());
+ }
+
+ /**
+ * Create the stored data from the entity.
+ */
+ public Object objectToData(Object object) {
+
+ Supplier supplier = (Supplier) object;
+ return new SupplierData(supplier.getName(), supplier.getStatus(),
+ supplier.getCity());
+ }
+ }
+
+ /**
+ * ShipmentBinding is used to bind the stored key/data entry pair for a
+ * shipment to a combined data object (entity).
+ */
+ private static class ShipmentBinding extends SerialSerialBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private ShipmentBinding(ClassCatalog classCatalog,
+ Class keyClass,
+ Class dataClass) {
+
+ super(classCatalog, keyClass, dataClass);
+ }
+
+ /**
+ * Create the entity by combining the stored key and data.
+ */
+ public Object entryToObject(Object keyInput, Object dataInput) {
+
+ ShipmentKey key = (ShipmentKey) keyInput;
+ ShipmentData data = (ShipmentData) dataInput;
+ return new Shipment(key.getPartNumber(), key.getSupplierNumber(),
+ data.getQuantity());
+ }
+
+ /**
+ * Create the stored key from the entity.
+ */
+ public Object objectToKey(Object object) {
+
+ Shipment shipment = (Shipment) object;
+ return new ShipmentKey(shipment.getPartNumber(),
+ shipment.getSupplierNumber());
+ }
+
+ /**
+ * Create the stored data from the entity.
+ */
+ public Object objectToData(Object object) {
+
+ Shipment shipment = (Shipment) object;
+ return new ShipmentData(shipment.getQuantity());
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/entity/Shipment.java b/examples_java/src/collections/ship/entity/Shipment.java
new file mode 100644
index 0000000..ad5df02
--- /dev/null
+++ b/examples_java/src/collections/ship/entity/Shipment.java
@@ -0,0 +1,55 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.entity;
+
+/**
+ * A Shipment represents the combined key/data pair for a shipment entity.
+ *
+ * <p> In this sample, Shipment is created from the stored key/data entry
+ * using a SerialSerialBinding. See {@link SampleViews.ShipmentBinding} for
+ * details. Since this class is not used directly for data storage, it does
+ * not need to be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Shipment {
+
+ private String partNumber;
+ private String supplierNumber;
+ private int quantity;
+
+ public Shipment(String partNumber, String supplierNumber, int quantity) {
+
+ this.partNumber = partNumber;
+ this.supplierNumber = supplierNumber;
+ this.quantity = quantity;
+ }
+
+ public final String getPartNumber() {
+
+ return partNumber;
+ }
+
+ public final String getSupplierNumber() {
+
+ return supplierNumber;
+ }
+
+ public final int getQuantity() {
+
+ return quantity;
+ }
+
+ public String toString() {
+
+ return "[Shipment: part=" + partNumber +
+ " supplier=" + supplierNumber +
+ " quantity=" + quantity + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/entity/ShipmentData.java b/examples_java/src/collections/ship/entity/ShipmentData.java
new file mode 100644
index 0000000..002acdc
--- /dev/null
+++ b/examples_java/src/collections/ship/entity/ShipmentData.java
@@ -0,0 +1,42 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.entity;
+
+import java.io.Serializable;
+
+/**
+ * A ShipmentData serves as the value in the key/value pair for a shipment
+ * entity.
+ *
+ * <p> In this sample, ShipmentData is used only as the storage data for the
+ * value, while the Shipment object is used as the value's object
+ * representation. Because it is used directly as storage data using
+ * serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class ShipmentData implements Serializable {
+
+ private int quantity;
+
+ public ShipmentData(int quantity) {
+
+ this.quantity = quantity;
+ }
+
+ public final int getQuantity() {
+
+ return quantity;
+ }
+
+ public String toString() {
+
+ return "[ShipmentData: quantity=" + quantity + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/entity/ShipmentKey.java b/examples_java/src/collections/ship/entity/ShipmentKey.java
new file mode 100644
index 0000000..8618e95
--- /dev/null
+++ b/examples_java/src/collections/ship/entity/ShipmentKey.java
@@ -0,0 +1,48 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.entity;
+
+import java.io.Serializable;
+
+/**
+ * A ShipmentKey serves as the key in the key/data pair for a shipment entity.
+ *
+ * <p> In this sample, ShipmentKey is used both as the storage entry for the
+ * key as well as the object binding to the key. Because it is used directly
+ * as storage data using serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class ShipmentKey implements Serializable {
+
+ private String partNumber;
+ private String supplierNumber;
+
+ public ShipmentKey(String partNumber, String supplierNumber) {
+
+ this.partNumber = partNumber;
+ this.supplierNumber = supplierNumber;
+ }
+
+ public final String getPartNumber() {
+
+ return partNumber;
+ }
+
+ public final String getSupplierNumber() {
+
+ return supplierNumber;
+ }
+
+ public String toString() {
+
+ return "[ShipmentKey: supplier=" + supplierNumber +
+ " part=" + partNumber + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/entity/Supplier.java b/examples_java/src/collections/ship/entity/Supplier.java
new file mode 100644
index 0000000..9019eb1
--- /dev/null
+++ b/examples_java/src/collections/ship/entity/Supplier.java
@@ -0,0 +1,63 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.entity;
+
+/**
+ * A Supplier represents the combined key/data pair for a supplier entity.
+ *
+ * <p> In this sample, Supplier is created from the stored key/data entry
+ * using a SerialSerialBinding. See {@link SampleViews.SupplierBinding} for
+ * details. Since this class is not used directly for data storage, it does
+ * not need to be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Supplier {
+
+ private String number;
+ private String name;
+ private int status;
+ private String city;
+
+ public Supplier(String number, String name, int status, String city) {
+
+ this.number = number;
+ this.name = name;
+ this.status = status;
+ this.city = city;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final int getStatus() {
+
+ return status;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[Supplier: number=" + number +
+ " name=" + name +
+ " status=" + status +
+ " city=" + city + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/entity/SupplierData.java b/examples_java/src/collections/ship/entity/SupplierData.java
new file mode 100644
index 0000000..b158b4f
--- /dev/null
+++ b/examples_java/src/collections/ship/entity/SupplierData.java
@@ -0,0 +1,58 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.entity;
+
+import java.io.Serializable;
+
+/**
+ * A SupplierData serves as the value in the key/value pair for a supplier
+ * entity.
+ *
+ * <p> In this sample, SupplierData is used only as the storage data for the
+ * value, while the Supplier object is used as the value's object
+ * representation. Because it is used directly as storage data using
+ * serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class SupplierData implements Serializable {
+
+ private String name;
+ private int status;
+ private String city;
+
+ public SupplierData(String name, int status, String city) {
+
+ this.name = name;
+ this.status = status;
+ this.city = city;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final int getStatus() {
+
+ return status;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[SupplierData: name=" + name +
+ " status=" + status +
+ " city=" + city + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/entity/SupplierKey.java b/examples_java/src/collections/ship/entity/SupplierKey.java
new file mode 100644
index 0000000..ccfccf1
--- /dev/null
+++ b/examples_java/src/collections/ship/entity/SupplierKey.java
@@ -0,0 +1,40 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.entity;
+
+import java.io.Serializable;
+
+/**
+ * A SupplierKey serves as the key in the key/data pair for a supplier entity.
+ *
+ * <p> In this sample, SupplierKey is used both as the storage entry for the
+ * key as well as the object binding to the key. Because it is used directly
+ * as storage data using serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class SupplierKey implements Serializable {
+
+ private String number;
+
+ public SupplierKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public String toString() {
+
+ return "[SupplierKey: number=" + number + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/entity/Weight.java b/examples_java/src/collections/ship/entity/Weight.java
new file mode 100644
index 0000000..cded81c
--- /dev/null
+++ b/examples_java/src/collections/ship/entity/Weight.java
@@ -0,0 +1,49 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.entity;
+
+import java.io.Serializable;
+
+/**
+ * Weight represents a weight amount and unit of measure.
+ *
+ * <p> In this sample, Weight is embedded in part data values which are stored
+ * as Serial serialized objects; therefore Weight must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Weight implements Serializable {
+
+ public final static String GRAMS = "grams";
+ public final static String OUNCES = "ounces";
+
+ private double amount;
+ private String units;
+
+ public Weight(double amount, String units) {
+
+ this.amount = amount;
+ this.units = units;
+ }
+
+ public final double getAmount() {
+
+ return amount;
+ }
+
+ public final String getUnits() {
+
+ return units;
+ }
+
+ public String toString() {
+
+ return "[" + amount + ' ' + units + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/factory/Part.java b/examples_java/src/collections/ship/factory/Part.java
new file mode 100644
index 0000000..af28e5a
--- /dev/null
+++ b/examples_java/src/collections/ship/factory/Part.java
@@ -0,0 +1,106 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.factory;
+
+import java.io.Serializable;
+
+import com.sleepycat.bind.tuple.MarshalledTupleKeyEntity;
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+/**
+ * A Part represents the combined key/data pair for a part entity.
+ *
+ * <p> In this sample, Part is bound to the stored key/data entry by
+ * implementing the MarshalledTupleKeyEntity interface. </p>
+ *
+ * <p> The binding is "tricky" in that it uses this class for both the stored
+ * data entry and the combined entity object. To do this, the key field(s)
+ * are transient and are set by the binding after the data object has been
+ * deserialized. This avoids the use of a PartData class completely. </p>
+ *
+ * <p> Since this class is used directly for data storage, it must be
+ * Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Part implements Serializable, MarshalledTupleKeyEntity {
+
+ private transient String number;
+ private String name;
+ private String color;
+ private Weight weight;
+ private String city;
+
+ public Part(String number, String name, String color, Weight weight,
+ String city) {
+
+ this.number = number;
+ this.name = name;
+ this.color = color;
+ this.weight = weight;
+ this.city = city;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final String getColor() {
+
+ return color;
+ }
+
+ public final Weight getWeight() {
+
+ return weight;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[Part: number=" + number +
+ " name=" + name +
+ " color=" + color +
+ " weight=" + weight +
+ " city=" + city + ']';
+ }
+
+ // --- MarshalledTupleKeyEntity implementation ---
+
+ public void marshalPrimaryKey(TupleOutput keyOutput) {
+
+ keyOutput.writeString(this.number);
+ }
+
+ public void unmarshalPrimaryKey(TupleInput keyInput) {
+
+ this.number = keyInput.readString();
+ }
+
+ public boolean marshalSecondaryKey(String keyName, TupleOutput keyOutput) {
+
+ throw new UnsupportedOperationException(keyName);
+ }
+
+ public boolean nullifyForeignKey(String keyName) {
+
+ throw new UnsupportedOperationException(keyName);
+ }
+}
diff --git a/examples_java/src/collections/ship/factory/PartKey.java b/examples_java/src/collections/ship/factory/PartKey.java
new file mode 100644
index 0000000..ad7f448
--- /dev/null
+++ b/examples_java/src/collections/ship/factory/PartKey.java
@@ -0,0 +1,60 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.factory;
+
+import com.sleepycat.bind.tuple.MarshalledTupleEntry;
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+/**
+ * A PartKey serves as the key in the key/data pair for a part entity.
+ *
+ * <p> In this sample, PartKey is bound to the stored key tuple entry by
+ * implementing the MarshalledTupleEntry interface, which is called by {@link
+ * SampleViews.MarshalledKeyBinding}. </p>
+ *
+ * @author Mark Hayes
+ */
+public class PartKey implements MarshalledTupleEntry {
+
+ private String number;
+
+ public PartKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public String toString() {
+
+ return "[PartKey: number=" + number + ']';
+ }
+
+ // --- MarshalledTupleEntry implementation ---
+
+ public PartKey() {
+
+ // A no-argument constructor is necessary only to allow the binding to
+ // instantiate objects of this class.
+ }
+
+ public void marshalEntry(TupleOutput keyOutput) {
+
+ keyOutput.writeString(this.number);
+ }
+
+ public void unmarshalEntry(TupleInput keyInput) {
+
+ this.number = keyInput.readString();
+ }
+}
diff --git a/examples_java/src/collections/ship/factory/Sample.java b/examples_java/src/collections/ship/factory/Sample.java
new file mode 100644
index 0000000..4fbb357
--- /dev/null
+++ b/examples_java/src/collections/ship/factory/Sample.java
@@ -0,0 +1,234 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.factory;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import com.sleepycat.collections.TransactionRunner;
+import com.sleepycat.collections.TransactionWorker;
+
+/**
+ * Sample is the main entry point for the sample program and may be run as
+ * follows:
+ *
+ * <pre>
+ * java collections.ship.factory.Sample
+ * [-h <home-directory> ]
+ * </pre>
+ *
+ * <p> The default for the home directory is ./tmp -- the tmp subdirectory of
+ * the current directory where the sample is run. To specify a different home
+ * directory, use the -home option. The home directory must exist before
+ * running the sample. To recreate the sample database from scratch, delete
+ * all files in the home directory before running the sample. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Sample {
+
+ private SampleDatabase db;
+ private SampleViews views;
+
+ /**
+ * Run the sample program.
+ */
+ public static void main(String[] args) {
+
+ System.out.println("\nRunning sample: " + Sample.class);
+
+ // Parse the command line arguments.
+ //
+ String homeDir = "./tmp";
+ for (int i = 0; i < args.length; i += 1) {
+ if (args[i].equals("-h") && i < args.length - 1) {
+ i += 1;
+ homeDir = args[i];
+ } else {
+ System.err.println("Usage:\n java " + Sample.class.getName() +
+ "\n [-h <home-directory>]");
+ System.exit(2);
+ }
+ }
+
+ // Run the sample.
+ //
+ Sample sample = null;
+ try {
+ sample = new Sample(homeDir);
+ sample.run();
+ } catch (Exception e) {
+ // If an exception reaches this point, the last transaction did not
+ // complete. If the exception is RunRecoveryException, follow
+ // the Berkeley DB recovery procedures before running again.
+ e.printStackTrace();
+ } finally {
+ if (sample != null) {
+ try {
+ // Always attempt to close the database cleanly.
+ sample.close();
+ } catch (Exception e) {
+ System.err.println("Exception during database close:");
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Open the database and views.
+ */
+ private Sample(String homeDir)
+ throws Exception {
+
+ db = new SampleDatabase(homeDir);
+ views = new SampleViews(db);
+ }
+
+ /**
+ * Close the database cleanly.
+ */
+ private void close()
+ throws Exception {
+
+ db.close();
+ }
+
+ /**
+ * Run two transactions to populate and print the database. A
+ * TransactionRunner is used to ensure consistent handling of transactions,
+ * including deadlock retries. But the best transaction handling mechanism
+ * to use depends on the application.
+ */
+ private void run()
+ throws Exception {
+
+ TransactionRunner runner = new TransactionRunner(db.getEnvironment());
+ runner.run(new PopulateDatabase());
+ runner.run(new PrintDatabase());
+ }
+
+ /**
+ * Populate the database in a single transaction.
+ */
+ private class PopulateDatabase implements TransactionWorker {
+
+ public void doWork()
+ throws Exception {
+ addSuppliers();
+ addParts();
+ addShipments();
+ }
+ }
+
+ /**
+ * Print the database in a single transaction. All entities are printed
+ * and the indices are used to print the entities for certain keys.
+ *
+ * <p> Note the use of special iterator() methods. These are used here
+ * with indices to find the shipments for certain keys.</p>
+ */
+ private class PrintDatabase implements TransactionWorker {
+
+ public void doWork()
+ throws Exception {
+ printValues("Parts",
+ views.getPartSet().iterator());
+ printValues("Suppliers",
+ views.getSupplierSet().iterator());
+ printValues("Suppliers for City Paris",
+ views.getSupplierByCityMap().duplicates(
+ "Paris").iterator());
+ printValues("Shipments",
+ views.getShipmentSet().iterator());
+ printValues("Shipments for Part P1",
+ views.getShipmentByPartMap().duplicates(
+ new PartKey("P1")).iterator());
+ printValues("Shipments for Supplier S1",
+ views.getShipmentBySupplierMap().duplicates(
+ new SupplierKey("S1")).iterator());
+ }
+ }
+
+ /**
+ * Populate the part entities in the database. If the part set is not
+ * empty, assume that this has already been done.
+ */
+ private void addParts() {
+
+ Set parts = views.getPartSet();
+ if (parts.isEmpty()) {
+ System.out.println("Adding Parts");
+ parts.add(new Part("P1", "Nut", "Red",
+ new Weight(12.0, Weight.GRAMS), "London"));
+ parts.add(new Part("P2", "Bolt", "Green",
+ new Weight(17.0, Weight.GRAMS), "Paris"));
+ parts.add(new Part("P3", "Screw", "Blue",
+ new Weight(17.0, Weight.GRAMS), "Rome"));
+ parts.add(new Part("P4", "Screw", "Red",
+ new Weight(14.0, Weight.GRAMS), "London"));
+ parts.add(new Part("P5", "Cam", "Blue",
+ new Weight(12.0, Weight.GRAMS), "Paris"));
+ parts.add(new Part("P6", "Cog", "Red",
+ new Weight(19.0, Weight.GRAMS), "London"));
+ }
+ }
+
+ /**
+ * Populate the supplier entities in the database. If the supplier set is
+ * not empty, assume that this has already been done.
+ */
+ private void addSuppliers() {
+
+ Set suppliers = views.getSupplierSet();
+ if (suppliers.isEmpty()) {
+ System.out.println("Adding Suppliers");
+ suppliers.add(new Supplier("S1", "Smith", 20, "London"));
+ suppliers.add(new Supplier("S2", "Jones", 10, "Paris"));
+ suppliers.add(new Supplier("S3", "Blake", 30, "Paris"));
+ suppliers.add(new Supplier("S4", "Clark", 20, "London"));
+ suppliers.add(new Supplier("S5", "Adams", 30, "Athens"));
+ }
+ }
+
+ /**
+ * Populate the shipment entities in the database. If the shipment set
+ * is not empty, assume that this has already been done.
+ */
+ private void addShipments() {
+
+ Set shipments = views.getShipmentSet();
+ if (shipments.isEmpty()) {
+ System.out.println("Adding Shipments");
+ shipments.add(new Shipment("P1", "S1", 300));
+ shipments.add(new Shipment("P2", "S1", 200));
+ shipments.add(new Shipment("P3", "S1", 400));
+ shipments.add(new Shipment("P4", "S1", 200));
+ shipments.add(new Shipment("P5", "S1", 100));
+ shipments.add(new Shipment("P6", "S1", 100));
+ shipments.add(new Shipment("P1", "S2", 300));
+ shipments.add(new Shipment("P2", "S2", 400));
+ shipments.add(new Shipment("P2", "S3", 200));
+ shipments.add(new Shipment("P2", "S4", 200));
+ shipments.add(new Shipment("P4", "S4", 300));
+ shipments.add(new Shipment("P5", "S4", 400));
+ }
+ }
+
+ /**
+ * Print the objects returned by an iterator of entity value objects.
+ */
+ private void printValues(String label, Iterator iterator) {
+
+ System.out.println("\n--- " + label + " ---");
+ while (iterator.hasNext()) {
+ System.out.println(iterator.next().toString());
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/factory/SampleDatabase.java b/examples_java/src/collections/ship/factory/SampleDatabase.java
new file mode 100644
index 0000000..bb00840
--- /dev/null
+++ b/examples_java/src/collections/ship/factory/SampleDatabase.java
@@ -0,0 +1,226 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.factory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import com.sleepycat.bind.serial.StoredClassCatalog;
+import com.sleepycat.collections.TupleSerialFactory;
+import com.sleepycat.db.Database;
+import com.sleepycat.db.DatabaseConfig;
+import com.sleepycat.db.DatabaseException;
+import com.sleepycat.db.DatabaseType;
+import com.sleepycat.db.Environment;
+import com.sleepycat.db.EnvironmentConfig;
+import com.sleepycat.db.ForeignKeyDeleteAction;
+import com.sleepycat.db.SecondaryConfig;
+import com.sleepycat.db.SecondaryDatabase;
+
+/**
+ * SampleDatabase defines the storage containers, indices and foreign keys
+ * for the sample database.
+ *
+ * @author Mark Hayes
+ */
+public class SampleDatabase {
+
+ private static final String CLASS_CATALOG = "java_class_catalog";
+ private static final String SUPPLIER_STORE = "supplier_store";
+ private static final String PART_STORE = "part_store";
+ private static final String SHIPMENT_STORE = "shipment_store";
+ private static final String SHIPMENT_PART_INDEX = "shipment_part_index";
+ private static final String SHIPMENT_SUPPLIER_INDEX =
+ "shipment_supplier_index";
+ private static final String SUPPLIER_CITY_INDEX = "supplier_city_index";
+
+ private Environment env;
+ private Database partDb;
+ private Database supplierDb;
+ private Database shipmentDb;
+ private SecondaryDatabase supplierByCityDb;
+ private SecondaryDatabase shipmentByPartDb;
+ private SecondaryDatabase shipmentBySupplierDb;
+ private StoredClassCatalog javaCatalog;
+ private TupleSerialFactory factory;
+
+ /**
+ * Open all storage containers, indices, and catalogs.
+ */
+ public SampleDatabase(String homeDirectory)
+ throws DatabaseException, FileNotFoundException {
+
+ // Open the Berkeley DB environment in transactional mode.
+ //
+ System.out.println("Opening environment in: " + homeDirectory);
+ EnvironmentConfig envConfig = new EnvironmentConfig();
+ envConfig.setTransactional(true);
+ envConfig.setAllowCreate(true);
+ envConfig.setInitializeCache(true);
+ envConfig.setInitializeLocking(true);
+ env = new Environment(new File(homeDirectory), envConfig);
+
+ // Set the Berkeley DB config for opening all stores.
+ //
+ DatabaseConfig dbConfig = new DatabaseConfig();
+ dbConfig.setTransactional(true);
+ dbConfig.setAllowCreate(true);
+ dbConfig.setType(DatabaseType.BTREE);
+
+ // Create the Serial class catalog. This holds the serialized class
+ // format for all database records of serial format.
+ //
+ Database catalogDb = env.openDatabase(null, CLASS_CATALOG, null,
+ dbConfig);
+ javaCatalog = new StoredClassCatalog(catalogDb);
+
+ // Use the TupleSerialDbFactory for a Serial/Tuple-based database
+ // where marshalling interfaces are used.
+ //
+ factory = new TupleSerialFactory(javaCatalog);
+
+ // Open the Berkeley DB database for the part, supplier and shipment
+ // stores. The stores are opened with no duplicate keys allowed.
+ //
+ partDb = env.openDatabase(null, PART_STORE, null, dbConfig);
+
+ supplierDb = env.openDatabase(null, SUPPLIER_STORE, null, dbConfig);
+
+ shipmentDb = env.openDatabase(null, SHIPMENT_STORE, null, dbConfig);
+
+ // Open the SecondaryDatabase for the city index of the supplier store,
+ // and for the part and supplier indices of the shipment store.
+ // Duplicate keys are allowed since more than one supplier may be in
+ // the same city, and more than one shipment may exist for the same
+ // supplier or part. A foreign key constraint is defined for the
+ // supplier and part indices to ensure that a shipment only refers to
+ // existing part and supplier keys. The CASCADE delete action means
+ // that shipments will be deleted if their associated part or supplier
+ // is deleted.
+ //
+ SecondaryConfig secConfig = new SecondaryConfig();
+ secConfig.setTransactional(true);
+ secConfig.setAllowCreate(true);
+ secConfig.setType(DatabaseType.BTREE);
+ secConfig.setSortedDuplicates(true);
+
+ secConfig.setKeyCreator(factory.getKeyCreator(Supplier.class,
+ Supplier.CITY_KEY));
+ supplierByCityDb = env.openSecondaryDatabase(null, SUPPLIER_CITY_INDEX,
+ null, supplierDb,
+ secConfig);
+
+ secConfig.setForeignKeyDatabase(partDb);
+ secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE);
+ secConfig.setKeyCreator(factory.getKeyCreator(Shipment.class,
+ Shipment.PART_KEY));
+ shipmentByPartDb = env.openSecondaryDatabase(null, SHIPMENT_PART_INDEX,
+ null, shipmentDb,
+ secConfig);
+
+ secConfig.setForeignKeyDatabase(supplierDb);
+ secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE);
+ secConfig.setKeyCreator(factory.getKeyCreator(Shipment.class,
+ Shipment.SUPPLIER_KEY));
+ shipmentBySupplierDb = env.openSecondaryDatabase(null,
+ SHIPMENT_SUPPLIER_INDEX,
+ null, shipmentDb,
+ secConfig);
+ }
+
+ /**
+ * Return the tuple-serial factory.
+ */
+ public final TupleSerialFactory getFactory() {
+
+ return factory;
+ }
+
+ /**
+ * Return the storage environment for the database.
+ */
+ public final Environment getEnvironment() {
+
+ return env;
+ }
+
+ /**
+ * Return the class catalog.
+ */
+ public final StoredClassCatalog getClassCatalog() {
+
+ return javaCatalog;
+ }
+
+ /**
+ * Return the part storage container.
+ */
+ public final Database getPartDatabase() {
+
+ return partDb;
+ }
+
+ /**
+ * Return the supplier storage container.
+ */
+ public final Database getSupplierDatabase() {
+
+ return supplierDb;
+ }
+
+ /**
+ * Return the shipment storage container.
+ */
+ public final Database getShipmentDatabase() {
+
+ return shipmentDb;
+ }
+
+ /**
+ * Return the shipment-by-part index.
+ */
+ public final SecondaryDatabase getShipmentByPartDatabase() {
+
+ return shipmentByPartDb;
+ }
+
+ /**
+ * Return the shipment-by-supplier index.
+ */
+ public final SecondaryDatabase getShipmentBySupplierDatabase() {
+
+ return shipmentBySupplierDb;
+ }
+
+ /**
+ * Return the supplier-by-city index.
+ */
+ public final SecondaryDatabase getSupplierByCityDatabase() {
+
+ return supplierByCityDb;
+ }
+
+ /**
+ * Close all databases and the environment.
+ */
+ public void close()
+ throws DatabaseException {
+
+ // Close secondary databases, then primary databases.
+ supplierByCityDb.close();
+ shipmentByPartDb.close();
+ shipmentBySupplierDb.close();
+ partDb.close();
+ supplierDb.close();
+ shipmentDb.close();
+ // And don't forget to close the catalog and the environment.
+ javaCatalog.close();
+ env.close();
+ }
+}
diff --git a/examples_java/src/collections/ship/factory/SampleViews.java b/examples_java/src/collections/ship/factory/SampleViews.java
new file mode 100644
index 0000000..bb03d8a
--- /dev/null
+++ b/examples_java/src/collections/ship/factory/SampleViews.java
@@ -0,0 +1,142 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.factory;
+
+import com.sleepycat.collections.StoredSortedMap;
+import com.sleepycat.collections.StoredSortedValueSet;
+import com.sleepycat.collections.TupleSerialFactory;
+
+/**
+ * SampleViews defines the data bindings and collection views for the sample
+ * database.
+ *
+ * @author Mark Hayes
+ */
+public class SampleViews {
+
+ private StoredSortedMap partMap;
+ private StoredSortedMap supplierMap;
+ private StoredSortedMap shipmentMap;
+ private StoredSortedMap shipmentByPartMap;
+ private StoredSortedMap shipmentBySupplierMap;
+ private StoredSortedMap supplierByCityMap;
+
+ /**
+ * Create the data bindings and collection views.
+ */
+ public SampleViews(SampleDatabase db) {
+
+ // Use the TupleSerialFactory for a Serial/Tuple-based database
+ // where marshalling interfaces are used.
+ //
+ TupleSerialFactory factory = db.getFactory();
+
+ // Create map views for all stores and indices.
+ // StoredSortedMap is used since the stores and indices are ordered
+ // (they use the DB_BTREE access method).
+ //
+ partMap =
+ factory.newSortedMap(db.getPartDatabase(),
+ PartKey.class, Part.class, true);
+ supplierMap =
+ factory.newSortedMap(db.getSupplierDatabase(),
+ SupplierKey.class, Supplier.class, true);
+ shipmentMap =
+ factory.newSortedMap(db.getShipmentDatabase(),
+ ShipmentKey.class, Shipment.class, true);
+ shipmentByPartMap =
+ factory.newSortedMap(db.getShipmentByPartDatabase(),
+ PartKey.class, Shipment.class, true);
+ shipmentBySupplierMap =
+ factory.newSortedMap(db.getShipmentBySupplierDatabase(),
+ SupplierKey.class, Shipment.class, true);
+ supplierByCityMap =
+ factory.newSortedMap(db.getSupplierByCityDatabase(),
+ String.class, Supplier.class, true);
+ }
+
+ // The views returned below can be accessed using the java.util.Map or
+ // java.util.Set interfaces, or using the StoredMap and StoredValueSet
+ // classes, which provide additional methods. The entity sets could be
+ // obtained directly from the Map.values() method but convenience methods
+ // are provided here to return them in order to avoid down-casting
+ // elsewhere.
+
+ /**
+ * Return a map view of the part storage container.
+ */
+ public StoredSortedMap getPartMap() {
+
+ return partMap;
+ }
+
+ /**
+ * Return a map view of the supplier storage container.
+ */
+ public StoredSortedMap getSupplierMap() {
+
+ return supplierMap;
+ }
+
+ /**
+ * Return a map view of the shipment storage container.
+ */
+ public StoredSortedMap getShipmentMap() {
+
+ return shipmentMap;
+ }
+
+ /**
+ * Return an entity set view of the part storage container.
+ */
+ public StoredSortedValueSet getPartSet() {
+
+ return (StoredSortedValueSet) partMap.values();
+ }
+
+ /**
+ * Return an entity set view of the supplier storage container.
+ */
+ public StoredSortedValueSet getSupplierSet() {
+
+ return (StoredSortedValueSet) supplierMap.values();
+ }
+
+ /**
+ * Return an entity set view of the shipment storage container.
+ */
+ public StoredSortedValueSet getShipmentSet() {
+
+ return (StoredSortedValueSet) shipmentMap.values();
+ }
+
+ /**
+ * Return a map view of the shipment-by-part index.
+ */
+ public StoredSortedMap getShipmentByPartMap() {
+
+ return shipmentByPartMap;
+ }
+
+ /**
+ * Return a map view of the shipment-by-supplier index.
+ */
+ public StoredSortedMap getShipmentBySupplierMap() {
+
+ return shipmentBySupplierMap;
+ }
+
+ /**
+ * Return a map view of the supplier-by-city index.
+ */
+ public StoredSortedMap getSupplierByCityMap() {
+
+ return supplierByCityMap;
+ }
+}
diff --git a/examples_java/src/collections/ship/factory/Shipment.java b/examples_java/src/collections/ship/factory/Shipment.java
new file mode 100644
index 0000000..eabed86
--- /dev/null
+++ b/examples_java/src/collections/ship/factory/Shipment.java
@@ -0,0 +1,102 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.factory;
+
+import java.io.Serializable;
+
+import com.sleepycat.bind.tuple.MarshalledTupleKeyEntity;
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+/**
+ * A Shipment represents the combined key/data pair for a shipment entity.
+ *
+ * <p> In this sample, Shipment is bound to the stored key/data entry by
+ * implementing the MarshalledTupleKeyEntity interface. </p>
+ *
+ * <p> The binding is "tricky" in that it uses this class for both the stored
+ * data entry and the combined entity object. To do this, the key field(s)
+ * are transient and are set by the binding after the data object has been
+ * deserialized. This avoids the use of a ShipmentData class completely. </p>
+ *
+ * <p> Since this class is used directly for data storage, it must be
+ * Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Shipment implements Serializable, MarshalledTupleKeyEntity {
+
+ static final String PART_KEY = "part";
+ static final String SUPPLIER_KEY = "supplier";
+
+ private transient String partNumber;
+ private transient String supplierNumber;
+ private int quantity;
+
+ public Shipment(String partNumber, String supplierNumber, int quantity) {
+
+ this.partNumber = partNumber;
+ this.supplierNumber = supplierNumber;
+ this.quantity = quantity;
+ }
+
+ public final String getPartNumber() {
+
+ return partNumber;
+ }
+
+ public final String getSupplierNumber() {
+
+ return supplierNumber;
+ }
+
+ public final int getQuantity() {
+
+ return quantity;
+ }
+
+ public String toString() {
+
+ return "[Shipment: part=" + partNumber +
+ " supplier=" + supplierNumber +
+ " quantity=" + quantity + ']';
+ }
+
+ // --- MarshalledTupleKeyEntity implementation ---
+
+ public void marshalPrimaryKey(TupleOutput keyOutput) {
+
+ keyOutput.writeString(this.partNumber);
+ keyOutput.writeString(this.supplierNumber);
+ }
+
+ public void unmarshalPrimaryKey(TupleInput keyInput) {
+
+ this.partNumber = keyInput.readString();
+ this.supplierNumber = keyInput.readString();
+ }
+
+ public boolean marshalSecondaryKey(String keyName, TupleOutput keyOutput) {
+
+ if (keyName.equals(PART_KEY)) {
+ keyOutput.writeString(this.partNumber);
+ return true;
+ } else if (keyName.equals(SUPPLIER_KEY)) {
+ keyOutput.writeString(this.supplierNumber);
+ return true;
+ } else {
+ throw new UnsupportedOperationException(keyName);
+ }
+ }
+
+ public boolean nullifyForeignKey(String keyName) {
+
+ throw new UnsupportedOperationException(keyName);
+ }
+}
diff --git a/examples_java/src/collections/ship/factory/ShipmentKey.java b/examples_java/src/collections/ship/factory/ShipmentKey.java
new file mode 100644
index 0000000..5258fbe
--- /dev/null
+++ b/examples_java/src/collections/ship/factory/ShipmentKey.java
@@ -0,0 +1,70 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.factory;
+
+import com.sleepycat.bind.tuple.MarshalledTupleEntry;
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+/**
+ * A ShipmentKey serves as the key in the key/data pair for a shipment entity.
+ *
+ * <p> In this sample, ShipmentKey is bound to the stored key tuple entry by
+ * implementing the MarshalledTupleEntry interface, which is called by {@link
+ * SampleViews.MarshalledKeyBinding}. </p>
+ *
+ * @author Mark Hayes
+ */
+public class ShipmentKey implements MarshalledTupleEntry {
+
+ private String partNumber;
+ private String supplierNumber;
+
+ public ShipmentKey(String partNumber, String supplierNumber) {
+
+ this.partNumber = partNumber;
+ this.supplierNumber = supplierNumber;
+ }
+
+ public final String getPartNumber() {
+
+ return partNumber;
+ }
+
+ public final String getSupplierNumber() {
+
+ return supplierNumber;
+ }
+
+ public String toString() {
+
+ return "[ShipmentKey: supplier=" + supplierNumber +
+ " part=" + partNumber + ']';
+ }
+
+ // --- MarshalledTupleEntry implementation ---
+
+ public ShipmentKey() {
+
+ // A no-argument constructor is necessary only to allow the binding to
+ // instantiate objects of this class.
+ }
+
+ public void marshalEntry(TupleOutput keyOutput) {
+
+ keyOutput.writeString(this.partNumber);
+ keyOutput.writeString(this.supplierNumber);
+ }
+
+ public void unmarshalEntry(TupleInput keyInput) {
+
+ this.partNumber = keyInput.readString();
+ this.supplierNumber = keyInput.readString();
+ }
+}
diff --git a/examples_java/src/collections/ship/factory/Supplier.java b/examples_java/src/collections/ship/factory/Supplier.java
new file mode 100644
index 0000000..0091cbc
--- /dev/null
+++ b/examples_java/src/collections/ship/factory/Supplier.java
@@ -0,0 +1,108 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.factory;
+
+import java.io.Serializable;
+
+import com.sleepycat.bind.tuple.MarshalledTupleKeyEntity;
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+/**
+ * A Supplier represents the combined key/data pair for a supplier entity.
+ *
+ * <p> In this sample, Supplier is bound to the stored key/data entry by
+ * implementing the MarshalledTupleKeyEntity interface. </p>
+ *
+ * <p> The binding is "tricky" in that it uses this class for both the stored
+ * data entry and the combined entity object. To do this, the key field(s) are
+ * transient and are set by the binding after the data object has been
+ * deserialized. This avoids the use of a SupplierData class completely. </p>
+ *
+ * <p> Since this class is used directly for data storage, it must be
+ * Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Supplier implements Serializable, MarshalledTupleKeyEntity {
+
+ static final String CITY_KEY = "city";
+
+ private transient String number;
+ private String name;
+ private int status;
+ private String city;
+
+ public Supplier(String number, String name, int status, String city) {
+
+ this.number = number;
+ this.name = name;
+ this.status = status;
+ this.city = city;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final int getStatus() {
+
+ return status;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[Supplier: number=" + number +
+ " name=" + name +
+ " status=" + status +
+ " city=" + city + ']';
+ }
+
+ // --- MarshalledTupleKeyEntity implementation ---
+
+ public void marshalPrimaryKey(TupleOutput keyOutput) {
+
+ keyOutput.writeString(this.number);
+ }
+
+ public void unmarshalPrimaryKey(TupleInput keyInput) {
+
+ this.number = keyInput.readString();
+ }
+
+ public boolean marshalSecondaryKey(String keyName, TupleOutput keyOutput) {
+
+ if (keyName.equals(CITY_KEY)) {
+ if (this.city != null) {
+ keyOutput.writeString(this.city);
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ throw new UnsupportedOperationException(keyName);
+ }
+ }
+
+ public boolean nullifyForeignKey(String keyName) {
+
+ throw new UnsupportedOperationException(keyName);
+ }
+}
diff --git a/examples_java/src/collections/ship/factory/SupplierKey.java b/examples_java/src/collections/ship/factory/SupplierKey.java
new file mode 100644
index 0000000..c4278b9
--- /dev/null
+++ b/examples_java/src/collections/ship/factory/SupplierKey.java
@@ -0,0 +1,60 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.factory;
+
+import com.sleepycat.bind.tuple.MarshalledTupleEntry;
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+/**
+ * A SupplierKey serves as the key in the key/data pair for a supplier entity.
+ *
+ * <p> In this sample, SupplierKey is bound to the stored key tuple entry by
+ * implementing the MarshalledTupleEntry interface, which is called by {@link
+ * SampleViews.MarshalledKeyBinding}. </p>
+ *
+ * @author Mark Hayes
+ */
+public class SupplierKey implements MarshalledTupleEntry {
+
+ private String number;
+
+ public SupplierKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public String toString() {
+
+ return "[SupplierKey: number=" + number + ']';
+ }
+
+ // --- MarshalledTupleEntry implementation ---
+
+ public SupplierKey() {
+
+ // A no-argument constructor is necessary only to allow the binding to
+ // instantiate objects of this class.
+ }
+
+ public void marshalEntry(TupleOutput keyOutput) {
+
+ keyOutput.writeString(this.number);
+ }
+
+ public void unmarshalEntry(TupleInput keyInput) {
+
+ this.number = keyInput.readString();
+ }
+}
diff --git a/examples_java/src/collections/ship/factory/Weight.java b/examples_java/src/collections/ship/factory/Weight.java
new file mode 100644
index 0000000..95cb0ed
--- /dev/null
+++ b/examples_java/src/collections/ship/factory/Weight.java
@@ -0,0 +1,49 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.factory;
+
+import java.io.Serializable;
+
+/**
+ * Weight represents a weight amount and unit of measure.
+ *
+ * <p> In this sample, Weight is embedded in part data values which are stored
+ * as Java serialized objects; therefore Weight must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Weight implements Serializable {
+
+ public final static String GRAMS = "grams";
+ public final static String OUNCES = "ounces";
+
+ private double amount;
+ private String units;
+
+ public Weight(double amount, String units) {
+
+ this.amount = amount;
+ this.units = units;
+ }
+
+ public final double getAmount() {
+
+ return amount;
+ }
+
+ public final String getUnits() {
+
+ return units;
+ }
+
+ public String toString() {
+
+ return "[" + amount + ' ' + units + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/index/PartData.java b/examples_java/src/collections/ship/index/PartData.java
new file mode 100644
index 0000000..a213f46
--- /dev/null
+++ b/examples_java/src/collections/ship/index/PartData.java
@@ -0,0 +1,64 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.index;
+
+import java.io.Serializable;
+
+/**
+ * A PartData serves as the data in the key/data pair for a part entity.
+ *
+ * <p> In this sample, PartData is used both as the storage data for the data
+ * as well as the object binding to the data. Because it is used directly as
+ * storage data using serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class PartData implements Serializable {
+
+ private String name;
+ private String color;
+ private Weight weight;
+ private String city;
+
+ public PartData(String name, String color, Weight weight, String city) {
+
+ this.name = name;
+ this.color = color;
+ this.weight = weight;
+ this.city = city;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final String getColor() {
+
+ return color;
+ }
+
+ public final Weight getWeight() {
+
+ return weight;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[PartData: name=" + name +
+ " color=" + color +
+ " weight=" + weight +
+ " city=" + city + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/index/PartKey.java b/examples_java/src/collections/ship/index/PartKey.java
new file mode 100644
index 0000000..c9d0f8a
--- /dev/null
+++ b/examples_java/src/collections/ship/index/PartKey.java
@@ -0,0 +1,40 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.index;
+
+import java.io.Serializable;
+
+/**
+ * A PartKey serves as the key in the key/data pair for a part entity.
+ *
+ * <p> In this sample, PartKey is used both as the storage data for the key as
+ * well as the object binding to the key. Because it is used directly as
+ * storage data using serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class PartKey implements Serializable {
+
+ private String number;
+
+ public PartKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public String toString() {
+
+ return "[PartKey: number=" + number + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/index/Sample.java b/examples_java/src/collections/ship/index/Sample.java
new file mode 100644
index 0000000..16cad43
--- /dev/null
+++ b/examples_java/src/collections/ship/index/Sample.java
@@ -0,0 +1,278 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.index;
+
+import java.io.FileNotFoundException;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.sleepycat.collections.TransactionRunner;
+import com.sleepycat.collections.TransactionWorker;
+import com.sleepycat.db.DatabaseException;
+
+/**
+ * Sample is the main entry point for the sample program and may be run as
+ * follows:
+ *
+ * <pre>
+ * java collections.ship.index.Sample
+ * [-h <home-directory> ]
+ * </pre>
+ *
+ * <p> The default for the home directory is ./tmp -- the tmp subdirectory of
+ * the current directory where the sample is run. The home directory must exist
+ * before running the sample. To recreate the sample database from scratch,
+ * delete all files in the home directory before running the sample. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Sample {
+
+ private SampleDatabase db;
+ private SampleViews views;
+
+ /**
+ * Run the sample program.
+ */
+ public static void main(String[] args) {
+
+ System.out.println("\nRunning sample: " + Sample.class);
+
+ // Parse the command line arguments.
+ //
+ String homeDir = "./tmp";
+ for (int i = 0; i < args.length; i += 1) {
+ if (args[i].equals("-h") && i < args.length - 1) {
+ i += 1;
+ homeDir = args[i];
+ } else {
+ System.err.println("Usage:\n java " + Sample.class.getName() +
+ "\n [-h <home-directory>]");
+ System.exit(2);
+ }
+ }
+
+ // Run the sample.
+ //
+ Sample sample = null;
+ try {
+ sample = new Sample(homeDir);
+ sample.run();
+ } catch (Exception e) {
+ // If an exception reaches this point, the last transaction did not
+ // complete. If the exception is RunRecoveryException, follow
+ // the Berkeley DB recovery procedures before running again.
+ e.printStackTrace();
+ } finally {
+ if (sample != null) {
+ try {
+ // Always attempt to close the database cleanly.
+ sample.close();
+ } catch (Exception e) {
+ System.err.println("Exception during database close:");
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Open the database and views.
+ */
+ private Sample(String homeDir)
+ throws DatabaseException, FileNotFoundException {
+
+ db = new SampleDatabase(homeDir);
+ views = new SampleViews(db);
+ }
+
+ /**
+ * Close the database cleanly.
+ */
+ private void close()
+ throws DatabaseException {
+
+ db.close();
+ }
+
+ /**
+ * Run two transactions to populate and print the database. A
+ * TransactionRunner is used to ensure consistent handling of transactions,
+ * including deadlock retries. But the best transaction handling mechanism
+ * to use depends on the application.
+ */
+ private void run()
+ throws Exception {
+
+ TransactionRunner runner = new TransactionRunner(db.getEnvironment());
+ runner.run(new PopulateDatabase());
+ runner.run(new PrintDatabase());
+ }
+
+ /**
+ * Populate the database in a single transaction.
+ */
+ private class PopulateDatabase implements TransactionWorker {
+
+ public void doWork()
+ throws Exception {
+ addSuppliers();
+ addParts();
+ addShipments();
+ }
+ }
+
+ /**
+ * Print the database in a single transaction. All entities are printed
+ * and the indices are used to print the entities for certain keys.
+ *
+ * <p> Note the use of special iterator() methods. These are used here
+ * with indices to find the shipments for certain keys.</p>
+ */
+ private class PrintDatabase implements TransactionWorker {
+
+ public void doWork()
+ throws Exception {
+ printEntries("Parts",
+ views.getPartEntrySet().iterator());
+ printEntries("Suppliers",
+ views.getSupplierEntrySet().iterator());
+ printValues("Suppliers for City Paris",
+ views.getSupplierByCityMap().duplicates(
+ "Paris").iterator());
+ printEntries("Shipments",
+ views.getShipmentEntrySet().iterator());
+ printValues("Shipments for Part P1",
+ views.getShipmentByPartMap().duplicates(
+ new PartKey("P1")).iterator());
+ printValues("Shipments for Supplier S1",
+ views.getShipmentBySupplierMap().duplicates(
+ new SupplierKey("S1")).iterator());
+ }
+ }
+
+ /**
+ * Populate the part entities in the database. If the part map is not
+ * empty, assume that this has already been done.
+ */
+ private void addParts() {
+
+ Map parts = views.getPartMap();
+ if (parts.isEmpty()) {
+ System.out.println("Adding Parts");
+ parts.put(new PartKey("P1"),
+ new PartData("Nut", "Red",
+ new Weight(12.0, Weight.GRAMS),
+ "London"));
+ parts.put(new PartKey("P2"),
+ new PartData("Bolt", "Green",
+ new Weight(17.0, Weight.GRAMS),
+ "Paris"));
+ parts.put(new PartKey("P3"),
+ new PartData("Screw", "Blue",
+ new Weight(17.0, Weight.GRAMS),
+ "Rome"));
+ parts.put(new PartKey("P4"),
+ new PartData("Screw", "Red",
+ new Weight(14.0, Weight.GRAMS),
+ "London"));
+ parts.put(new PartKey("P5"),
+ new PartData("Cam", "Blue",
+ new Weight(12.0, Weight.GRAMS),
+ "Paris"));
+ parts.put(new PartKey("P6"),
+ new PartData("Cog", "Red",
+ new Weight(19.0, Weight.GRAMS),
+ "London"));
+ }
+ }
+
+ /**
+ * Populate the supplier entities in the database. If the supplier map is
+ * not empty, assume that this has already been done.
+ */
+ private void addSuppliers() {
+
+ Map suppliers = views.getSupplierMap();
+ if (suppliers.isEmpty()) {
+ System.out.println("Adding Suppliers");
+ suppliers.put(new SupplierKey("S1"),
+ new SupplierData("Smith", 20, "London"));
+ suppliers.put(new SupplierKey("S2"),
+ new SupplierData("Jones", 10, "Paris"));
+ suppliers.put(new SupplierKey("S3"),
+ new SupplierData("Blake", 30, "Paris"));
+ suppliers.put(new SupplierKey("S4"),
+ new SupplierData("Clark", 20, "London"));
+ suppliers.put(new SupplierKey("S5"),
+ new SupplierData("Adams", 30, "Athens"));
+ }
+ }
+
+ /**
+ * Populate the shipment entities in the database. If the shipment map
+ * is not empty, assume that this has already been done.
+ */
+ private void addShipments() {
+
+ Map shipments = views.getShipmentMap();
+ if (shipments.isEmpty()) {
+ System.out.println("Adding Shipments");
+ shipments.put(new ShipmentKey("P1", "S1"),
+ new ShipmentData(300));
+ shipments.put(new ShipmentKey("P2", "S1"),
+ new ShipmentData(200));
+ shipments.put(new ShipmentKey("P3", "S1"),
+ new ShipmentData(400));
+ shipments.put(new ShipmentKey("P4", "S1"),
+ new ShipmentData(200));
+ shipments.put(new ShipmentKey("P5", "S1"),
+ new ShipmentData(100));
+ shipments.put(new ShipmentKey("P6", "S1"),
+ new ShipmentData(100));
+ shipments.put(new ShipmentKey("P1", "S2"),
+ new ShipmentData(300));
+ shipments.put(new ShipmentKey("P2", "S2"),
+ new ShipmentData(400));
+ shipments.put(new ShipmentKey("P2", "S3"),
+ new ShipmentData(200));
+ shipments.put(new ShipmentKey("P2", "S4"),
+ new ShipmentData(200));
+ shipments.put(new ShipmentKey("P4", "S4"),
+ new ShipmentData(300));
+ shipments.put(new ShipmentKey("P5", "S4"),
+ new ShipmentData(400));
+ }
+ }
+
+ /**
+ * Print the key/value objects returned by an iterator of Map.Entry
+ * objects.
+ */
+ private void printEntries(String label, Iterator iterator) {
+
+ System.out.println("\n--- " + label + " ---");
+ while (iterator.hasNext()) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ System.out.println(entry.getKey().toString());
+ System.out.println(entry.getValue().toString());
+ }
+ }
+
+ /**
+ * Print the objects returned by an iterator of value objects.
+ */
+ private void printValues(String label, Iterator iterator) {
+
+ System.out.println("\n--- " + label + " ---");
+ while (iterator.hasNext()) {
+ System.out.println(iterator.next().toString());
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/index/SampleDatabase.java b/examples_java/src/collections/ship/index/SampleDatabase.java
new file mode 100644
index 0000000..5903edf
--- /dev/null
+++ b/examples_java/src/collections/ship/index/SampleDatabase.java
@@ -0,0 +1,331 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.index;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import com.sleepycat.bind.serial.ClassCatalog;
+import com.sleepycat.bind.serial.SerialSerialKeyCreator;
+import com.sleepycat.bind.serial.StoredClassCatalog;
+import com.sleepycat.db.Database;
+import com.sleepycat.db.DatabaseConfig;
+import com.sleepycat.db.DatabaseException;
+import com.sleepycat.db.DatabaseType;
+import com.sleepycat.db.Environment;
+import com.sleepycat.db.EnvironmentConfig;
+import com.sleepycat.db.ForeignKeyDeleteAction;
+import com.sleepycat.db.SecondaryConfig;
+import com.sleepycat.db.SecondaryDatabase;
+
+/**
+ * SampleDatabase defines the storage containers, indices and foreign keys
+ * for the sample database.
+ *
+ * @author Mark Hayes
+ */
+public class SampleDatabase {
+
+ private static final String CLASS_CATALOG = "java_class_catalog";
+ private static final String SUPPLIER_STORE = "supplier_store";
+ private static final String PART_STORE = "part_store";
+ private static final String SHIPMENT_STORE = "shipment_store";
+ private static final String SHIPMENT_PART_INDEX = "shipment_part_index";
+ private static final String SHIPMENT_SUPPLIER_INDEX =
+ "shipment_supplier_index";
+ private static final String SUPPLIER_CITY_INDEX = "supplier_city_index";
+
+ private Environment env;
+ private Database partDb;
+ private Database supplierDb;
+ private Database shipmentDb;
+ private SecondaryDatabase supplierByCityDb;
+ private SecondaryDatabase shipmentByPartDb;
+ private SecondaryDatabase shipmentBySupplierDb;
+ private StoredClassCatalog javaCatalog;
+
+ /**
+ * Open all storage containers, indices, and catalogs.
+ */
+ public SampleDatabase(String homeDirectory)
+ throws DatabaseException, FileNotFoundException {
+
+ // Open the Berkeley DB environment in transactional mode.
+ //
+ System.out.println("Opening environment in: " + homeDirectory);
+ EnvironmentConfig envConfig = new EnvironmentConfig();
+ envConfig.setTransactional(true);
+ envConfig.setAllowCreate(true);
+ envConfig.setInitializeCache(true);
+ envConfig.setInitializeLocking(true);
+ env = new Environment(new File(homeDirectory), envConfig);
+
+ // Set the Berkeley DB config for opening all stores.
+ //
+ DatabaseConfig dbConfig = new DatabaseConfig();
+ dbConfig.setTransactional(true);
+ dbConfig.setAllowCreate(true);
+ dbConfig.setType(DatabaseType.BTREE);
+
+ // Create the Serial class catalog. This holds the serialized class
+ // format for all database records of serial format.
+ //
+ Database catalogDb = env.openDatabase(null, CLASS_CATALOG, null,
+ dbConfig);
+ javaCatalog = new StoredClassCatalog(catalogDb);
+
+ // Open the Berkeley DB database for the part, supplier and shipment
+ // stores. The stores are opened with no duplicate keys allowed.
+ //
+ partDb = env.openDatabase(null, PART_STORE, null, dbConfig);
+
+ supplierDb = env.openDatabase(null, SUPPLIER_STORE, null, dbConfig);
+
+ shipmentDb = env.openDatabase(null, SHIPMENT_STORE, null, dbConfig);
+
+ // Open the SecondaryDatabase for the city index of the supplier store,
+ // and for the part and supplier indices of the shipment store.
+ // Duplicate keys are allowed since more than one supplier may be in
+ // the same city, and more than one shipment may exist for the same
+ // supplier or part. A foreign key constraint is defined for the
+ // supplier and part indices to ensure that a shipment only refers to
+ // existing part and supplier keys. The CASCADE delete action means
+ // that shipments will be deleted if their associated part or supplier
+ // is deleted.
+ //
+ SecondaryConfig secConfig = new SecondaryConfig();
+ secConfig.setTransactional(true);
+ secConfig.setAllowCreate(true);
+ secConfig.setType(DatabaseType.BTREE);
+ secConfig.setSortedDuplicates(true);
+
+ secConfig.setKeyCreator(
+ new SupplierByCityKeyCreator(javaCatalog,
+ SupplierKey.class,
+ SupplierData.class,
+ String.class));
+ supplierByCityDb = env.openSecondaryDatabase(null, SUPPLIER_CITY_INDEX,
+ null, supplierDb,
+ secConfig);
+
+ secConfig.setForeignKeyDatabase(partDb);
+ secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE);
+ secConfig.setKeyCreator(
+ new ShipmentByPartKeyCreator(javaCatalog,
+ ShipmentKey.class,
+ ShipmentData.class,
+ PartKey.class));
+ shipmentByPartDb = env.openSecondaryDatabase(null, SHIPMENT_PART_INDEX,
+ null, shipmentDb,
+ secConfig);
+
+ secConfig.setForeignKeyDatabase(supplierDb);
+ secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE);
+ secConfig.setKeyCreator(
+ new ShipmentBySupplierKeyCreator(javaCatalog,
+ ShipmentKey.class,
+ ShipmentData.class,
+ SupplierKey.class));
+ shipmentBySupplierDb = env.openSecondaryDatabase(null,
+ SHIPMENT_SUPPLIER_INDEX,
+ null, shipmentDb,
+ secConfig);
+ }
+
+ /**
+ * Return the storage environment for the database.
+ */
+ public final Environment getEnvironment() {
+
+ return env;
+ }
+
+ /**
+ * Return the class catalog.
+ */
+ public final StoredClassCatalog getClassCatalog() {
+
+ return javaCatalog;
+ }
+
+ /**
+ * Return the part storage container.
+ */
+ public final Database getPartDatabase() {
+
+ return partDb;
+ }
+
+ /**
+ * Return the supplier storage container.
+ */
+ public final Database getSupplierDatabase() {
+
+ return supplierDb;
+ }
+
+ /**
+ * Return the shipment storage container.
+ */
+ public final Database getShipmentDatabase() {
+
+ return shipmentDb;
+ }
+
+ /**
+ * Return the shipment-by-part index.
+ */
+ public final SecondaryDatabase getShipmentByPartDatabase() {
+
+ return shipmentByPartDb;
+ }
+
+ /**
+ * Return the shipment-by-supplier index.
+ */
+ public final SecondaryDatabase getShipmentBySupplierDatabase() {
+
+ return shipmentBySupplierDb;
+ }
+
+ /**
+ * Return the supplier-by-city index.
+ */
+ public final SecondaryDatabase getSupplierByCityDatabase() {
+
+ return supplierByCityDb;
+ }
+
+ /**
+ * Close all stores (closing a store automatically closes its indices).
+ */
+ public void close()
+ throws DatabaseException {
+
+ // Close secondary databases, then primary databases.
+ supplierByCityDb.close();
+ shipmentByPartDb.close();
+ shipmentBySupplierDb.close();
+ partDb.close();
+ supplierDb.close();
+ shipmentDb.close();
+ // And don't forget to close the catalog and the environment.
+ javaCatalog.close();
+ env.close();
+ }
+
+ /**
+ * The SecondaryKeyCreator for the SupplierByCity index. This is an
+ * extension of the abstract class SerialSerialKeyCreator, which implements
+ * SecondaryKeyCreator for the case where the data keys and value are all
+ * of the serial format.
+ */
+ private static class SupplierByCityKeyCreator
+ extends SerialSerialKeyCreator {
+
+ /**
+ * Construct the city key extractor.
+ * @param catalog is the class catalog.
+ * @param primaryKeyClass is the supplier key class.
+ * @param valueClass is the supplier value class.
+ * @param indexKeyClass is the city key class.
+ */
+ private SupplierByCityKeyCreator(ClassCatalog catalog,
+ Class primaryKeyClass,
+ Class valueClass,
+ Class indexKeyClass) {
+
+ super(catalog, primaryKeyClass, valueClass, indexKeyClass);
+ }
+
+ /**
+ * Extract the city key from a supplier key/value pair. The city key
+ * is stored in the supplier value, so the supplier key is not used.
+ */
+ public Object createSecondaryKey(Object primaryKeyInput,
+ Object valueInput) {
+
+ SupplierData supplierData = (SupplierData) valueInput;
+ return supplierData.getCity();
+ }
+ }
+
+ /**
+ * The SecondaryKeyCreator for the ShipmentByPart index. This is an
+ * extension of the abstract class SerialSerialKeyCreator, which implements
+ * SecondaryKeyCreator for the case where the data keys and value are all
+ * of the serial format.
+ */
+ private static class ShipmentByPartKeyCreator
+ extends SerialSerialKeyCreator {
+
+ /**
+ * Construct the part key extractor.
+ * @param catalog is the class catalog.
+ * @param primaryKeyClass is the shipment key class.
+ * @param valueClass is the shipment value class.
+ * @param indexKeyClass is the part key class.
+ */
+ private ShipmentByPartKeyCreator(ClassCatalog catalog,
+ Class primaryKeyClass,
+ Class valueClass,
+ Class indexKeyClass) {
+
+ super(catalog, primaryKeyClass, valueClass, indexKeyClass);
+ }
+
+ /**
+ * Extract the part key from a shipment key/value pair. The part key
+ * is stored in the shipment key, so the shipment value is not used.
+ */
+ public Object createSecondaryKey(Object primaryKeyInput,
+ Object valueInput) {
+
+ ShipmentKey shipmentKey = (ShipmentKey) primaryKeyInput;
+ return new PartKey(shipmentKey.getPartNumber());
+ }
+ }
+
+ /**
+ * The SecondaryKeyCreator for the ShipmentBySupplier index. This is an
+ * extension of the abstract class SerialSerialKeyCreator, which implements
+ * SecondaryKeyCreator for the case where the data keys and value are all
+ * of the serial format.
+ */
+ private static class ShipmentBySupplierKeyCreator
+ extends SerialSerialKeyCreator {
+
+ /**
+ * Construct the supplier key extractor.
+ * @param catalog is the class catalog.
+ * @param primaryKeyClass is the shipment key class.
+ * @param valueClass is the shipment value class.
+ * @param indexKeyClass is the supplier key class.
+ */
+ private ShipmentBySupplierKeyCreator(ClassCatalog catalog,
+ Class primaryKeyClass,
+ Class valueClass,
+ Class indexKeyClass) {
+
+ super(catalog, primaryKeyClass, valueClass, indexKeyClass);
+ }
+
+ /**
+ * Extract the supplier key from a shipment key/value pair. The part
+ * key is stored in the shipment key, so the shipment value is not
+ * used.
+ */
+ public Object createSecondaryKey(Object primaryKeyInput,
+ Object valueInput) {
+
+ ShipmentKey shipmentKey = (ShipmentKey) primaryKeyInput;
+ return new SupplierKey(shipmentKey.getSupplierNumber());
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/index/SampleViews.java b/examples_java/src/collections/ship/index/SampleViews.java
new file mode 100644
index 0000000..3c101c9
--- /dev/null
+++ b/examples_java/src/collections/ship/index/SampleViews.java
@@ -0,0 +1,161 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.index;
+
+import com.sleepycat.bind.EntryBinding;
+import com.sleepycat.bind.serial.ClassCatalog;
+import com.sleepycat.bind.serial.SerialBinding;
+import com.sleepycat.collections.StoredEntrySet;
+import com.sleepycat.collections.StoredSortedMap;
+
+/**
+ * SampleViews defines the data bindings and collection views for the sample
+ * database.
+ *
+ * @author Mark Hayes
+ */
+public class SampleViews {
+
+ private StoredSortedMap partMap;
+ private StoredSortedMap supplierMap;
+ private StoredSortedMap shipmentMap;
+ private StoredSortedMap shipmentByPartMap;
+ private StoredSortedMap shipmentBySupplierMap;
+ private StoredSortedMap supplierByCityMap;
+
+ /**
+ * Create the data bindings and collection views.
+ */
+ public SampleViews(SampleDatabase db) {
+
+ // Create the data bindings.
+ // In this sample, the stored key and data entries are used directly
+ // rather than mapping them to separate objects. Therefore, no binding
+ // classes are defined here and the SerialBinding class is used.
+ //
+ ClassCatalog catalog = db.getClassCatalog();
+ EntryBinding partKeyBinding =
+ new SerialBinding(catalog, PartKey.class);
+ EntryBinding partDataBinding =
+ new SerialBinding(catalog, PartData.class);
+ EntryBinding supplierKeyBinding =
+ new SerialBinding(catalog, SupplierKey.class);
+ EntryBinding supplierDataBinding =
+ new SerialBinding(catalog, SupplierData.class);
+ EntryBinding shipmentKeyBinding =
+ new SerialBinding(catalog, ShipmentKey.class);
+ EntryBinding shipmentDataBinding =
+ new SerialBinding(catalog, ShipmentData.class);
+ EntryBinding cityKeyBinding =
+ new SerialBinding(catalog, String.class);
+
+ // Create map views for all stores and indices.
+ // StoredSortedMap is not used since the stores and indices are
+ // ordered by serialized key objects, which do not provide a very
+ // useful ordering.
+ //
+ partMap =
+ new StoredSortedMap(db.getPartDatabase(),
+ partKeyBinding, partDataBinding, true);
+ supplierMap =
+ new StoredSortedMap(db.getSupplierDatabase(),
+ supplierKeyBinding, supplierDataBinding, true);
+ shipmentMap =
+ new StoredSortedMap(db.getShipmentDatabase(),
+ shipmentKeyBinding, shipmentDataBinding, true);
+ shipmentByPartMap =
+ new StoredSortedMap(db.getShipmentByPartDatabase(),
+ partKeyBinding, shipmentDataBinding, true);
+ shipmentBySupplierMap =
+ new StoredSortedMap(db.getShipmentBySupplierDatabase(),
+ supplierKeyBinding, shipmentDataBinding, true);
+ supplierByCityMap =
+ new StoredSortedMap(db.getSupplierByCityDatabase(),
+ cityKeyBinding, supplierDataBinding, true);
+ }
+
+ // The views returned below can be accessed using the java.util.Map or
+ // java.util.Set interfaces, or using the StoredSortedMap and
+ // StoredEntrySet classes, which provide additional methods. The entry
+ // sets could be obtained directly from the Map.entrySet() method, but
+ // convenience methods are provided here to return them in order to avoid
+ // down-casting elsewhere.
+
+ /**
+ * Return a map view of the part storage container.
+ */
+ public final StoredSortedMap getPartMap() {
+
+ return partMap;
+ }
+
+ /**
+ * Return a map view of the supplier storage container.
+ */
+ public final StoredSortedMap getSupplierMap() {
+
+ return supplierMap;
+ }
+
+ /**
+ * Return a map view of the shipment storage container.
+ */
+ public final StoredSortedMap getShipmentMap() {
+
+ return shipmentMap;
+ }
+
+ /**
+ * Return an entry set view of the part storage container.
+ */
+ public final StoredEntrySet getPartEntrySet() {
+
+ return (StoredEntrySet) partMap.entrySet();
+ }
+
+ /**
+ * Return an entry set view of the supplier storage container.
+ */
+ public final StoredEntrySet getSupplierEntrySet() {
+
+ return (StoredEntrySet) supplierMap.entrySet();
+ }
+
+ /**
+ * Return an entry set view of the shipment storage container.
+ */
+ public final StoredEntrySet getShipmentEntrySet() {
+
+ return (StoredEntrySet) shipmentMap.entrySet();
+ }
+
+ /**
+ * Return a map view of the shipment-by-part index.
+ */
+ public StoredSortedMap getShipmentByPartMap() {
+
+ return shipmentByPartMap;
+ }
+
+ /**
+ * Return a map view of the shipment-by-supplier index.
+ */
+ public StoredSortedMap getShipmentBySupplierMap() {
+
+ return shipmentBySupplierMap;
+ }
+
+ /**
+ * Return a map view of the supplier-by-city index.
+ */
+ public final StoredSortedMap getSupplierByCityMap() {
+
+ return supplierByCityMap;
+ }
+}
diff --git a/examples_java/src/collections/ship/index/ShipmentData.java b/examples_java/src/collections/ship/index/ShipmentData.java
new file mode 100644
index 0000000..3a249da
--- /dev/null
+++ b/examples_java/src/collections/ship/index/ShipmentData.java
@@ -0,0 +1,41 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.index;
+
+import java.io.Serializable;
+
+/**
+ * A ShipmentData serves as the data in the key/data pair for a shipment
+ * entity.
+ *
+ * <p> In this sample, ShipmentData is used both as the storage data for the
+ * data as well as the object binding to the data. Because it is used
+ * directly as storage data using serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class ShipmentData implements Serializable {
+
+ private int quantity;
+
+ public ShipmentData(int quantity) {
+
+ this.quantity = quantity;
+ }
+
+ public final int getQuantity() {
+
+ return quantity;
+ }
+
+ public String toString() {
+
+ return "[ShipmentData: quantity=" + quantity + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/index/ShipmentKey.java b/examples_java/src/collections/ship/index/ShipmentKey.java
new file mode 100644
index 0000000..63d1a18
--- /dev/null
+++ b/examples_java/src/collections/ship/index/ShipmentKey.java
@@ -0,0 +1,48 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.index;
+
+import java.io.Serializable;
+
+/**
+ * A ShipmentKey serves as the key in the key/data pair for a shipment entity.
+ *
+ * <p> In this sample, ShipmentKey is used both as the storage data for the key
+ * as well as the object binding to the key. Because it is used directly as
+ * storage data using serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class ShipmentKey implements Serializable {
+
+ private String partNumber;
+ private String supplierNumber;
+
+ public ShipmentKey(String partNumber, String supplierNumber) {
+
+ this.partNumber = partNumber;
+ this.supplierNumber = supplierNumber;
+ }
+
+ public final String getPartNumber() {
+
+ return partNumber;
+ }
+
+ public final String getSupplierNumber() {
+
+ return supplierNumber;
+ }
+
+ public String toString() {
+
+ return "[ShipmentKey: supplier=" + supplierNumber +
+ " part=" + partNumber + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/index/SupplierData.java b/examples_java/src/collections/ship/index/SupplierData.java
new file mode 100644
index 0000000..46727f2
--- /dev/null
+++ b/examples_java/src/collections/ship/index/SupplierData.java
@@ -0,0 +1,57 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.index;
+
+import java.io.Serializable;
+
+/**
+ * A SupplierData serves as the data in the key/data pair for a supplier
+ * entity.
+ *
+ * <p> In this sample, SupplierData is used both as the storage data for the
+ * data as well as the object binding to the data. Because it is used
+ * directly as storage data using serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class SupplierData implements Serializable {
+
+ private String name;
+ private int status;
+ private String city;
+
+ public SupplierData(String name, int status, String city) {
+
+ this.name = name;
+ this.status = status;
+ this.city = city;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final int getStatus() {
+
+ return status;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[SupplierData: name=" + name +
+ " status=" + status +
+ " city=" + city + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/index/SupplierKey.java b/examples_java/src/collections/ship/index/SupplierKey.java
new file mode 100644
index 0000000..71b8f22
--- /dev/null
+++ b/examples_java/src/collections/ship/index/SupplierKey.java
@@ -0,0 +1,40 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.index;
+
+import java.io.Serializable;
+
+/**
+ * A SupplierKey serves as the key in the key/data pair for a supplier entity.
+ *
+ * <p> In this sample, SupplierKey is used both as the storage data for the key
+ * as well as the object binding to the key. Because it is used directly as
+ * storage data using serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class SupplierKey implements Serializable {
+
+ private String number;
+
+ public SupplierKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public String toString() {
+
+ return "[SupplierKey: number=" + number + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/index/Weight.java b/examples_java/src/collections/ship/index/Weight.java
new file mode 100644
index 0000000..ee93d29
--- /dev/null
+++ b/examples_java/src/collections/ship/index/Weight.java
@@ -0,0 +1,49 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.index;
+
+import java.io.Serializable;
+
+/**
+ * Weight represents a weight amount and unit of measure.
+ *
+ * <p> In this sample, Weight is embedded in part data values which are stored
+ * as Serial serialized objects; therefore Weight must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Weight implements Serializable {
+
+ public final static String GRAMS = "grams";
+ public final static String OUNCES = "ounces";
+
+ private double amount;
+ private String units;
+
+ public Weight(double amount, String units) {
+
+ this.amount = amount;
+ this.units = units;
+ }
+
+ public final double getAmount() {
+
+ return amount;
+ }
+
+ public final String getUnits() {
+
+ return units;
+ }
+
+ public String toString() {
+
+ return "[" + amount + ' ' + units + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/marshal/MarshalledEnt.java b/examples_java/src/collections/ship/marshal/MarshalledEnt.java
new file mode 100644
index 0000000..fefa2be
--- /dev/null
+++ b/examples_java/src/collections/ship/marshal/MarshalledEnt.java
@@ -0,0 +1,42 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.marshal;
+
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+/**
+ * MarshalledEnt is implemented by entity (combined key/data) objects and
+ * called by {@link SampleViews.MarshalledEntityBinding}. In this sample,
+ * MarshalledEnt is implemented by {@link Part}, {@link Supplier}, and
+ * {@link Shipment}. This interface is package-protected rather than public
+ * to hide the marshalling interface from other users of the data objects.
+ * Note that a MarshalledEnt must also have a no arguments constructor so
+ * that it can be instantiated by the binding.
+ *
+ * @author Mark Hayes
+ */
+interface MarshalledEnt {
+
+ /**
+ * Extracts the entity's primary key and writes it to the key output.
+ */
+ void marshalPrimaryKey(TupleOutput keyOutput);
+
+ /**
+ * Completes construction of the entity by setting its primary key from the
+ * stored primary key.
+ */
+ void unmarshalPrimaryKey(TupleInput keyInput);
+
+ /**
+ * Extracts the entity's index key and writes it to the key output.
+ */
+ boolean marshalSecondaryKey(String keyName, TupleOutput keyOutput);
+}
diff --git a/examples_java/src/collections/ship/marshal/MarshalledKey.java b/examples_java/src/collections/ship/marshal/MarshalledKey.java
new file mode 100644
index 0000000..8e2d171
--- /dev/null
+++ b/examples_java/src/collections/ship/marshal/MarshalledKey.java
@@ -0,0 +1,36 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.marshal;
+
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+/**
+ * MarshalledKey is implemented by key objects and called by {@link
+ * SampleViews.MarshalledKeyBinding}. In this sample, MarshalledKey is
+ * implemented by {@link PartKey}, {@link SupplierKey}, and {@link
+ * ShipmentKey}. This interface is package-protected rather than public to
+ * hide the marshalling interface from other users of the data objects. Note
+ * that a MarshalledKey must also have a no arguments constructor so
+ * that it can be instantiated by the binding.
+ *
+ * @author Mark Hayes
+ */
+interface MarshalledKey {
+
+ /**
+ * Construct the key tuple entry from the key object.
+ */
+ void marshalKey(TupleOutput keyOutput);
+
+ /**
+ * Construct the key object from the key tuple entry.
+ */
+ void unmarshalKey(TupleInput keyInput);
+}
diff --git a/examples_java/src/collections/ship/marshal/Part.java b/examples_java/src/collections/ship/marshal/Part.java
new file mode 100644
index 0000000..ba0a758
--- /dev/null
+++ b/examples_java/src/collections/ship/marshal/Part.java
@@ -0,0 +1,116 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.marshal;
+
+import java.io.Serializable;
+
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+/**
+ * A Part represents the combined key/data pair for a part entity.
+ *
+ * <p> In this sample, Part is bound to the stored key/data entry by
+ * implementing the MarshalledEnt interface, which is called by {@link
+ * SampleViews.MarshalledEntityBinding}. </p>
+ *
+ * <p> The binding is "tricky" in that it uses this class for both the stored
+ * data entry and the combined entity object. To do this, the key field(s) are
+ * transient and are set by the binding after the data object has been
+ * deserialized. This avoids the use of a PartData class completely. </p>
+ *
+ * <p> Since this class is used directly for data storage, it must be
+ * Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Part implements Serializable, MarshalledEnt {
+
+ private transient String number;
+ private String name;
+ private String color;
+ private Weight weight;
+ private String city;
+
+ public Part(String number, String name, String color, Weight weight,
+ String city) {
+
+ this.number = number;
+ this.name = name;
+ this.color = color;
+ this.weight = weight;
+ this.city = city;
+ }
+
+ /**
+ * Set the transient key fields after deserializing. This method is only
+ * called by data bindings.
+ */
+ final void setKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final String getColor() {
+
+ return color;
+ }
+
+ public final Weight getWeight() {
+
+ return weight;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[Part: number=" + number +
+ " name=" + name +
+ " color=" + color +
+ " weight=" + weight +
+ " city=" + city + ']';
+ }
+
+ // --- MarshalledEnt implementation ---
+
+ Part() {
+
+ // A no-argument constructor is necessary only to allow the binding to
+ // instantiate objects of this class.
+ }
+
+ public void unmarshalPrimaryKey(TupleInput keyInput) {
+
+ this.number = keyInput.readString();
+ }
+
+ public void marshalPrimaryKey(TupleOutput keyOutput) {
+
+ keyOutput.writeString(this.number);
+ }
+
+ public boolean marshalSecondaryKey(String keyName, TupleOutput keyOutput) {
+
+ throw new UnsupportedOperationException(keyName);
+ }
+}
diff --git a/examples_java/src/collections/ship/marshal/PartKey.java b/examples_java/src/collections/ship/marshal/PartKey.java
new file mode 100644
index 0000000..fc81535
--- /dev/null
+++ b/examples_java/src/collections/ship/marshal/PartKey.java
@@ -0,0 +1,59 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.marshal;
+
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+/**
+ * A PartKey serves as the key in the key/data pair for a part entity.
+ *
+ * <p> In this sample, PartKey is bound to the stored key tuple entry by
+ * implementing the MarshalledKey interface, which is called by {@link
+ * SampleViews.MarshalledKeyBinding}. </p>
+ *
+ * @author Mark Hayes
+ */
+public class PartKey implements MarshalledKey {
+
+ private String number;
+
+ public PartKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public String toString() {
+
+ return "[PartKey: number=" + number + ']';
+ }
+
+ // --- MarshalledKey implementation ---
+
+ PartKey() {
+
+ // A no-argument constructor is necessary only to allow the binding to
+ // instantiate objects of this class.
+ }
+
+ public void unmarshalKey(TupleInput keyInput) {
+
+ this.number = keyInput.readString();
+ }
+
+ public void marshalKey(TupleOutput keyOutput) {
+
+ keyOutput.writeString(this.number);
+ }
+}
diff --git a/examples_java/src/collections/ship/marshal/Sample.java b/examples_java/src/collections/ship/marshal/Sample.java
new file mode 100644
index 0000000..4789921
--- /dev/null
+++ b/examples_java/src/collections/ship/marshal/Sample.java
@@ -0,0 +1,236 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.marshal;
+
+import java.io.FileNotFoundException;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.sleepycat.collections.TransactionRunner;
+import com.sleepycat.collections.TransactionWorker;
+import com.sleepycat.db.DatabaseException;
+
+/**
+ * Sample is the main entry point for the sample program and may be run as
+ * follows:
+ *
+ * <pre>
+ * java collections.ship.marshal.Sample
+ * [-h <home-directory> ]
+ * </pre>
+ *
+ * <p> The default for the home directory is ./tmp -- the tmp subdirectory of
+ * the current directory where the sample is run. To specify a different home
+ * directory, use the -home option. The home directory must exist before
+ * running the sample. To recreate the sample database from scratch, delete
+ * all files in the home directory before running the sample. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Sample {
+
+ private SampleDatabase db;
+ private SampleViews views;
+
+ /**
+ * Run the sample program.
+ */
+ public static void main(String[] args) {
+
+ System.out.println("\nRunning sample: " + Sample.class);
+
+ // Parse the command line arguments.
+ //
+ String homeDir = "./tmp";
+ for (int i = 0; i < args.length; i += 1) {
+ if (args[i].equals("-h") && i < args.length - 1) {
+ i += 1;
+ homeDir = args[i];
+ } else {
+ System.err.println("Usage:\n java " + Sample.class.getName() +
+ "\n [-h <home-directory>]");
+ System.exit(2);
+ }
+ }
+
+ // Run the sample.
+ //
+ Sample sample = null;
+ try {
+ sample = new Sample(homeDir);
+ sample.run();
+ } catch (Exception e) {
+ // If an exception reaches this point, the last transaction did not
+ // complete. If the exception is RunRecoveryException, follow
+ // the Berkeley DB recovery procedures before running again.
+ e.printStackTrace();
+ } finally {
+ if (sample != null) {
+ try {
+ // Always attempt to close the database cleanly.
+ sample.close();
+ } catch (Exception e) {
+ System.err.println("Exception during database close:");
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Open the database and views.
+ */
+ private Sample(String homeDir)
+ throws DatabaseException, FileNotFoundException {
+
+ db = new SampleDatabase(homeDir);
+ views = new SampleViews(db);
+ }
+
+ /**
+ * Close the database cleanly.
+ */
+ private void close()
+ throws DatabaseException {
+
+ db.close();
+ }
+
+ /**
+ * Run two transactions to populate and print the database. A
+ * TransactionRunner is used to ensure consistent handling of transactions,
+ * including deadlock retries. But the best transaction handling mechanism
+ * to use depends on the application.
+ */
+ private void run()
+ throws Exception {
+
+ TransactionRunner runner = new TransactionRunner(db.getEnvironment());
+ runner.run(new PopulateDatabase());
+ runner.run(new PrintDatabase());
+ }
+
+ /**
+ * Populate the database in a single transaction.
+ */
+ private class PopulateDatabase implements TransactionWorker {
+
+ public void doWork()
+ throws Exception {
+ addSuppliers();
+ addParts();
+ addShipments();
+ }
+ }
+
+ /**
+ * Print the database in a single transaction. All entities are printed
+ * and the indices are used to print the entities for certain keys.
+ *
+ * <p> Note the use of special iterator() methods. These are used here
+ * with indices to find the shipments for certain keys.</p>
+ */
+ private class PrintDatabase implements TransactionWorker {
+
+ public void doWork()
+ throws Exception {
+ printValues("Parts",
+ views.getPartSet().iterator());
+ printValues("Suppliers",
+ views.getSupplierSet().iterator());
+ printValues("Suppliers for City Paris",
+ views.getSupplierByCityMap().duplicates(
+ "Paris").iterator());
+ printValues("Shipments",
+ views.getShipmentSet().iterator());
+ printValues("Shipments for Part P1",
+ views.getShipmentByPartMap().duplicates(
+ new PartKey("P1")).iterator());
+ printValues("Shipments for Supplier S1",
+ views.getShipmentBySupplierMap().duplicates(
+ new SupplierKey("S1")).iterator());
+ }
+ }
+
+ /**
+ * Populate the part entities in the database. If the part set is not
+ * empty, assume that this has already been done.
+ */
+ private void addParts() {
+
+ Set parts = views.getPartSet();
+ if (parts.isEmpty()) {
+ System.out.println("Adding Parts");
+ parts.add(new Part("P1", "Nut", "Red",
+ new Weight(12.0, Weight.GRAMS), "London"));
+ parts.add(new Part("P2", "Bolt", "Green",
+ new Weight(17.0, Weight.GRAMS), "Paris"));
+ parts.add(new Part("P3", "Screw", "Blue",
+ new Weight(17.0, Weight.GRAMS), "Rome"));
+ parts.add(new Part("P4", "Screw", "Red",
+ new Weight(14.0, Weight.GRAMS), "London"));
+ parts.add(new Part("P5", "Cam", "Blue",
+ new Weight(12.0, Weight.GRAMS), "Paris"));
+ parts.add(new Part("P6", "Cog", "Red",
+ new Weight(19.0, Weight.GRAMS), "London"));
+ }
+ }
+
+ /**
+ * Populate the supplier entities in the database. If the supplier set is
+ * not empty, assume that this has already been done.
+ */
+ private void addSuppliers() {
+
+ Set suppliers = views.getSupplierSet();
+ if (suppliers.isEmpty()) {
+ System.out.println("Adding Suppliers");
+ suppliers.add(new Supplier("S1", "Smith", 20, "London"));
+ suppliers.add(new Supplier("S2", "Jones", 10, "Paris"));
+ suppliers.add(new Supplier("S3", "Blake", 30, "Paris"));
+ suppliers.add(new Supplier("S4", "Clark", 20, "London"));
+ suppliers.add(new Supplier("S5", "Adams", 30, "Athens"));
+ }
+ }
+
+ /**
+ * Populate the shipment entities in the database. If the shipment set
+ * is not empty, assume that this has already been done.
+ */
+ private void addShipments() {
+
+ Set shipments = views.getShipmentSet();
+ if (shipments.isEmpty()) {
+ System.out.println("Adding Shipments");
+ shipments.add(new Shipment("P1", "S1", 300));
+ shipments.add(new Shipment("P2", "S1", 200));
+ shipments.add(new Shipment("P3", "S1", 400));
+ shipments.add(new Shipment("P4", "S1", 200));
+ shipments.add(new Shipment("P5", "S1", 100));
+ shipments.add(new Shipment("P6", "S1", 100));
+ shipments.add(new Shipment("P1", "S2", 300));
+ shipments.add(new Shipment("P2", "S2", 400));
+ shipments.add(new Shipment("P2", "S3", 200));
+ shipments.add(new Shipment("P2", "S4", 200));
+ shipments.add(new Shipment("P4", "S4", 300));
+ shipments.add(new Shipment("P5", "S4", 400));
+ }
+ }
+
+ /**
+ * Print the objects returned by an iterator of entity value objects.
+ */
+ private void printValues(String label, Iterator iterator) {
+
+ System.out.println("\n--- " + label + " ---");
+ while (iterator.hasNext()) {
+ System.out.println(iterator.next().toString());
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/marshal/SampleDatabase.java b/examples_java/src/collections/ship/marshal/SampleDatabase.java
new file mode 100644
index 0000000..53df679
--- /dev/null
+++ b/examples_java/src/collections/ship/marshal/SampleDatabase.java
@@ -0,0 +1,260 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.marshal;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import com.sleepycat.bind.serial.ClassCatalog;
+import com.sleepycat.bind.serial.StoredClassCatalog;
+import com.sleepycat.bind.serial.TupleSerialKeyCreator;
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+import com.sleepycat.db.Database;
+import com.sleepycat.db.DatabaseConfig;
+import com.sleepycat.db.DatabaseException;
+import com.sleepycat.db.DatabaseType;
+import com.sleepycat.db.Environment;
+import com.sleepycat.db.EnvironmentConfig;
+import com.sleepycat.db.ForeignKeyDeleteAction;
+import com.sleepycat.db.SecondaryConfig;
+import com.sleepycat.db.SecondaryDatabase;
+
+/**
+ * SampleDatabase defines the storage containers, indices and foreign keys
+ * for the sample database.
+ *
+ * @author Mark Hayes
+ */
+public class SampleDatabase {
+
+ private static final String CLASS_CATALOG = "java_class_catalog";
+ private static final String SUPPLIER_STORE = "supplier_store";
+ private static final String PART_STORE = "part_store";
+ private static final String SHIPMENT_STORE = "shipment_store";
+ private static final String SHIPMENT_PART_INDEX = "shipment_part_index";
+ private static final String SHIPMENT_SUPPLIER_INDEX =
+ "shipment_supplier_index";
+ private static final String SUPPLIER_CITY_INDEX = "supplier_city_index";
+
+ private Environment env;
+ private Database partDb;
+ private Database supplierDb;
+ private Database shipmentDb;
+ private SecondaryDatabase supplierByCityDb;
+ private SecondaryDatabase shipmentByPartDb;
+ private SecondaryDatabase shipmentBySupplierDb;
+ private StoredClassCatalog javaCatalog;
+
+ /**
+ * Open all storage containers, indices, and catalogs.
+ */
+ public SampleDatabase(String homeDirectory)
+ throws DatabaseException, FileNotFoundException {
+
+ // Open the Berkeley DB environment in transactional mode.
+ //
+ System.out.println("Opening environment in: " + homeDirectory);
+ EnvironmentConfig envConfig = new EnvironmentConfig();
+ envConfig.setTransactional(true);
+ envConfig.setAllowCreate(true);
+ envConfig.setInitializeCache(true);
+ envConfig.setInitializeLocking(true);
+ env = new Environment(new File(homeDirectory), envConfig);
+
+ // Set the Berkeley DB config for opening all stores.
+ //
+ DatabaseConfig dbConfig = new DatabaseConfig();
+ dbConfig.setTransactional(true);
+ dbConfig.setAllowCreate(true);
+ dbConfig.setType(DatabaseType.BTREE);
+
+ // Create the Serial class catalog. This holds the serialized class
+ // format for all database records of serial format.
+ //
+ Database catalogDb = env.openDatabase(null, CLASS_CATALOG, null,
+ dbConfig);
+ javaCatalog = new StoredClassCatalog(catalogDb);
+
+ // Open the Berkeley DB database for the part, supplier and shipment
+ // stores. The stores are opened with no duplicate keys allowed.
+ //
+ partDb = env.openDatabase(null, PART_STORE, null, dbConfig);
+
+ supplierDb = env.openDatabase(null, SUPPLIER_STORE, null, dbConfig);
+
+ shipmentDb = env.openDatabase(null, SHIPMENT_STORE, null, dbConfig);
+
+ // Open the SecondaryDatabase for the city index of the supplier store,
+ // and for the part and supplier indices of the shipment store.
+ // Duplicate keys are allowed since more than one supplier may be in
+ // the same city, and more than one shipment may exist for the same
+ // supplier or part. A foreign key constraint is defined for the
+ // supplier and part indices to ensure that a shipment only refers to
+ // existing part and supplier keys. The CASCADE delete action means
+ // that shipments will be deleted if their associated part or supplier
+ // is deleted.
+ //
+ SecondaryConfig secConfig = new SecondaryConfig();
+ secConfig.setTransactional(true);
+ secConfig.setAllowCreate(true);
+ secConfig.setType(DatabaseType.BTREE);
+ secConfig.setSortedDuplicates(true);
+
+ secConfig.setKeyCreator(new MarshalledKeyCreator(javaCatalog,
+ Supplier.class,
+ Supplier.CITY_KEY));
+ supplierByCityDb = env.openSecondaryDatabase(null, SUPPLIER_CITY_INDEX,
+ null, supplierDb,
+ secConfig);
+
+ secConfig.setForeignKeyDatabase(partDb);
+ secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE);
+ secConfig.setKeyCreator(new MarshalledKeyCreator(javaCatalog,
+ Shipment.class,
+ Shipment.PART_KEY));
+ shipmentByPartDb = env.openSecondaryDatabase(null, SHIPMENT_PART_INDEX,
+ null, shipmentDb,
+ secConfig);
+
+ secConfig.setForeignKeyDatabase(supplierDb);
+ secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE);
+ secConfig.setKeyCreator(new MarshalledKeyCreator(javaCatalog,
+ Shipment.class,
+ Shipment.SUPPLIER_KEY));
+ shipmentBySupplierDb = env.openSecondaryDatabase(null,
+ SHIPMENT_SUPPLIER_INDEX,
+ null, shipmentDb,
+ secConfig);
+ }
+
+ /**
+ * Return the storage environment for the database.
+ */
+ public final Environment getEnvironment() {
+
+ return env;
+ }
+
+ /**
+ * Return the class catalog.
+ */
+ public final StoredClassCatalog getClassCatalog() {
+
+ return javaCatalog;
+ }
+
+ /**
+ * Return the part storage container.
+ */
+ public final Database getPartDatabase() {
+
+ return partDb;
+ }
+
+ /**
+ * Return the supplier storage container.
+ */
+ public final Database getSupplierDatabase() {
+
+ return supplierDb;
+ }
+
+ /**
+ * Return the shipment storage container.
+ */
+ public final Database getShipmentDatabase() {
+
+ return shipmentDb;
+ }
+
+ /**
+ * Return the shipment-by-part index.
+ */
+ public final SecondaryDatabase getShipmentByPartDatabase() {
+
+ return shipmentByPartDb;
+ }
+
+ /**
+ * Return the shipment-by-supplier index.
+ */
+ public final SecondaryDatabase getShipmentBySupplierDatabase() {
+
+ return shipmentBySupplierDb;
+ }
+
+ /**
+ * Return the supplier-by-city index.
+ */
+ public final SecondaryDatabase getSupplierByCityDatabase() {
+
+ return supplierByCityDb;
+ }
+
+ /**
+ * Close all stores (closing a store automatically closes its indices).
+ */
+ public void close()
+ throws DatabaseException {
+
+ // Close secondary databases, then primary databases.
+ supplierByCityDb.close();
+ shipmentByPartDb.close();
+ shipmentBySupplierDb.close();
+ partDb.close();
+ supplierDb.close();
+ shipmentDb.close();
+ // And don't forget to close the catalog and the environment.
+ javaCatalog.close();
+ env.close();
+ }
+
+ /**
+ * The SecondaryKeyCreator for MarshalledEnt objects. This is an
+ * extension of the abstract class TupleSerialKeyCreator, which implements
+ * SecondaryKeyCreator for the case where the data keys are of the format
+ * TupleFormat and the data values are of the format SerialFormat.
+ */
+ private static class MarshalledKeyCreator
+ extends TupleSerialKeyCreator {
+
+ private String keyName;
+
+ /**
+ * Construct the key creator.
+ * @param catalog is the class catalog.
+ * @param valueClass is the supplier value class.
+ * @param keyName is the key name passed to the marshalling methods.
+ */
+ private MarshalledKeyCreator(ClassCatalog catalog,
+ Class valueClass,
+ String keyName) {
+
+ super(catalog, valueClass);
+ this.keyName = keyName;
+ }
+
+ /**
+ * Extract the city key from a supplier key/value pair. The city key
+ * is stored in the supplier value, so the supplier key is not used.
+ */
+ public boolean createSecondaryKey(TupleInput primaryKeyInput,
+ Object valueInput,
+ TupleOutput indexKeyOutput) {
+
+ // the primary key is unmarshalled before marshalling the index
+ // key, to account for cases where the index key is composed of
+ // data elements from the primary key
+ MarshalledEnt entity = (MarshalledEnt) valueInput;
+ entity.unmarshalPrimaryKey(primaryKeyInput);
+ return entity.marshalSecondaryKey(keyName, indexKeyOutput);
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/marshal/SampleViews.java b/examples_java/src/collections/ship/marshal/SampleViews.java
new file mode 100644
index 0000000..91310e4
--- /dev/null
+++ b/examples_java/src/collections/ship/marshal/SampleViews.java
@@ -0,0 +1,276 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.marshal;
+
+import com.sleepycat.bind.EntityBinding;
+import com.sleepycat.bind.EntryBinding;
+import com.sleepycat.bind.serial.ClassCatalog;
+import com.sleepycat.bind.serial.TupleSerialBinding;
+import com.sleepycat.bind.tuple.TupleBinding;
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+import com.sleepycat.collections.StoredSortedMap;
+import com.sleepycat.collections.StoredSortedValueSet;
+import com.sleepycat.util.RuntimeExceptionWrapper;
+
+/**
+ * SampleViews defines the data bindings and collection views for the sample
+ * database.
+ *
+ * @author Mark Hayes
+ */
+public class SampleViews {
+
+ private StoredSortedMap partMap;
+ private StoredSortedMap supplierMap;
+ private StoredSortedMap shipmentMap;
+ private StoredSortedMap shipmentByPartMap;
+ private StoredSortedMap shipmentBySupplierMap;
+ private StoredSortedMap supplierByCityMap;
+
+ /**
+ * Create the data bindings and collection views.
+ */
+ public SampleViews(SampleDatabase db) {
+
+ // Create the data bindings.
+ // In this sample, EntityBinding classes are used to bind the stored
+ // key/data entry pair to a combined data object; a "tricky" binding
+ // that uses transient fields is used--see PartBinding, etc, for
+ // details. For keys, a one-to-one binding is implemented with
+ // EntryBinding classes to bind the stored tuple entry to a key Object.
+ //
+ ClassCatalog catalog = db.getClassCatalog();
+ EntryBinding partKeyBinding =
+ new MarshalledKeyBinding(PartKey.class);
+ EntityBinding partDataBinding =
+ new MarshalledEntityBinding(catalog, Part.class);
+ EntryBinding supplierKeyBinding =
+ new MarshalledKeyBinding(SupplierKey.class);
+ EntityBinding supplierDataBinding =
+ new MarshalledEntityBinding(catalog, Supplier.class);
+ EntryBinding shipmentKeyBinding =
+ new MarshalledKeyBinding(ShipmentKey.class);
+ EntityBinding shipmentDataBinding =
+ new MarshalledEntityBinding(catalog, Shipment.class);
+ EntryBinding cityKeyBinding =
+ TupleBinding.getPrimitiveBinding(String.class);
+
+ // Create map views for all stores and indices.
+ // StoredSortedMap is used since the stores and indices are ordered
+ // (they use the DB_BTREE access method).
+ //
+ partMap =
+ new StoredSortedMap(db.getPartDatabase(),
+ partKeyBinding, partDataBinding, true);
+ supplierMap =
+ new StoredSortedMap(db.getSupplierDatabase(),
+ supplierKeyBinding, supplierDataBinding, true);
+ shipmentMap =
+ new StoredSortedMap(db.getShipmentDatabase(),
+ shipmentKeyBinding, shipmentDataBinding, true);
+ shipmentByPartMap =
+ new StoredSortedMap(db.getShipmentByPartDatabase(),
+ partKeyBinding, shipmentDataBinding, true);
+ shipmentBySupplierMap =
+ new StoredSortedMap(db.getShipmentBySupplierDatabase(),
+ supplierKeyBinding, shipmentDataBinding, true);
+ supplierByCityMap =
+ new StoredSortedMap(db.getSupplierByCityDatabase(),
+ cityKeyBinding, supplierDataBinding, true);
+ }
+
+ // The views returned below can be accessed using the java.util.Map or
+ // java.util.Set interfaces, or using the StoredSortedMap and
+ // StoredValueSet classes, which provide additional methods. The entity
+ // sets could be obtained directly from the Map.values() method but
+ // convenience methods are provided here to return them in order to avoid
+ // down-casting elsewhere.
+
+ /**
+ * Return a map view of the part storage container.
+ */
+ public StoredSortedMap getPartMap() {
+
+ return partMap;
+ }
+
+ /**
+ * Return a map view of the supplier storage container.
+ */
+ public StoredSortedMap getSupplierMap() {
+
+ return supplierMap;
+ }
+
+ /**
+ * Return a map view of the shipment storage container.
+ */
+ public StoredSortedMap getShipmentMap() {
+
+ return shipmentMap;
+ }
+
+ /**
+ * Return an entity set view of the part storage container.
+ */
+ public StoredSortedValueSet getPartSet() {
+
+ return (StoredSortedValueSet) partMap.values();
+ }
+
+ /**
+ * Return an entity set view of the supplier storage container.
+ */
+ public StoredSortedValueSet getSupplierSet() {
+
+ return (StoredSortedValueSet) supplierMap.values();
+ }
+
+ /**
+ * Return an entity set view of the shipment storage container.
+ */
+ public StoredSortedValueSet getShipmentSet() {
+
+ return (StoredSortedValueSet) shipmentMap.values();
+ }
+
+ /**
+ * Return a map view of the shipment-by-part index.
+ */
+ public StoredSortedMap getShipmentByPartMap() {
+
+ return shipmentByPartMap;
+ }
+
+ /**
+ * Return a map view of the shipment-by-supplier index.
+ */
+ public StoredSortedMap getShipmentBySupplierMap() {
+
+ return shipmentBySupplierMap;
+ }
+
+ /**
+ * Return a map view of the supplier-by-city index.
+ */
+ public final StoredSortedMap getSupplierByCityMap() {
+
+ return supplierByCityMap;
+ }
+
+ /**
+ * MarshalledKeyBinding is used to bind the stored key tuple entry to a key
+ * object representation. To do this, it calls the MarshalledKey interface
+ * implemented by the key class.
+ */
+ private static class MarshalledKeyBinding extends TupleBinding {
+
+ private Class keyClass;
+
+ /**
+ * Construct the binding object.
+ */
+ private MarshalledKeyBinding(Class keyClass) {
+
+ // The key class will be used to instantiate the key object.
+ //
+ if (!MarshalledKey.class.isAssignableFrom(keyClass)) {
+ throw new IllegalArgumentException(keyClass.toString() +
+ " does not implement MarshalledKey");
+ }
+ this.keyClass = keyClass;
+ }
+
+ /**
+ * Create the key object from the stored key tuple entry.
+ */
+ public Object entryToObject(TupleInput input) {
+
+ try {
+ MarshalledKey key = (MarshalledKey) keyClass.newInstance();
+ key.unmarshalKey(input);
+ return key;
+ } catch (IllegalAccessException e) {
+ throw new RuntimeExceptionWrapper(e);
+ } catch (InstantiationException e) {
+ throw new RuntimeExceptionWrapper(e);
+ }
+ }
+
+ /**
+ * Create the stored key tuple entry from the key object.
+ */
+ public void objectToEntry(Object object, TupleOutput output) {
+
+ MarshalledKey key = (MarshalledKey) object;
+ key.marshalKey(output);
+ }
+ }
+
+ /**
+ * MarshalledEntityBinding is used to bind the stored key/data entry pair
+ * to a combined to an entity object representation. To do this, it calls
+ * the MarshalledEnt interface implemented by the entity class.
+ *
+ * <p> The binding is "tricky" in that it uses the entity class for both
+ * the stored data entry and the combined entity object. To do this,
+ * entity's key field(s) are transient and are set by the binding after the
+ * data object has been deserialized. This avoids the use of a "data" class
+ * completely. </p>
+ */
+ private static class MarshalledEntityBinding extends TupleSerialBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private MarshalledEntityBinding(ClassCatalog classCatalog,
+ Class entityClass) {
+
+ super(classCatalog, entityClass);
+
+ // The entity class will be used to instantiate the entity object.
+ //
+ if (!MarshalledEnt.class.isAssignableFrom(entityClass)) {
+ throw new IllegalArgumentException(entityClass.toString() +
+ " does not implement MarshalledEnt");
+ }
+ }
+
+ /**
+ * Create the entity by combining the stored key and data.
+ * This "tricky" binding returns the stored data as the entity, but
+ * first it sets the transient key fields from the stored key.
+ */
+ public Object entryToObject(TupleInput tupleInput, Object javaInput) {
+
+ MarshalledEnt entity = (MarshalledEnt) javaInput;
+ entity.unmarshalPrimaryKey(tupleInput);
+ return entity;
+ }
+
+ /**
+ * Create the stored key from the entity.
+ */
+ public void objectToKey(Object object, TupleOutput output) {
+
+ MarshalledEnt entity = (MarshalledEnt) object;
+ entity.marshalPrimaryKey(output);
+ }
+
+ /**
+ * Return the entity as the stored data. There is nothing to do here
+ * since the entity's key fields are transient.
+ */
+ public Object objectToData(Object object) {
+
+ return object;
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/marshal/Shipment.java b/examples_java/src/collections/ship/marshal/Shipment.java
new file mode 100644
index 0000000..bbc2ccb
--- /dev/null
+++ b/examples_java/src/collections/ship/marshal/Shipment.java
@@ -0,0 +1,113 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.marshal;
+
+import java.io.Serializable;
+
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+/**
+ * A Shipment represents the combined key/data pair for a shipment entity.
+ *
+ * <p> In this sample, Shipment is bound to the stored key/data entry by
+ * implementing the MarshalledEnt interface, which is called by {@link
+ * SampleViews.MarshalledEntityBinding}. </p>
+ *
+ * <p> The binding is "tricky" in that it uses this class for both the stored
+ * data entry and the combined entity object. To do this, the key field(s) are
+ * transient and are set by the binding after the data object has been
+ * deserialized. This avoids the use of a ShipmentData class completely. </p>
+ *
+ * <p> Since this class is used directly for data storage, it must be
+ * Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Shipment implements Serializable, MarshalledEnt {
+
+ static final String PART_KEY = "part";
+ static final String SUPPLIER_KEY = "supplier";
+
+ private transient String partNumber;
+ private transient String supplierNumber;
+ private int quantity;
+
+ public Shipment(String partNumber, String supplierNumber, int quantity) {
+
+ this.partNumber = partNumber;
+ this.supplierNumber = supplierNumber;
+ this.quantity = quantity;
+ }
+
+ /**
+ * Set the transient key fields after deserializing. This method is only
+ * called by data bindings.
+ */
+ void setKey(String partNumber, String supplierNumber) {
+
+ this.partNumber = partNumber;
+ this.supplierNumber = supplierNumber;
+ }
+
+ public final String getPartNumber() {
+
+ return partNumber;
+ }
+
+ public final String getSupplierNumber() {
+
+ return supplierNumber;
+ }
+
+ public final int getQuantity() {
+
+ return quantity;
+ }
+
+ public String toString() {
+
+ return "[Shipment: part=" + partNumber +
+ " supplier=" + supplierNumber +
+ " quantity=" + quantity + ']';
+ }
+
+ // --- MarshalledEnt implementation ---
+
+ Shipment() {
+
+ // A no-argument constructor is necessary only to allow the binding to
+ // instantiate objects of this class.
+ }
+
+ public void unmarshalPrimaryKey(TupleInput keyInput) {
+
+ this.partNumber = keyInput.readString();
+ this.supplierNumber = keyInput.readString();
+ }
+
+ public void marshalPrimaryKey(TupleOutput keyOutput) {
+
+ keyOutput.writeString(this.partNumber);
+ keyOutput.writeString(this.supplierNumber);
+ }
+
+ public boolean marshalSecondaryKey(String keyName, TupleOutput keyOutput) {
+
+ if (keyName.equals(PART_KEY)) {
+ keyOutput.writeString(this.partNumber);
+ return true;
+ } else if (keyName.equals(SUPPLIER_KEY)) {
+ keyOutput.writeString(this.supplierNumber);
+ return true;
+ } else {
+ throw new UnsupportedOperationException(keyName);
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/marshal/ShipmentKey.java b/examples_java/src/collections/ship/marshal/ShipmentKey.java
new file mode 100644
index 0000000..a066822
--- /dev/null
+++ b/examples_java/src/collections/ship/marshal/ShipmentKey.java
@@ -0,0 +1,69 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.marshal;
+
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+/**
+ * A ShipmentKey serves as the key in the key/data pair for a shipment entity.
+ *
+ * <p> In this sample, ShipmentKey is bound to the stored key tuple entry by
+ * implementing the MarshalledKey interface, which is called by {@link
+ * SampleViews.MarshalledKeyBinding}. </p>
+ *
+ * @author Mark Hayes
+ */
+public class ShipmentKey implements MarshalledKey {
+
+ private String partNumber;
+ private String supplierNumber;
+
+ public ShipmentKey(String partNumber, String supplierNumber) {
+
+ this.partNumber = partNumber;
+ this.supplierNumber = supplierNumber;
+ }
+
+ public final String getPartNumber() {
+
+ return partNumber;
+ }
+
+ public final String getSupplierNumber() {
+
+ return supplierNumber;
+ }
+
+ public String toString() {
+
+ return "[ShipmentKey: supplier=" + supplierNumber +
+ " part=" + partNumber + ']';
+ }
+
+ // --- MarshalledKey implementation ---
+
+ ShipmentKey() {
+
+ // A no-argument constructor is necessary only to allow the binding to
+ // instantiate objects of this class.
+ }
+
+ public void unmarshalKey(TupleInput keyInput) {
+
+ this.partNumber = keyInput.readString();
+ this.supplierNumber = keyInput.readString();
+ }
+
+ public void marshalKey(TupleOutput keyOutput) {
+
+ keyOutput.writeString(this.partNumber);
+ keyOutput.writeString(this.supplierNumber);
+ }
+}
diff --git a/examples_java/src/collections/ship/marshal/Supplier.java b/examples_java/src/collections/ship/marshal/Supplier.java
new file mode 100644
index 0000000..43d97c0
--- /dev/null
+++ b/examples_java/src/collections/ship/marshal/Supplier.java
@@ -0,0 +1,118 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.marshal;
+
+import java.io.Serializable;
+
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+/**
+ * A Supplier represents the combined key/data pair for a supplier entity.
+ *
+ * <p> In this sample, Supplier is bound to the stored key/data entry by
+ * implementing the MarshalledEnt interface, which is called by {@link
+ * SampleViews.MarshalledEntityBinding}. </p>
+ *
+ * <p> The binding is "tricky" in that it uses this class for both the stored
+ * data entry and the combined entity object. To do this, the key field(s) are
+ * transient and are set by the binding after the data object has been
+ * deserialized. This avoids the use of a SupplierData class completely. </p>
+ *
+ * <p> Since this class is used directly for data storage, it must be
+ * Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Supplier implements Serializable, MarshalledEnt {
+
+ static final String CITY_KEY = "city";
+
+ private transient String number;
+ private String name;
+ private int status;
+ private String city;
+
+ public Supplier(String number, String name, int status, String city) {
+
+ this.number = number;
+ this.name = name;
+ this.status = status;
+ this.city = city;
+ }
+
+ /**
+ * Set the transient key fields after deserializing. This method is only
+ * called by data bindings.
+ */
+ void setKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final int getStatus() {
+
+ return status;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[Supplier: number=" + number +
+ " name=" + name +
+ " status=" + status +
+ " city=" + city + ']';
+ }
+
+ // --- MarshalledEnt implementation ---
+
+ Supplier() {
+
+ // A no-argument constructor is necessary only to allow the binding to
+ // instantiate objects of this class.
+ }
+
+ public void unmarshalPrimaryKey(TupleInput keyInput) {
+
+ this.number = keyInput.readString();
+ }
+
+ public void marshalPrimaryKey(TupleOutput keyOutput) {
+
+ keyOutput.writeString(this.number);
+ }
+
+ public boolean marshalSecondaryKey(String keyName, TupleOutput keyOutput) {
+
+ if (keyName.equals(CITY_KEY)) {
+ if (this.city != null) {
+ keyOutput.writeString(this.city);
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ throw new UnsupportedOperationException(keyName);
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/marshal/SupplierKey.java b/examples_java/src/collections/ship/marshal/SupplierKey.java
new file mode 100644
index 0000000..d8ab019
--- /dev/null
+++ b/examples_java/src/collections/ship/marshal/SupplierKey.java
@@ -0,0 +1,59 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.marshal;
+
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+/**
+ * A SupplierKey serves as the key in the key/data pair for a supplier entity.
+ *
+ * <p> In this sample, SupplierKey is bound to the stored key tuple entry by
+ * implementing the MarshalledKey interface, which is called by {@link
+ * SampleViews.MarshalledKeyBinding}. </p>
+ *
+ * @author Mark Hayes
+ */
+public class SupplierKey implements MarshalledKey {
+
+ private String number;
+
+ public SupplierKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public String toString() {
+
+ return "[SupplierKey: number=" + number + ']';
+ }
+
+ // --- MarshalledKey implementation ---
+
+ SupplierKey() {
+
+ // A no-argument constructor is necessary only to allow the binding to
+ // instantiate objects of this class.
+ }
+
+ public void unmarshalKey(TupleInput keyInput) {
+
+ this.number = keyInput.readString();
+ }
+
+ public void marshalKey(TupleOutput keyOutput) {
+
+ keyOutput.writeString(this.number);
+ }
+}
diff --git a/examples_java/src/collections/ship/marshal/Weight.java b/examples_java/src/collections/ship/marshal/Weight.java
new file mode 100644
index 0000000..608629d
--- /dev/null
+++ b/examples_java/src/collections/ship/marshal/Weight.java
@@ -0,0 +1,49 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.marshal;
+
+import java.io.Serializable;
+
+/**
+ * Weight represents a weight amount and unit of measure.
+ *
+ * <p> In this sample, Weight is embedded in part data values which are stored
+ * as Java serialized objects; therefore Weight must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Weight implements Serializable {
+
+ public final static String GRAMS = "grams";
+ public final static String OUNCES = "ounces";
+
+ private double amount;
+ private String units;
+
+ public Weight(double amount, String units) {
+
+ this.amount = amount;
+ this.units = units;
+ }
+
+ public final double getAmount() {
+
+ return amount;
+ }
+
+ public final String getUnits() {
+
+ return units;
+ }
+
+ public String toString() {
+
+ return "[" + amount + ' ' + units + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/sentity/Part.java b/examples_java/src/collections/ship/sentity/Part.java
new file mode 100644
index 0000000..b50bfe9
--- /dev/null
+++ b/examples_java/src/collections/ship/sentity/Part.java
@@ -0,0 +1,90 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.sentity;
+
+import java.io.Serializable;
+
+/**
+ * A Part represents the combined key/data pair for a part entity.
+ *
+ * <p> In this sample, Part is created from the stored key/data entry using a
+ * TupleSerialEntityBinding. See {@link SampleViews.PartBinding} for details.
+ * </p>
+ *
+ * <p> The binding is "tricky" in that it uses this class for both the stored
+ * data entry and the combined entity object. To do this, the key field(s) are
+ * transient and are set by the binding after the data object has been
+ * deserialized. This avoids the use of a PartData class completely. </p>
+ *
+ * <p> Since this class is used directly for data storage, it must be
+ * Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Part implements Serializable {
+
+ private transient String number;
+ private String name;
+ private String color;
+ private Weight weight;
+ private String city;
+
+ public Part(String number, String name, String color, Weight weight,
+ String city) {
+
+ this.number = number;
+ this.name = name;
+ this.color = color;
+ this.weight = weight;
+ this.city = city;
+ }
+
+ /**
+ * Set the transient key fields after deserializing. This method is only
+ * called by data bindings.
+ */
+ final void setKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final String getColor() {
+
+ return color;
+ }
+
+ public final Weight getWeight() {
+
+ return weight;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[Part: number=" + number +
+ " name=" + name +
+ " color=" + color +
+ " weight=" + weight +
+ " city=" + city + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/sentity/PartKey.java b/examples_java/src/collections/ship/sentity/PartKey.java
new file mode 100644
index 0000000..b2ae689
--- /dev/null
+++ b/examples_java/src/collections/ship/sentity/PartKey.java
@@ -0,0 +1,38 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.sentity;
+
+/**
+ * A PartKey serves as the key in the key/data pair for a part entity.
+ *
+ * <p> In this sample, PartKey is bound to the key's tuple storage entry using
+ * a TupleBinding. Because it is not used directly as storage data, it does
+ * not need to be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class PartKey {
+
+ private String number;
+
+ public PartKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public String toString() {
+
+ return "[PartKey: number=" + number + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/sentity/Sample.java b/examples_java/src/collections/ship/sentity/Sample.java
new file mode 100644
index 0000000..c7d1b44
--- /dev/null
+++ b/examples_java/src/collections/ship/sentity/Sample.java
@@ -0,0 +1,249 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.sentity;
+
+import java.io.FileNotFoundException;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.sleepycat.collections.StoredIterator;
+import com.sleepycat.collections.TransactionRunner;
+import com.sleepycat.collections.TransactionWorker;
+import com.sleepycat.db.DatabaseException;
+
+/**
+ * Sample is the main entry point for the sample program and may be run as
+ * follows:
+ *
+ * <pre>
+ * java collections.ship.sentity.Sample
+ * [-h <home-directory> ]
+ * </pre>
+ *
+ * <p> The default for the home directory is ./tmp -- the tmp subdirectory of
+ * the current directory where the sample is run. To specify a different home
+ * directory, use the -home option. The home directory must exist before
+ * running the sample. To recreate the sample database from scratch, delete
+ * all files in the home directory before running the sample. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Sample {
+
+ private SampleDatabase db;
+ private SampleViews views;
+
+ /**
+ * Run the sample program.
+ */
+ public static void main(String[] args) {
+
+ System.out.println("\nRunning sample: " + Sample.class);
+
+ // Parse the command line arguments.
+ //
+ String homeDir = "./tmp";
+ for (int i = 0; i < args.length; i += 1) {
+ if (args[i].equals("-h") && i < args.length - 1) {
+ i += 1;
+ homeDir = args[i];
+ } else {
+ System.err.println("Usage:\n java " + Sample.class.getName() +
+ "\n [-h <home-directory>]");
+ System.exit(2);
+ }
+ }
+
+ // Run the sample.
+ //
+ Sample sample = null;
+ try {
+ sample = new Sample(homeDir);
+ sample.run();
+ } catch (Exception e) {
+ // If an exception reaches this point, the last transaction did not
+ // complete. If the exception is RunRecoveryException, follow
+ // the Berkeley DB recovery procedures before running again.
+ e.printStackTrace();
+ } finally {
+ if (sample != null) {
+ try {
+ // Always attempt to close the database cleanly.
+ sample.close();
+ } catch (Exception e) {
+ System.err.println("Exception during database close:");
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Open the database and views.
+ */
+ private Sample(String homeDir)
+ throws DatabaseException, FileNotFoundException {
+
+ db = new SampleDatabase(homeDir);
+ views = new SampleViews(db);
+ }
+
+ /**
+ * Close the database cleanly.
+ */
+ private void close()
+ throws DatabaseException {
+
+ db.close();
+ }
+
+ /**
+ * Run two transactions to populate and print the database. A
+ * TransactionRunner is used to ensure consistent handling of transactions,
+ * including deadlock retries. But the best transaction handling mechanism
+ * to use depends on the application.
+ */
+ private void run()
+ throws Exception {
+
+ TransactionRunner runner = new TransactionRunner(db.getEnvironment());
+ runner.run(new PopulateDatabase());
+ runner.run(new PrintDatabase());
+ }
+
+ /**
+ * Populate the database in a single transaction.
+ */
+ private class PopulateDatabase implements TransactionWorker {
+
+ public void doWork()
+ throws Exception {
+ addSuppliers();
+ addParts();
+ addShipments();
+ }
+ }
+
+ /**
+ * Print the database in a single transaction. All entities are printed
+ * and the indices are used to print the entities for certain keys.
+ *
+ * <p> Note the use of special iterator() methods. These are used here
+ * with indices to find the shipments for certain keys. For details on
+ * database iterators see {@link StoredIterator}. </p>
+ */
+ private class PrintDatabase implements TransactionWorker {
+
+ public void doWork()
+ throws Exception {
+ printValues("Parts",
+ views.getPartSet().iterator());
+ printValues("Suppliers",
+ views.getSupplierSet().iterator());
+ printValues("Suppliers for City Paris",
+ views.getSupplierByCityMap().duplicates(
+ "Paris").iterator());
+ printValues("Shipments",
+ views.getShipmentSet().iterator());
+ printValues("Shipments for Part P1",
+ views.getShipmentByPartMap().duplicates(
+ new PartKey("P1")).iterator());
+ printValues("Shipments for Supplier S1",
+ views.getShipmentBySupplierMap().duplicates(
+ new SupplierKey("S1")).iterator());
+ }
+ }
+
+ /**
+ * Populate the part entities in the database. If the part set is not
+ * empty, assume that this has already been done.
+ */
+ private void addParts() {
+
+ Set parts = views.getPartSet();
+ if (parts.isEmpty()) {
+ System.out.println("Adding Parts");
+ parts.add(new Part("P1", "Nut", "Red",
+ new Weight(12.0, Weight.GRAMS), "London"));
+ parts.add(new Part("P2", "Bolt", "Green",
+ new Weight(17.0, Weight.GRAMS), "Paris"));
+ parts.add(new Part("P3", "Screw", "Blue",
+ new Weight(17.0, Weight.GRAMS), "Rome"));
+ parts.add(new Part("P4", "Screw", "Red",
+ new Weight(14.0, Weight.GRAMS), "London"));
+ parts.add(new Part("P5", "Cam", "Blue",
+ new Weight(12.0, Weight.GRAMS), "Paris"));
+ parts.add(new Part("P6", "Cog", "Red",
+ new Weight(19.0, Weight.GRAMS), "London"));
+ }
+ }
+
+ /**
+ * Populate the supplier entities in the database. If the supplier set is
+ * not empty, assume that this has already been done.
+ */
+ private void addSuppliers() {
+
+ Set suppliers = views.getSupplierSet();
+ if (suppliers.isEmpty()) {
+ System.out.println("Adding Suppliers");
+ suppliers.add(new Supplier("S1", "Smith", 20, "London"));
+ suppliers.add(new Supplier("S2", "Jones", 10, "Paris"));
+ suppliers.add(new Supplier("S3", "Blake", 30, "Paris"));
+ suppliers.add(new Supplier("S4", "Clark", 20, "London"));
+ suppliers.add(new Supplier("S5", "Adams", 30, "Athens"));
+ }
+ }
+
+ /**
+ * Populate the shipment entities in the database. If the shipment set
+ * is not empty, assume that this has already been done.
+ */
+ private void addShipments() {
+
+ Set shipments = views.getShipmentSet();
+ if (shipments.isEmpty()) {
+ System.out.println("Adding Shipments");
+ shipments.add(new Shipment("P1", "S1", 300));
+ shipments.add(new Shipment("P2", "S1", 200));
+ shipments.add(new Shipment("P3", "S1", 400));
+ shipments.add(new Shipment("P4", "S1", 200));
+ shipments.add(new Shipment("P5", "S1", 100));
+ shipments.add(new Shipment("P6", "S1", 100));
+ shipments.add(new Shipment("P1", "S2", 300));
+ shipments.add(new Shipment("P2", "S2", 400));
+ shipments.add(new Shipment("P2", "S3", 200));
+ shipments.add(new Shipment("P2", "S4", 200));
+ shipments.add(new Shipment("P4", "S4", 300));
+ shipments.add(new Shipment("P5", "S4", 400));
+ }
+ }
+
+ /**
+ * Print the objects returned by an iterator of entity value objects.
+ *
+ * <p><b> IMPORTANT: All database iterators must be closed to avoid
+ * serious database problems. If the iterator is not closed, the
+ * underlying Berkeley DB cursor is not closed either. </b></p>
+ */
+ private void printValues(String label, Iterator iterator) {
+
+ System.out.println("\n--- " + label + " ---");
+ try {
+ while (iterator.hasNext()) {
+ System.out.println(iterator.next().toString());
+ }
+ } finally {
+ // IMPORTANT: Use StoredIterator to close all database
+ // iterators. If java.util.Iterator is in hand, you can safely
+ // close it by calling StoredIterator.close(Iterator).
+ StoredIterator.close(iterator);
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/sentity/SampleDatabase.java b/examples_java/src/collections/ship/sentity/SampleDatabase.java
new file mode 100644
index 0000000..c51e125
--- /dev/null
+++ b/examples_java/src/collections/ship/sentity/SampleDatabase.java
@@ -0,0 +1,323 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.sentity;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import com.sleepycat.bind.serial.ClassCatalog;
+import com.sleepycat.bind.serial.StoredClassCatalog;
+import com.sleepycat.bind.serial.TupleSerialKeyCreator;
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+import com.sleepycat.db.Database;
+import com.sleepycat.db.DatabaseConfig;
+import com.sleepycat.db.DatabaseException;
+import com.sleepycat.db.DatabaseType;
+import com.sleepycat.db.Environment;
+import com.sleepycat.db.EnvironmentConfig;
+import com.sleepycat.db.ForeignKeyDeleteAction;
+import com.sleepycat.db.SecondaryConfig;
+import com.sleepycat.db.SecondaryDatabase;
+
+/**
+ * SampleDatabase defines the storage containers, indices and foreign keys
+ * for the sample database.
+ *
+ * @author Mark Hayes
+ */
+public class SampleDatabase {
+
+ private static final String CLASS_CATALOG = "java_class_catalog";
+ private static final String SUPPLIER_STORE = "supplier_store";
+ private static final String PART_STORE = "part_store";
+ private static final String SHIPMENT_STORE = "shipment_store";
+ private static final String SHIPMENT_PART_INDEX = "shipment_part_index";
+ private static final String SHIPMENT_SUPPLIER_INDEX =
+ "shipment_supplier_index";
+ private static final String SUPPLIER_CITY_INDEX = "supplier_city_index";
+
+ private Environment env;
+ private Database partDb;
+ private Database supplierDb;
+ private Database shipmentDb;
+ private SecondaryDatabase supplierByCityDb;
+ private SecondaryDatabase shipmentByPartDb;
+ private SecondaryDatabase shipmentBySupplierDb;
+ private StoredClassCatalog javaCatalog;
+
+ /**
+ * Open all storage containers, indices, and catalogs.
+ */
+ public SampleDatabase(String homeDirectory)
+ throws DatabaseException, FileNotFoundException {
+
+ // Open the Berkeley DB environment in transactional mode.
+ //
+ System.out.println("Opening environment in: " + homeDirectory);
+ EnvironmentConfig envConfig = new EnvironmentConfig();
+ envConfig.setTransactional(true);
+ envConfig.setAllowCreate(true);
+ envConfig.setInitializeCache(true);
+ envConfig.setInitializeLocking(true);
+ env = new Environment(new File(homeDirectory), envConfig);
+
+ // Set the Berkeley DB config for opening all stores.
+ //
+ DatabaseConfig dbConfig = new DatabaseConfig();
+ dbConfig.setTransactional(true);
+ dbConfig.setAllowCreate(true);
+ dbConfig.setType(DatabaseType.BTREE);
+
+ // Create the Serial class catalog. This holds the serialized class
+ // format for all database records of serial format.
+ //
+ Database catalogDb = env.openDatabase(null, CLASS_CATALOG, null,
+ dbConfig);
+ javaCatalog = new StoredClassCatalog(catalogDb);
+
+ // Open the Berkeley DB database for the part, supplier and shipment
+ // stores. The stores are opened with no duplicate keys allowed.
+ //
+ partDb = env.openDatabase(null, PART_STORE, null, dbConfig);
+
+ supplierDb = env.openDatabase(null, SUPPLIER_STORE, null, dbConfig);
+
+ shipmentDb = env.openDatabase(null, SHIPMENT_STORE, null, dbConfig);
+
+ // Open the SecondaryDatabase for the city index of the supplier store,
+ // and for the part and supplier indices of the shipment store.
+ // Duplicate keys are allowed since more than one supplier may be in
+ // the same city, and more than one shipment may exist for the same
+ // supplier or part. A foreign key constraint is defined for the
+ // supplier and part indices to ensure that a shipment only refers to
+ // existing part and supplier keys. The CASCADE delete action means
+ // that shipments will be deleted if their associated part or supplier
+ // is deleted.
+ //
+ SecondaryConfig secConfig = new SecondaryConfig();
+ secConfig.setTransactional(true);
+ secConfig.setAllowCreate(true);
+ secConfig.setType(DatabaseType.BTREE);
+ secConfig.setSortedDuplicates(true);
+
+ secConfig.setKeyCreator(new SupplierByCityKeyCreator(javaCatalog,
+ Supplier.class));
+ supplierByCityDb = env.openSecondaryDatabase(null, SUPPLIER_CITY_INDEX,
+ null, supplierDb,
+ secConfig);
+
+ secConfig.setForeignKeyDatabase(partDb);
+ secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE);
+ secConfig.setKeyCreator(new ShipmentByPartKeyCreator(javaCatalog,
+ Shipment.class));
+ shipmentByPartDb = env.openSecondaryDatabase(null, SHIPMENT_PART_INDEX,
+ null, shipmentDb,
+ secConfig);
+
+ secConfig.setForeignKeyDatabase(supplierDb);
+ secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE);
+ secConfig.setKeyCreator(new ShipmentBySupplierKeyCreator(javaCatalog,
+ Shipment.class));
+ shipmentBySupplierDb = env.openSecondaryDatabase(null,
+ SHIPMENT_SUPPLIER_INDEX,
+ null, shipmentDb,
+ secConfig);
+ }
+
+ /**
+ * Return the storage environment for the database.
+ */
+ public final Environment getEnvironment() {
+
+ return env;
+ }
+
+ /**
+ * Return the class catalog.
+ */
+ public final StoredClassCatalog getClassCatalog() {
+
+ return javaCatalog;
+ }
+
+ /**
+ * Return the part storage container.
+ */
+ public final Database getPartDatabase() {
+
+ return partDb;
+ }
+
+ /**
+ * Return the supplier storage container.
+ */
+ public final Database getSupplierDatabase() {
+
+ return supplierDb;
+ }
+
+ /**
+ * Return the shipment storage container.
+ */
+ public final Database getShipmentDatabase() {
+
+ return shipmentDb;
+ }
+
+ /**
+ * Return the shipment-by-part index.
+ */
+ public final SecondaryDatabase getShipmentByPartDatabase() {
+
+ return shipmentByPartDb;
+ }
+
+ /**
+ * Return the shipment-by-supplier index.
+ */
+ public final SecondaryDatabase getShipmentBySupplierDatabase() {
+
+ return shipmentBySupplierDb;
+ }
+
+ /**
+ * Return the supplier-by-city index.
+ */
+ public final SecondaryDatabase getSupplierByCityDatabase() {
+
+ return supplierByCityDb;
+ }
+
+ /**
+ * Close all stores (closing a store automatically closes its indices).
+ */
+ public void close()
+ throws DatabaseException {
+
+ // Close secondary databases, then primary databases.
+ supplierByCityDb.close();
+ shipmentByPartDb.close();
+ shipmentBySupplierDb.close();
+ partDb.close();
+ supplierDb.close();
+ shipmentDb.close();
+ // And don't forget to close the catalog and the environment.
+ javaCatalog.close();
+ env.close();
+ }
+
+ /**
+ * The SecondaryKeyCreator for the SupplierByCity index. This is an
+ * extension of the abstract class TupleSerialKeyCreator, which implements
+ * SecondaryKeyCreator for the case where the data keys are of the format
+ * TupleFormat and the data values are of the format SerialFormat.
+ */
+ private static class SupplierByCityKeyCreator
+ extends TupleSerialKeyCreator {
+
+ /**
+ * Construct the city key extractor.
+ * @param catalog is the class catalog.
+ * @param valueClass is the supplier value class.
+ */
+ private SupplierByCityKeyCreator(ClassCatalog catalog,
+ Class valueClass) {
+
+ super(catalog, valueClass);
+ }
+
+ /**
+ * Extract the city key from a supplier key/value pair. The city key
+ * is stored in the supplier value, so the supplier key is not used.
+ */
+ public boolean createSecondaryKey(TupleInput primaryKeyInput,
+ Object valueInput,
+ TupleOutput indexKeyOutput) {
+
+ Supplier supplier = (Supplier) valueInput;
+ String city = supplier.getCity();
+ if (city != null) {
+ indexKeyOutput.writeString(supplier.getCity());
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * The SecondaryKeyCreator for the ShipmentByPart index. This is an
+ * extension of the abstract class TupleSerialKeyCreator, which implements
+ * SecondaryKeyCreator for the case where the data keys are of the format
+ * TupleFormat and the data values are of the format SerialFormat.
+ */
+ private static class ShipmentByPartKeyCreator
+ extends TupleSerialKeyCreator {
+
+ /**
+ * Construct the part key extractor.
+ * @param catalog is the class catalog.
+ * @param valueClass is the shipment value class.
+ */
+ private ShipmentByPartKeyCreator(ClassCatalog catalog,
+ Class valueClass) {
+ super(catalog, valueClass);
+ }
+
+ /**
+ * Extract the part key from a shipment key/value pair. The part key
+ * is stored in the shipment key, so the shipment value is not used.
+ */
+ public boolean createSecondaryKey(TupleInput primaryKeyInput,
+ Object valueInput,
+ TupleOutput indexKeyOutput) {
+
+ String partNumber = primaryKeyInput.readString();
+ // don't bother reading the supplierNumber
+ indexKeyOutput.writeString(partNumber);
+ return true;
+ }
+ }
+
+ /**
+ * The SecondaryKeyCreator for the ShipmentBySupplier index. This is an
+ * extension of the abstract class TupleSerialKeyCreator, which implements
+ * SecondaryKeyCreator for the case where the data keys are of the format
+ * TupleFormat and the data values are of the format SerialFormat.
+ */
+ private static class ShipmentBySupplierKeyCreator
+ extends TupleSerialKeyCreator {
+
+ /**
+ * Construct the supplier key extractor.
+ * @param catalog is the class catalog.
+ * @param valueClass is the shipment value class.
+ */
+ private ShipmentBySupplierKeyCreator(ClassCatalog catalog,
+ Class valueClass) {
+ super(catalog, valueClass);
+ }
+
+ /**
+ * Extract the supplier key from a shipment key/value pair. The
+ * supplier key is stored in the shipment key, so the shipment value is
+ * not used.
+ */
+ public boolean createSecondaryKey(TupleInput primaryKeyInput,
+ Object valueInput,
+ TupleOutput indexKeyOutput) {
+
+ primaryKeyInput.readString(); // skip the partNumber
+ String supplierNumber = primaryKeyInput.readString();
+ indexKeyOutput.writeString(supplierNumber);
+ return true;
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/sentity/SampleViews.java b/examples_java/src/collections/ship/sentity/SampleViews.java
new file mode 100644
index 0000000..9b69061
--- /dev/null
+++ b/examples_java/src/collections/ship/sentity/SampleViews.java
@@ -0,0 +1,419 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.sentity;
+
+import com.sleepycat.bind.EntityBinding;
+import com.sleepycat.bind.EntryBinding;
+import com.sleepycat.bind.serial.ClassCatalog;
+import com.sleepycat.bind.serial.TupleSerialBinding;
+import com.sleepycat.bind.tuple.TupleBinding;
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+import com.sleepycat.collections.StoredSortedMap;
+import com.sleepycat.collections.StoredSortedValueSet;
+
+/**
+ * SampleViews defines the data bindings and collection views for the sample
+ * database.
+ *
+ * @author Mark Hayes
+ */
+public class SampleViews {
+
+ private StoredSortedMap partMap;
+ private StoredSortedMap supplierMap;
+ private StoredSortedMap shipmentMap;
+ private StoredSortedMap shipmentByPartMap;
+ private StoredSortedMap shipmentBySupplierMap;
+ private StoredSortedMap supplierByCityMap;
+
+ /**
+ * Create the data bindings and collection views.
+ */
+ public SampleViews(SampleDatabase db) {
+
+ // Create the data bindings.
+ // In this sample, EntityBinding classes are used to bind the stored
+ // key/data entry pair to a combined data object; a "tricky" binding
+ // that uses transient fields is used--see PartBinding, etc, for
+ // details. For keys, a one-to-one binding is implemented with
+ // EntryBinding classes to bind the stored tuple entry to a key Object.
+ //
+ ClassCatalog catalog = db.getClassCatalog();
+ EntryBinding partKeyBinding =
+ new PartKeyBinding();
+ EntityBinding partDataBinding =
+ new PartBinding(catalog, Part.class);
+ EntryBinding supplierKeyBinding =
+ new SupplierKeyBinding();
+ EntityBinding supplierDataBinding =
+ new SupplierBinding(catalog, Supplier.class);
+ EntryBinding shipmentKeyBinding =
+ new ShipmentKeyBinding();
+ EntityBinding shipmentDataBinding =
+ new ShipmentBinding(catalog, Shipment.class);
+ EntryBinding cityKeyBinding =
+ TupleBinding.getPrimitiveBinding(String.class);
+
+ // Create map views for all stores and indices.
+ // StoredSortedMap is used since the stores and indices are ordered
+ // (they use the DB_BTREE access method).
+ //
+ partMap =
+ new StoredSortedMap(db.getPartDatabase(),
+ partKeyBinding, partDataBinding, true);
+ supplierMap =
+ new StoredSortedMap(db.getSupplierDatabase(),
+ supplierKeyBinding, supplierDataBinding, true);
+ shipmentMap =
+ new StoredSortedMap(db.getShipmentDatabase(),
+ shipmentKeyBinding, shipmentDataBinding, true);
+ shipmentByPartMap =
+ new StoredSortedMap(db.getShipmentByPartDatabase(),
+ partKeyBinding, shipmentDataBinding, true);
+ shipmentBySupplierMap =
+ new StoredSortedMap(db.getShipmentBySupplierDatabase(),
+ supplierKeyBinding, shipmentDataBinding, true);
+ supplierByCityMap =
+ new StoredSortedMap(db.getSupplierByCityDatabase(),
+ cityKeyBinding, supplierDataBinding, true);
+ }
+
+ // The views returned below can be accessed using the java.util.Map or
+ // java.util.Set interfaces, or using the StoredSortedMap and
+ // StoredValueSet classes, which provide additional methods. The entity
+ // sets could be obtained directly from the Map.values() method but
+ // convenience methods are provided here to return them in order to avoid
+ // down-casting elsewhere.
+
+ /**
+ * Return a map view of the part storage container.
+ */
+ public StoredSortedMap getPartMap() {
+
+ return partMap;
+ }
+
+ /**
+ * Return a map view of the supplier storage container.
+ */
+ public StoredSortedMap getSupplierMap() {
+
+ return supplierMap;
+ }
+
+ /**
+ * Return a map view of the shipment storage container.
+ */
+ public StoredSortedMap getShipmentMap() {
+
+ return shipmentMap;
+ }
+
+ /**
+ * Return an entity set view of the part storage container.
+ */
+ public StoredSortedValueSet getPartSet() {
+
+ return (StoredSortedValueSet) partMap.values();
+ }
+
+ /**
+ * Return an entity set view of the supplier storage container.
+ */
+ public StoredSortedValueSet getSupplierSet() {
+
+ return (StoredSortedValueSet) supplierMap.values();
+ }
+
+ /**
+ * Return an entity set view of the shipment storage container.
+ */
+ public StoredSortedValueSet getShipmentSet() {
+
+ return (StoredSortedValueSet) shipmentMap.values();
+ }
+
+ /**
+ * Return a map view of the shipment-by-part index.
+ */
+ public StoredSortedMap getShipmentByPartMap() {
+
+ return shipmentByPartMap;
+ }
+
+ /**
+ * Return a map view of the shipment-by-supplier index.
+ */
+ public StoredSortedMap getShipmentBySupplierMap() {
+
+ return shipmentBySupplierMap;
+ }
+
+ /**
+ * Return a map view of the supplier-by-city index.
+ */
+ public final StoredSortedMap getSupplierByCityMap() {
+
+ return supplierByCityMap;
+ }
+
+ /**
+ * PartKeyBinding is used to bind the stored key tuple entry for a part to
+ * a key object representation.
+ */
+ private static class PartKeyBinding extends TupleBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private PartKeyBinding() {
+ }
+
+ /**
+ * Create the key object from the stored key tuple entry.
+ */
+ public Object entryToObject(TupleInput input) {
+
+ String number = input.readString();
+ return new PartKey(number);
+ }
+
+ /**
+ * Create the stored key tuple entry from the key object.
+ */
+ public void objectToEntry(Object object, TupleOutput output) {
+
+ PartKey key = (PartKey) object;
+ output.writeString(key.getNumber());
+ }
+ }
+
+ /**
+ * PartBinding is used to bind the stored key/data entry pair for a part
+ * to a combined data object (entity).
+ *
+ * <p> The binding is "tricky" in that it uses the Part class for both the
+ * stored data entry and the combined entity object. To do this, Part's
+ * key field(s) are transient and are set by the binding after the data
+ * object has been deserialized. This avoids the use of a PartData class
+ * completely. </p>
+ */
+ private static class PartBinding extends TupleSerialBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private PartBinding(ClassCatalog classCatalog, Class dataClass) {
+
+ super(classCatalog, dataClass);
+ }
+
+ /**
+ * Create the entity by combining the stored key and data.
+ * This "tricky" binding returns the stored data as the entity, but
+ * first it sets the transient key fields from the stored key.
+ */
+ public Object entryToObject(TupleInput keyInput, Object dataInput) {
+
+ String number = keyInput.readString();
+ Part part = (Part) dataInput;
+ part.setKey(number);
+ return part;
+ }
+
+ /**
+ * Create the stored key from the entity.
+ */
+ public void objectToKey(Object object, TupleOutput output) {
+
+ Part part = (Part) object;
+ output.writeString(part.getNumber());
+ }
+
+ /**
+ * Return the entity as the stored data. There is nothing to do here
+ * since the entity's key fields are transient.
+ */
+ public Object objectToData(Object object) {
+
+ return object;
+ }
+ }
+
+ /**
+ * SupplierKeyBinding is used to bind the stored key tuple entry for a
+ * supplier to a key object representation.
+ */
+ private static class SupplierKeyBinding extends TupleBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private SupplierKeyBinding() {
+ }
+
+ /**
+ * Create the key object from the stored key tuple entry.
+ */
+ public Object entryToObject(TupleInput input) {
+
+ String number = input.readString();
+ return new SupplierKey(number);
+ }
+
+ /**
+ * Create the stored key tuple entry from the key object.
+ */
+ public void objectToEntry(Object object, TupleOutput output) {
+
+ SupplierKey key = (SupplierKey) object;
+ output.writeString(key.getNumber());
+ }
+ }
+
+ /**
+ * SupplierBinding is used to bind the stored key/data entry pair for a
+ * supplier to a combined data object (entity).
+ *
+ * <p> The binding is "tricky" in that it uses the Supplier class for both
+ * the stored data entry and the combined entity object. To do this,
+ * Supplier's key field(s) are transient and are set by the binding after
+ * the data object has been deserialized. This avoids the use of a
+ * SupplierData class completely. </p>
+ */
+ private static class SupplierBinding extends TupleSerialBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private SupplierBinding(ClassCatalog classCatalog, Class dataClass) {
+
+ super(classCatalog, dataClass);
+ }
+
+ /**
+ * Create the entity by combining the stored key and data.
+ * This "tricky" binding returns the stored data as the entity, but
+ * first it sets the transient key fields from the stored key.
+ */
+ public Object entryToObject(TupleInput keyInput, Object dataInput) {
+
+ String number = keyInput.readString();
+ Supplier supplier = (Supplier) dataInput;
+ supplier.setKey(number);
+ return supplier;
+ }
+
+ /**
+ * Create the stored key from the entity.
+ */
+ public void objectToKey(Object object, TupleOutput output) {
+
+ Supplier supplier = (Supplier) object;
+ output.writeString(supplier.getNumber());
+ }
+
+ /**
+ * Return the entity as the stored data. There is nothing to do here
+ * since the entity's key fields are transient.
+ */
+ public Object objectToData(Object object) {
+
+ return object;
+ }
+ }
+
+ /**
+ * ShipmentKeyBinding is used to bind the stored key tuple entry for a
+ * shipment to a key object representation.
+ */
+ private static class ShipmentKeyBinding extends TupleBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private ShipmentKeyBinding() {
+ }
+
+ /**
+ * Create the key object from the stored key tuple entry.
+ */
+ public Object entryToObject(TupleInput input) {
+
+ String partNumber = input.readString();
+ String supplierNumber = input.readString();
+ return new ShipmentKey(partNumber, supplierNumber);
+ }
+
+ /**
+ * Create the stored key tuple entry from the key object.
+ */
+ public void objectToEntry(Object object, TupleOutput output) {
+
+ ShipmentKey key = (ShipmentKey) object;
+ output.writeString(key.getPartNumber());
+ output.writeString(key.getSupplierNumber());
+ }
+ }
+
+ /**
+ * ShipmentBinding is used to bind the stored key/data entry pair for a
+ * shipment to a combined data object (entity).
+ *
+ * <p> The binding is "tricky" in that it uses the Shipment class for both
+ * the stored data entry and the combined entity object. To do this,
+ * Shipment's key field(s) are transient and are set by the binding after
+ * the data object has been deserialized. This avoids the use of a
+ * ShipmentData class completely. </p>
+ */
+ private static class ShipmentBinding extends TupleSerialBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private ShipmentBinding(ClassCatalog classCatalog, Class dataClass) {
+
+ super(classCatalog, dataClass);
+ }
+
+ /**
+ * Create the entity by combining the stored key and data.
+ * This "tricky" binding returns the stored data as the entity, but
+ * first it sets the transient key fields from the stored key.
+ */
+ public Object entryToObject(TupleInput keyInput, Object dataInput) {
+
+ String partNumber = keyInput.readString();
+ String supplierNumber = keyInput.readString();
+ Shipment shipment = (Shipment) dataInput;
+ shipment.setKey(partNumber, supplierNumber);
+ return shipment;
+ }
+
+ /**
+ * Create the stored key from the entity.
+ */
+ public void objectToKey(Object object, TupleOutput output) {
+
+ Shipment shipment = (Shipment) object;
+ output.writeString(shipment.getPartNumber());
+ output.writeString(shipment.getSupplierNumber());
+ }
+
+ /**
+ * Return the entity as the stored data. There is nothing to do here
+ * since the entity's key fields are transient.
+ */
+ public Object objectToData(Object object) {
+
+ return object;
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/sentity/Shipment.java b/examples_java/src/collections/ship/sentity/Shipment.java
new file mode 100644
index 0000000..cb6f91e
--- /dev/null
+++ b/examples_java/src/collections/ship/sentity/Shipment.java
@@ -0,0 +1,75 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.sentity;
+
+import java.io.Serializable;
+
+/**
+ * A Shipment represents the combined key/data pair for a shipment entity.
+ *
+ * <p> In this sample, Shipment is created from the stored key/data entry
+ * using TupleSerialEntityBinding. See {@link SampleViews.PartBinding} for
+ * details.
+ * </p>
+ *
+ * <p> The binding is "tricky" in that it uses this class for both the stored
+ * data entry and the combined entity object. To do this, the key field(s)
+ * are transient and are set by the binding after the data object has been
+ * deserialized. This avoids the use of a ShipmentData class completely. </p>
+ *
+ * <p> Since this class is used directly for data storage, it must be
+ * Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Shipment implements Serializable {
+
+ private transient String partNumber;
+ private transient String supplierNumber;
+ private int quantity;
+
+ public Shipment(String partNumber, String supplierNumber, int quantity) {
+
+ this.partNumber = partNumber;
+ this.supplierNumber = supplierNumber;
+ this.quantity = quantity;
+ }
+
+ /**
+ * Set the transient key fields after deserializing. This method is only
+ * called by data bindings.
+ */
+ void setKey(String partNumber, String supplierNumber) {
+
+ this.partNumber = partNumber;
+ this.supplierNumber = supplierNumber;
+ }
+
+ public final String getPartNumber() {
+
+ return partNumber;
+ }
+
+ public final String getSupplierNumber() {
+
+ return supplierNumber;
+ }
+
+ public final int getQuantity() {
+
+ return quantity;
+ }
+
+ public String toString() {
+
+ return "[Shipment: part=" + partNumber +
+ " supplier=" + supplierNumber +
+ " quantity=" + quantity + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/sentity/ShipmentKey.java b/examples_java/src/collections/ship/sentity/ShipmentKey.java
new file mode 100644
index 0000000..374e1bd
--- /dev/null
+++ b/examples_java/src/collections/ship/sentity/ShipmentKey.java
@@ -0,0 +1,46 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.sentity;
+
+/**
+ * A ShipmentKey serves as the key in the key/data pair for a shipment entity.
+ *
+ * <p> In this sample, ShipmentKey is bound to the key's tuple storage entry
+ * using a TupleBinding. Because it is not used directly as storage data, it
+ * does not need to be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class ShipmentKey {
+
+ private String partNumber;
+ private String supplierNumber;
+
+ public ShipmentKey(String partNumber, String supplierNumber) {
+
+ this.partNumber = partNumber;
+ this.supplierNumber = supplierNumber;
+ }
+
+ public final String getPartNumber() {
+
+ return partNumber;
+ }
+
+ public final String getSupplierNumber() {
+
+ return supplierNumber;
+ }
+
+ public String toString() {
+
+ return "[ShipmentKey: supplier=" + supplierNumber +
+ " part=" + partNumber + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/sentity/Supplier.java b/examples_java/src/collections/ship/sentity/Supplier.java
new file mode 100644
index 0000000..a9e7bc7
--- /dev/null
+++ b/examples_java/src/collections/ship/sentity/Supplier.java
@@ -0,0 +1,82 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.sentity;
+
+import java.io.Serializable;
+
+/**
+ * A Supplier represents the combined key/data pair for a supplier entity.
+ *
+ * <p> In this sample, Supplier is created from the stored key/data entry
+ * using TupleSerialEntityBinding. See {@link SampleViews.PartBinding} for
+ * details.
+ * </p>
+ *
+ * <p> The binding is "tricky" in that it uses this class for both the stored
+ * data entry and the combined entity object. To do this, the key field(s) are
+ * transient and are set by the binding after the data object has been
+ * deserialized. This avoids the use of a SupplierData class completely. </p>
+ *
+ * <p> Since this class is used directly for data storage, it must be
+ * Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Supplier implements Serializable {
+
+ private transient String number;
+ private String name;
+ private int status;
+ private String city;
+
+ public Supplier(String number, String name, int status, String city) {
+
+ this.number = number;
+ this.name = name;
+ this.status = status;
+ this.city = city;
+ }
+
+ /**
+ * Set the transient key fields after deserializing. This method is only
+ * called by data bindings.
+ */
+ void setKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final int getStatus() {
+
+ return status;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[Supplier: number=" + number +
+ " name=" + name +
+ " status=" + status +
+ " city=" + city + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/sentity/SupplierKey.java b/examples_java/src/collections/ship/sentity/SupplierKey.java
new file mode 100644
index 0000000..1d30a3c
--- /dev/null
+++ b/examples_java/src/collections/ship/sentity/SupplierKey.java
@@ -0,0 +1,38 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.sentity;
+
+/**
+ * A SupplierKey serves as the key in the key/data pair for a supplier entity.
+ *
+ * <p> In this sample, SupplierKey is bound to the key's tuple storage entry
+ * using a TupleBinding. Because it is not used directly as storage data, it
+ * does not need to be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class SupplierKey {
+
+ private String number;
+
+ public SupplierKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public String toString() {
+
+ return "[SupplierKey: number=" + number + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/sentity/Weight.java b/examples_java/src/collections/ship/sentity/Weight.java
new file mode 100644
index 0000000..39e6e1c
--- /dev/null
+++ b/examples_java/src/collections/ship/sentity/Weight.java
@@ -0,0 +1,49 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.sentity;
+
+import java.io.Serializable;
+
+/**
+ * Weight represents a weight amount and unit of measure.
+ *
+ * <p> In this sample, Weight is embedded in part data values which are stored
+ * as Java serialized objects; therefore Weight must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Weight implements Serializable {
+
+ public final static String GRAMS = "grams";
+ public final static String OUNCES = "ounces";
+
+ private double amount;
+ private String units;
+
+ public Weight(double amount, String units) {
+
+ this.amount = amount;
+ this.units = units;
+ }
+
+ public final double getAmount() {
+
+ return amount;
+ }
+
+ public final String getUnits() {
+
+ return units;
+ }
+
+ public String toString() {
+
+ return "[" + amount + ' ' + units + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/tuple/Part.java b/examples_java/src/collections/ship/tuple/Part.java
new file mode 100644
index 0000000..a821e0a
--- /dev/null
+++ b/examples_java/src/collections/ship/tuple/Part.java
@@ -0,0 +1,72 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.tuple;
+
+/**
+ * A Part represents the combined key/data pair for a part entity.
+ *
+ * <p> In this sample, Part is created from the stored key/data entry using a
+ * SerialSerialBinding. See {@link SampleViews.PartBinding} for details.
+ * Since this class is not directly used for data storage, it does not need to
+ * be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Part {
+
+ private String number;
+ private String name;
+ private String color;
+ private Weight weight;
+ private String city;
+
+ public Part(String number, String name, String color, Weight weight,
+ String city) {
+
+ this.number = number;
+ this.name = name;
+ this.color = color;
+ this.weight = weight;
+ this.city = city;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final String getColor() {
+
+ return color;
+ }
+
+ public final Weight getWeight() {
+
+ return weight;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[Part: number=" + number +
+ " name=" + name +
+ " color=" + color +
+ " weight=" + weight +
+ " city=" + city + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/tuple/PartData.java b/examples_java/src/collections/ship/tuple/PartData.java
new file mode 100644
index 0000000..8ccc3b1
--- /dev/null
+++ b/examples_java/src/collections/ship/tuple/PartData.java
@@ -0,0 +1,65 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.tuple;
+
+import java.io.Serializable;
+
+/**
+ * A PartData serves as the value in the key/value pair for a part entity.
+ *
+ * <p> In this sample, PartData is used only as the storage data for the
+ * value, while the Part object is used as the value's object representation.
+ * Because it is used directly as storage data using serial format, it must be
+ * Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class PartData implements Serializable {
+
+ private String name;
+ private String color;
+ private Weight weight;
+ private String city;
+
+ public PartData(String name, String color, Weight weight, String city) {
+
+ this.name = name;
+ this.color = color;
+ this.weight = weight;
+ this.city = city;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final String getColor() {
+
+ return color;
+ }
+
+ public final Weight getWeight() {
+
+ return weight;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[PartData: name=" + name +
+ " color=" + color +
+ " weight=" + weight +
+ " city=" + city + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/tuple/PartKey.java b/examples_java/src/collections/ship/tuple/PartKey.java
new file mode 100644
index 0000000..ff65812
--- /dev/null
+++ b/examples_java/src/collections/ship/tuple/PartKey.java
@@ -0,0 +1,38 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.tuple;
+
+/**
+ * A PartKey serves as the key in the key/data pair for a part entity.
+ *
+ * <p> In this sample, PartKey is bound to the key's tuple storage entry using
+ * a TupleBinding. Because it is not used directly as storage data, it does
+ * not need to be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class PartKey {
+
+ private String number;
+
+ public PartKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public String toString() {
+
+ return "[PartKey: number=" + number + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/tuple/Sample.java b/examples_java/src/collections/ship/tuple/Sample.java
new file mode 100644
index 0000000..9c14fc3
--- /dev/null
+++ b/examples_java/src/collections/ship/tuple/Sample.java
@@ -0,0 +1,235 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.tuple;
+
+import java.io.FileNotFoundException;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.sleepycat.collections.TransactionRunner;
+import com.sleepycat.collections.TransactionWorker;
+import com.sleepycat.db.DatabaseException;
+
+/**
+ * Sample is the main entry point for the sample program and may be run as
+ * follows:
+ *
+ * <pre>
+ * java collections.ship.tuple.Sample
+ * [-h <home-directory> ]
+ * </pre>
+ *
+ * <p> The default for the home directory is ./tmp -- the tmp subdirectory of
+ * the current directory where the sample is run. The home directory must exist
+ * before running the sample. To recreate the sample database from scratch,
+ * delete all files in the home directory before running the sample. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Sample {
+
+ private SampleDatabase db;
+ private SampleViews views;
+
+ /**
+ * Run the sample program.
+ */
+ public static void main(String[] args) {
+
+ System.out.println("\nRunning sample: " + Sample.class);
+
+ // Parse the command line arguments.
+ //
+ String homeDir = "./tmp";
+ for (int i = 0; i < args.length; i += 1) {
+ if (args[i].equals("-h") && i < args.length - 1) {
+ i += 1;
+ homeDir = args[i];
+ } else {
+ System.err.println("Usage:\n java " + Sample.class.getName() +
+ "\n [-h <home-directory>]");
+ System.exit(2);
+ }
+ }
+
+ // Run the sample.
+ //
+ Sample sample = null;
+ try {
+ sample = new Sample(homeDir);
+ sample.run();
+ } catch (Exception e) {
+ // If an exception reaches this point, the last transaction did not
+ // complete. If the exception is RunRecoveryException, follow
+ // the Berkeley DB recovery procedures before running again.
+ e.printStackTrace();
+ } finally {
+ if (sample != null) {
+ try {
+ // Always attempt to close the database cleanly.
+ sample.close();
+ } catch (Exception e) {
+ System.err.println("Exception during database close:");
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Open the database and views.
+ */
+ private Sample(String homeDir)
+ throws DatabaseException, FileNotFoundException {
+
+ db = new SampleDatabase(homeDir);
+ views = new SampleViews(db);
+ }
+
+ /**
+ * Close the database cleanly.
+ */
+ private void close()
+ throws DatabaseException {
+
+ db.close();
+ }
+
+ /**
+ * Run two transactions to populate and print the database. A
+ * TransactionRunner is used to ensure consistent handling of transactions,
+ * including deadlock retries. But the best transaction handling mechanism
+ * to use depends on the application.
+ */
+ private void run()
+ throws Exception {
+
+ TransactionRunner runner = new TransactionRunner(db.getEnvironment());
+ runner.run(new PopulateDatabase());
+ runner.run(new PrintDatabase());
+ }
+
+ /**
+ * Populate the database in a single transaction.
+ */
+ private class PopulateDatabase implements TransactionWorker {
+
+ public void doWork()
+ throws Exception {
+ addSuppliers();
+ addParts();
+ addShipments();
+ }
+ }
+
+ /**
+ * Print the database in a single transaction. All entities are printed
+ * and the indices are used to print the entities for certain keys.
+ *
+ * <p> Note the use of special iterator() methods. These are used here
+ * with indices to find the shipments for certain keys.</p>
+ */
+ private class PrintDatabase implements TransactionWorker {
+
+ public void doWork()
+ throws Exception {
+ printValues("Parts",
+ views.getPartSet().iterator());
+ printValues("Suppliers",
+ views.getSupplierSet().iterator());
+ printValues("Suppliers for City Paris",
+ views.getSupplierByCityMap().duplicates(
+ "Paris").iterator());
+ printValues("Shipments",
+ views.getShipmentSet().iterator());
+ printValues("Shipments for Part P1",
+ views.getShipmentByPartMap().duplicates(
+ new PartKey("P1")).iterator());
+ printValues("Shipments for Supplier S1",
+ views.getShipmentBySupplierMap().duplicates(
+ new SupplierKey("S1")).iterator());
+ }
+ }
+
+ /**
+ * Populate the part entities in the database. If the part set is not
+ * empty, assume that this has already been done.
+ */
+ private void addParts() {
+
+ Set parts = views.getPartSet();
+ if (parts.isEmpty()) {
+ System.out.println("Adding Parts");
+ parts.add(new Part("P1", "Nut", "Red",
+ new Weight(12.0, Weight.GRAMS), "London"));
+ parts.add(new Part("P2", "Bolt", "Green",
+ new Weight(17.0, Weight.GRAMS), "Paris"));
+ parts.add(new Part("P3", "Screw", "Blue",
+ new Weight(17.0, Weight.GRAMS), "Rome"));
+ parts.add(new Part("P4", "Screw", "Red",
+ new Weight(14.0, Weight.GRAMS), "London"));
+ parts.add(new Part("P5", "Cam", "Blue",
+ new Weight(12.0, Weight.GRAMS), "Paris"));
+ parts.add(new Part("P6", "Cog", "Red",
+ new Weight(19.0, Weight.GRAMS), "London"));
+ }
+ }
+
+ /**
+ * Populate the supplier entities in the database. If the supplier set is
+ * not empty, assume that this has already been done.
+ */
+ private void addSuppliers() {
+
+ Set suppliers = views.getSupplierSet();
+ if (suppliers.isEmpty()) {
+ System.out.println("Adding Suppliers");
+ suppliers.add(new Supplier("S1", "Smith", 20, "London"));
+ suppliers.add(new Supplier("S2", "Jones", 10, "Paris"));
+ suppliers.add(new Supplier("S3", "Blake", 30, "Paris"));
+ suppliers.add(new Supplier("S4", "Clark", 20, "London"));
+ suppliers.add(new Supplier("S5", "Adams", 30, "Athens"));
+ }
+ }
+
+ /**
+ * Populate the shipment entities in the database. If the shipment set
+ * is not empty, assume that this has already been done.
+ */
+ private void addShipments() {
+
+ Set shipments = views.getShipmentSet();
+ if (shipments.isEmpty()) {
+ System.out.println("Adding Shipments");
+ shipments.add(new Shipment("P1", "S1", 300));
+ shipments.add(new Shipment("P2", "S1", 200));
+ shipments.add(new Shipment("P3", "S1", 400));
+ shipments.add(new Shipment("P4", "S1", 200));
+ shipments.add(new Shipment("P5", "S1", 100));
+ shipments.add(new Shipment("P6", "S1", 100));
+ shipments.add(new Shipment("P1", "S2", 300));
+ shipments.add(new Shipment("P2", "S2", 400));
+ shipments.add(new Shipment("P2", "S3", 200));
+ shipments.add(new Shipment("P2", "S4", 200));
+ shipments.add(new Shipment("P4", "S4", 300));
+ shipments.add(new Shipment("P5", "S4", 400));
+ }
+ }
+
+ /**
+ * Print the objects returned by an iterator of entity value objects.
+ */
+ private void printValues(String label, Iterator iterator) {
+
+ System.out.println("\n--- " + label + " ---");
+ while (iterator.hasNext()) {
+ System.out.println(iterator.next().toString());
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/tuple/SampleDatabase.java b/examples_java/src/collections/ship/tuple/SampleDatabase.java
new file mode 100644
index 0000000..ed42591
--- /dev/null
+++ b/examples_java/src/collections/ship/tuple/SampleDatabase.java
@@ -0,0 +1,323 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.tuple;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import com.sleepycat.bind.serial.ClassCatalog;
+import com.sleepycat.bind.serial.StoredClassCatalog;
+import com.sleepycat.bind.serial.TupleSerialKeyCreator;
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+import com.sleepycat.db.Database;
+import com.sleepycat.db.DatabaseConfig;
+import com.sleepycat.db.DatabaseException;
+import com.sleepycat.db.DatabaseType;
+import com.sleepycat.db.Environment;
+import com.sleepycat.db.EnvironmentConfig;
+import com.sleepycat.db.ForeignKeyDeleteAction;
+import com.sleepycat.db.SecondaryConfig;
+import com.sleepycat.db.SecondaryDatabase;
+
+/**
+ * SampleDatabase defines the storage containers, indices and foreign keys
+ * for the sample database.
+ *
+ * @author Mark Hayes
+ */
+public class SampleDatabase {
+
+ private static final String CLASS_CATALOG = "java_class_catalog";
+ private static final String SUPPLIER_STORE = "supplier_store";
+ private static final String PART_STORE = "part_store";
+ private static final String SHIPMENT_STORE = "shipment_store";
+ private static final String SHIPMENT_PART_INDEX = "shipment_part_index";
+ private static final String SHIPMENT_SUPPLIER_INDEX =
+ "shipment_supplier_index";
+ private static final String SUPPLIER_CITY_INDEX = "supplier_city_index";
+
+ private Environment env;
+ private Database partDb;
+ private Database supplierDb;
+ private Database shipmentDb;
+ private SecondaryDatabase supplierByCityDb;
+ private SecondaryDatabase shipmentByPartDb;
+ private SecondaryDatabase shipmentBySupplierDb;
+ private StoredClassCatalog javaCatalog;
+
+ /**
+ * Open all storage containers, indices, and catalogs.
+ */
+ public SampleDatabase(String homeDirectory)
+ throws DatabaseException, FileNotFoundException {
+
+ // Open the Berkeley DB environment in transactional mode.
+ //
+ System.out.println("Opening environment in: " + homeDirectory);
+ EnvironmentConfig envConfig = new EnvironmentConfig();
+ envConfig.setTransactional(true);
+ envConfig.setAllowCreate(true);
+ envConfig.setInitializeCache(true);
+ envConfig.setInitializeLocking(true);
+ env = new Environment(new File(homeDirectory), envConfig);
+
+ // Set the Berkeley DB config for opening all stores.
+ //
+ DatabaseConfig dbConfig = new DatabaseConfig();
+ dbConfig.setTransactional(true);
+ dbConfig.setAllowCreate(true);
+ dbConfig.setType(DatabaseType.BTREE);
+
+ // Create the Serial class catalog. This holds the serialized class
+ // format for all database records of serial format.
+ //
+ Database catalogDb = env.openDatabase(null, CLASS_CATALOG, null,
+ dbConfig);
+ javaCatalog = new StoredClassCatalog(catalogDb);
+
+ // Open the Berkeley DB database for the part, supplier and shipment
+ // stores. The stores are opened with no duplicate keys allowed.
+ //
+ partDb = env.openDatabase(null, PART_STORE, null, dbConfig);
+
+ supplierDb = env.openDatabase(null, SUPPLIER_STORE, null, dbConfig);
+
+ shipmentDb = env.openDatabase(null, SHIPMENT_STORE, null, dbConfig);
+
+ // Open the SecondaryDatabase for the city index of the supplier store,
+ // and for the part and supplier indices of the shipment store.
+ // Duplicate keys are allowed since more than one supplier may be in
+ // the same city, and more than one shipment may exist for the same
+ // supplier or part. A foreign key constraint is defined for the
+ // supplier and part indices to ensure that a shipment only refers to
+ // existing part and supplier keys. The CASCADE delete action means
+ // that shipments will be deleted if their associated part or supplier
+ // is deleted.
+ //
+ SecondaryConfig secConfig = new SecondaryConfig();
+ secConfig.setTransactional(true);
+ secConfig.setAllowCreate(true);
+ secConfig.setType(DatabaseType.BTREE);
+ secConfig.setSortedDuplicates(true);
+
+ secConfig.setKeyCreator(new SupplierByCityKeyCreator(javaCatalog,
+ SupplierData.class));
+ supplierByCityDb = env.openSecondaryDatabase(null, SUPPLIER_CITY_INDEX,
+ null, supplierDb,
+ secConfig);
+
+ secConfig.setForeignKeyDatabase(partDb);
+ secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE);
+ secConfig.setKeyCreator(new ShipmentByPartKeyCreator(javaCatalog,
+ ShipmentData.class));
+ shipmentByPartDb = env.openSecondaryDatabase(null, SHIPMENT_PART_INDEX,
+ null, shipmentDb,
+ secConfig);
+
+ secConfig.setForeignKeyDatabase(supplierDb);
+ secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE);
+ secConfig.setKeyCreator(new ShipmentBySupplierKeyCreator(javaCatalog,
+ ShipmentData.class));
+ shipmentBySupplierDb = env.openSecondaryDatabase(null,
+ SHIPMENT_SUPPLIER_INDEX,
+ null, shipmentDb,
+ secConfig);
+ }
+
+ /**
+ * Return the storage environment for the database.
+ */
+ public final Environment getEnvironment() {
+
+ return env;
+ }
+
+ /**
+ * Return the class catalog.
+ */
+ public final StoredClassCatalog getClassCatalog() {
+
+ return javaCatalog;
+ }
+
+ /**
+ * Return the part storage container.
+ */
+ public final Database getPartDatabase() {
+
+ return partDb;
+ }
+
+ /**
+ * Return the supplier storage container.
+ */
+ public final Database getSupplierDatabase() {
+
+ return supplierDb;
+ }
+
+ /**
+ * Return the shipment storage container.
+ */
+ public final Database getShipmentDatabase() {
+
+ return shipmentDb;
+ }
+
+ /**
+ * Return the shipment-by-part index.
+ */
+ public final SecondaryDatabase getShipmentByPartDatabase() {
+
+ return shipmentByPartDb;
+ }
+
+ /**
+ * Return the shipment-by-supplier index.
+ */
+ public final SecondaryDatabase getShipmentBySupplierDatabase() {
+
+ return shipmentBySupplierDb;
+ }
+
+ /**
+ * Return the supplier-by-city index.
+ */
+ public final SecondaryDatabase getSupplierByCityDatabase() {
+
+ return supplierByCityDb;
+ }
+
+ /**
+ * Close all stores (closing a store automatically closes its indices).
+ */
+ public void close()
+ throws DatabaseException {
+
+ // Close secondary databases, then primary databases.
+ supplierByCityDb.close();
+ shipmentByPartDb.close();
+ shipmentBySupplierDb.close();
+ partDb.close();
+ supplierDb.close();
+ shipmentDb.close();
+ // And don't forget to close the catalog and the environment.
+ javaCatalog.close();
+ env.close();
+ }
+
+ /**
+ * The SecondaryKeyCreator for the SupplierByCity index. This is an
+ * extension of the abstract class TupleSerialKeyCreator, which implements
+ * SecondaryKeyCreator for the case where the data keys are of the format
+ * TupleFormat and the data values are of the format SerialFormat.
+ */
+ private static class SupplierByCityKeyCreator
+ extends TupleSerialKeyCreator {
+
+ /**
+ * Construct the city key extractor.
+ * @param catalog is the class catalog.
+ * @param valueClass is the supplier value class.
+ */
+ private SupplierByCityKeyCreator(ClassCatalog catalog,
+ Class valueClass) {
+
+ super(catalog, valueClass);
+ }
+
+ /**
+ * Extract the city key from a supplier key/value pair. The city key
+ * is stored in the supplier value, so the supplier key is not used.
+ */
+ public boolean createSecondaryKey(TupleInput primaryKeyInput,
+ Object valueInput,
+ TupleOutput indexKeyOutput) {
+
+ SupplierData supplierData = (SupplierData) valueInput;
+ String city = supplierData.getCity();
+ if (city != null) {
+ indexKeyOutput.writeString(supplierData.getCity());
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * The SecondaryKeyCreator for the ShipmentByPart index. This is an
+ * extension of the abstract class TupleSerialKeyCreator, which implements
+ * SecondaryKeyCreator for the case where the data keys are of the format
+ * TupleFormat and the data values are of the format SerialFormat.
+ */
+ private static class ShipmentByPartKeyCreator
+ extends TupleSerialKeyCreator {
+
+ /**
+ * Construct the part key extractor.
+ * @param catalog is the class catalog.
+ * @param valueClass is the shipment value class.
+ */
+ private ShipmentByPartKeyCreator(ClassCatalog catalog,
+ Class valueClass) {
+ super(catalog, valueClass);
+ }
+
+ /**
+ * Extract the part key from a shipment key/value pair. The part key
+ * is stored in the shipment key, so the shipment value is not used.
+ */
+ public boolean createSecondaryKey(TupleInput primaryKeyInput,
+ Object valueInput,
+ TupleOutput indexKeyOutput) {
+
+ String partNumber = primaryKeyInput.readString();
+ // don't bother reading the supplierNumber
+ indexKeyOutput.writeString(partNumber);
+ return true;
+ }
+ }
+
+ /**
+ * The SecondaryKeyCreator for the ShipmentBySupplier index. This is an
+ * extension of the abstract class TupleSerialKeyCreator, which implements
+ * SecondaryKeyCreator for the case where the data keys are of the format
+ * TupleFormat and the data values are of the format SerialFormat.
+ */
+ private static class ShipmentBySupplierKeyCreator
+ extends TupleSerialKeyCreator {
+
+ /**
+ * Construct the supplier key extractor.
+ * @param catalog is the class catalog.
+ * @param valueClass is the shipment value class.
+ */
+ private ShipmentBySupplierKeyCreator(ClassCatalog catalog,
+ Class valueClass) {
+ super(catalog, valueClass);
+ }
+
+ /**
+ * Extract the supplier key from a shipment key/value pair. The
+ * supplier key is stored in the shipment key, so the shipment value is
+ * not used.
+ */
+ public boolean createSecondaryKey(TupleInput primaryKeyInput,
+ Object valueInput,
+ TupleOutput indexKeyOutput) {
+
+ primaryKeyInput.readString(); // skip the partNumber
+ String supplierNumber = primaryKeyInput.readString();
+ indexKeyOutput.writeString(supplierNumber);
+ return true;
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/tuple/SampleViews.java b/examples_java/src/collections/ship/tuple/SampleViews.java
new file mode 100644
index 0000000..3bb4b1d
--- /dev/null
+++ b/examples_java/src/collections/ship/tuple/SampleViews.java
@@ -0,0 +1,396 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.tuple;
+
+import com.sleepycat.bind.EntityBinding;
+import com.sleepycat.bind.EntryBinding;
+import com.sleepycat.bind.serial.ClassCatalog;
+import com.sleepycat.bind.serial.TupleSerialBinding;
+import com.sleepycat.bind.tuple.TupleBinding;
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+import com.sleepycat.collections.StoredSortedMap;
+import com.sleepycat.collections.StoredSortedValueSet;
+
+/**
+ * SampleViews defines the data bindings and collection views for the sample
+ * database.
+ *
+ * @author Mark Hayes
+ */
+public class SampleViews {
+
+ private StoredSortedMap partMap;
+ private StoredSortedMap supplierMap;
+ private StoredSortedMap shipmentMap;
+ private StoredSortedMap shipmentByPartMap;
+ private StoredSortedMap shipmentBySupplierMap;
+ private StoredSortedMap supplierByCityMap;
+
+ /**
+ * Create the data bindings and collection views.
+ */
+ public SampleViews(SampleDatabase db) {
+
+ // Create the data bindings.
+ // In this sample, EntityBinding classes are used to bind the stored
+ // key/data entry pair to a combined data object. For keys, a
+ // one-to-one binding is implemented with EntryBinding classes to bind
+ // the stored tuple entry to a key Object.
+ //
+ ClassCatalog catalog = db.getClassCatalog();
+ EntryBinding partKeyBinding =
+ new PartKeyBinding();
+ EntityBinding partDataBinding =
+ new PartBinding(catalog, PartData.class);
+ EntryBinding supplierKeyBinding =
+ new SupplierKeyBinding();
+ EntityBinding supplierDataBinding =
+ new SupplierBinding(catalog, SupplierData.class);
+ EntryBinding shipmentKeyBinding =
+ new ShipmentKeyBinding();
+ EntityBinding shipmentDataBinding =
+ new ShipmentBinding(catalog, ShipmentData.class);
+ EntryBinding cityKeyBinding =
+ TupleBinding.getPrimitiveBinding(String.class);
+
+ // Create map views for all stores and indices.
+ // StoredSortedMap is used since the stores and indices are ordered
+ // (they use the DB_BTREE access method).
+ //
+ partMap =
+ new StoredSortedMap(db.getPartDatabase(),
+ partKeyBinding, partDataBinding, true);
+ supplierMap =
+ new StoredSortedMap(db.getSupplierDatabase(),
+ supplierKeyBinding, supplierDataBinding, true);
+ shipmentMap =
+ new StoredSortedMap(db.getShipmentDatabase(),
+ shipmentKeyBinding, shipmentDataBinding, true);
+ shipmentByPartMap =
+ new StoredSortedMap(db.getShipmentByPartDatabase(),
+ partKeyBinding, shipmentDataBinding, true);
+ shipmentBySupplierMap =
+ new StoredSortedMap(db.getShipmentBySupplierDatabase(),
+ supplierKeyBinding, shipmentDataBinding, true);
+ supplierByCityMap =
+ new StoredSortedMap(db.getSupplierByCityDatabase(),
+ cityKeyBinding, supplierDataBinding, true);
+ }
+
+ // The views returned below can be accessed using the java.util.Map or
+ // java.util.Set interfaces, or using the StoredSortedMap and
+ // StoredValueSet classes, which provide additional methods. The entity
+ // sets could be obtained directly from the Map.values() method but
+ // convenience methods are provided here to return them in order to avoid
+ // down-casting elsewhere.
+
+ /**
+ * Return a map view of the part storage container.
+ */
+ public StoredSortedMap getPartMap() {
+
+ return partMap;
+ }
+
+ /**
+ * Return a map view of the supplier storage container.
+ */
+ public StoredSortedMap getSupplierMap() {
+
+ return supplierMap;
+ }
+
+ /**
+ * Return a map view of the shipment storage container.
+ */
+ public StoredSortedMap getShipmentMap() {
+
+ return shipmentMap;
+ }
+
+ /**
+ * Return an entity set view of the part storage container.
+ */
+ public StoredSortedValueSet getPartSet() {
+
+ return (StoredSortedValueSet) partMap.values();
+ }
+
+ /**
+ * Return an entity set view of the supplier storage container.
+ */
+ public StoredSortedValueSet getSupplierSet() {
+
+ return (StoredSortedValueSet) supplierMap.values();
+ }
+
+ /**
+ * Return an entity set view of the shipment storage container.
+ */
+ public StoredSortedValueSet getShipmentSet() {
+
+ return (StoredSortedValueSet) shipmentMap.values();
+ }
+
+ /**
+ * Return a map view of the shipment-by-part index.
+ */
+ public StoredSortedMap getShipmentByPartMap() {
+
+ return shipmentByPartMap;
+ }
+
+ /**
+ * Return a map view of the shipment-by-supplier index.
+ */
+ public StoredSortedMap getShipmentBySupplierMap() {
+
+ return shipmentBySupplierMap;
+ }
+
+ /**
+ * Return a map view of the supplier-by-city index.
+ */
+ public final StoredSortedMap getSupplierByCityMap() {
+
+ return supplierByCityMap;
+ }
+
+ /**
+ * PartKeyBinding is used to bind the stored key tuple entry for a part to
+ * a key object representation.
+ */
+ private static class PartKeyBinding extends TupleBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private PartKeyBinding() {
+ }
+
+ /**
+ * Create the key object from the stored key tuple entry.
+ */
+ public Object entryToObject(TupleInput input) {
+
+ String number = input.readString();
+ return new PartKey(number);
+ }
+
+ /**
+ * Create the stored key tuple entry from the key object.
+ */
+ public void objectToEntry(Object object, TupleOutput output) {
+
+ PartKey key = (PartKey) object;
+ output.writeString(key.getNumber());
+ }
+ }
+
+ /**
+ * PartBinding is used to bind the stored key/data entry pair for a part
+ * to a combined data object (entity).
+ */
+ private static class PartBinding extends TupleSerialBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private PartBinding(ClassCatalog classCatalog, Class dataClass) {
+
+ super(classCatalog, dataClass);
+ }
+
+ /**
+ * Create the entity by combining the stored key and data.
+ */
+ public Object entryToObject(TupleInput keyInput, Object dataInput) {
+
+ String number = keyInput.readString();
+ PartData data = (PartData) dataInput;
+ return new Part(number, data.getName(), data.getColor(),
+ data.getWeight(), data.getCity());
+ }
+
+ /**
+ * Create the stored key from the entity.
+ */
+ public void objectToKey(Object object, TupleOutput output) {
+
+ Part part = (Part) object;
+ output.writeString(part.getNumber());
+ }
+
+ /**
+ * Create the stored data from the entity.
+ */
+ public Object objectToData(Object object) {
+
+ Part part = (Part) object;
+ return new PartData(part.getName(), part.getColor(),
+ part.getWeight(), part.getCity());
+ }
+ }
+
+ /**
+ * SupplierKeyBinding is used to bind the stored key tuple entry for a
+ * supplier to a key object representation.
+ */
+ private static class SupplierKeyBinding extends TupleBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private SupplierKeyBinding() {
+ }
+
+ /**
+ * Create the key object from the stored key tuple entry.
+ */
+ public Object entryToObject(TupleInput input) {
+
+ String number = input.readString();
+ return new SupplierKey(number);
+ }
+
+ /**
+ * Create the stored key tuple entry from the key object.
+ */
+ public void objectToEntry(Object object, TupleOutput output) {
+
+ SupplierKey key = (SupplierKey) object;
+ output.writeString(key.getNumber());
+ }
+ }
+
+ /**
+ * SupplierBinding is used to bind the stored key/data entry pair for a
+ * supplier to a combined data object (entity).
+ */
+ private static class SupplierBinding extends TupleSerialBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private SupplierBinding(ClassCatalog classCatalog, Class dataClass) {
+
+ super(classCatalog, dataClass);
+ }
+
+ /**
+ * Create the entity by combining the stored key and data.
+ */
+ public Object entryToObject(TupleInput keyInput, Object dataInput) {
+
+ String number = keyInput.readString();
+ SupplierData data = (SupplierData) dataInput;
+ return new Supplier(number, data.getName(),
+ data.getStatus(), data.getCity());
+ }
+
+ /**
+ * Create the stored key from the entity.
+ */
+ public void objectToKey(Object object, TupleOutput output) {
+
+ Supplier supplier = (Supplier) object;
+ output.writeString(supplier.getNumber());
+ }
+
+ /**
+ * Create the stored data from the entity.
+ */
+ public Object objectToData(Object object) {
+
+ Supplier supplier = (Supplier) object;
+ return new SupplierData(supplier.getName(), supplier.getStatus(),
+ supplier.getCity());
+ }
+ }
+
+ /**
+ * ShipmentKeyBinding is used to bind the stored key tuple entry for a
+ * shipment to a key object representation.
+ */
+ private static class ShipmentKeyBinding extends TupleBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private ShipmentKeyBinding() {
+ }
+
+ /**
+ * Create the key object from the stored key tuple entry.
+ */
+ public Object entryToObject(TupleInput input) {
+
+ String partNumber = input.readString();
+ String supplierNumber = input.readString();
+ return new ShipmentKey(partNumber, supplierNumber);
+ }
+
+ /**
+ * Create the stored key tuple entry from the key object.
+ */
+ public void objectToEntry(Object object, TupleOutput output) {
+
+ ShipmentKey key = (ShipmentKey) object;
+ output.writeString(key.getPartNumber());
+ output.writeString(key.getSupplierNumber());
+ }
+ }
+
+ /**
+ * ShipmentBinding is used to bind the stored key/data entry pair for a
+ * shipment to a combined data object (entity).
+ */
+ private static class ShipmentBinding extends TupleSerialBinding {
+
+ /**
+ * Construct the binding object.
+ */
+ private ShipmentBinding(ClassCatalog classCatalog, Class dataClass) {
+
+ super(classCatalog, dataClass);
+ }
+
+ /**
+ * Create the entity by combining the stored key and data.
+ */
+ public Object entryToObject(TupleInput keyInput, Object dataInput) {
+
+ String partNumber = keyInput.readString();
+ String supplierNumber = keyInput.readString();
+ ShipmentData data = (ShipmentData) dataInput;
+ return new Shipment(partNumber, supplierNumber,
+ data.getQuantity());
+ }
+
+ /**
+ * Create the stored key from the entity.
+ */
+ public void objectToKey(Object object, TupleOutput output) {
+
+ Shipment shipment = (Shipment) object;
+ output.writeString(shipment.getPartNumber());
+ output.writeString(shipment.getSupplierNumber());
+ }
+
+ /**
+ * Create the stored data from the entity.
+ */
+ public Object objectToData(Object object) {
+
+ Shipment shipment = (Shipment) object;
+ return new ShipmentData(shipment.getQuantity());
+ }
+ }
+}
diff --git a/examples_java/src/collections/ship/tuple/Shipment.java b/examples_java/src/collections/ship/tuple/Shipment.java
new file mode 100644
index 0000000..6c15ea0
--- /dev/null
+++ b/examples_java/src/collections/ship/tuple/Shipment.java
@@ -0,0 +1,55 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.tuple;
+
+/**
+ * A Shipment represents the combined key/data pair for a shipment entity.
+ *
+ * <p> In this sample, Shipment is created from the stored key/data entry
+ * using a SerialSerialBinding. See {@link SampleViews.ShipmentBinding} for
+ * details. Since this class is not used directly for data storage, it does
+ * not need to be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Shipment {
+
+ private String partNumber;
+ private String supplierNumber;
+ private int quantity;
+
+ public Shipment(String partNumber, String supplierNumber, int quantity) {
+
+ this.partNumber = partNumber;
+ this.supplierNumber = supplierNumber;
+ this.quantity = quantity;
+ }
+
+ public final String getPartNumber() {
+
+ return partNumber;
+ }
+
+ public final String getSupplierNumber() {
+
+ return supplierNumber;
+ }
+
+ public final int getQuantity() {
+
+ return quantity;
+ }
+
+ public String toString() {
+
+ return "[Shipment: part=" + partNumber +
+ " supplier=" + supplierNumber +
+ " quantity=" + quantity + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/tuple/ShipmentData.java b/examples_java/src/collections/ship/tuple/ShipmentData.java
new file mode 100644
index 0000000..4009c61
--- /dev/null
+++ b/examples_java/src/collections/ship/tuple/ShipmentData.java
@@ -0,0 +1,42 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.tuple;
+
+import java.io.Serializable;
+
+/**
+ * A ShipmentData serves as the value in the key/value pair for a shipment
+ * entity.
+ *
+ * <p> In this sample, ShipmentData is used only as the storage data for the
+ * value, while the Shipment object is used as the value's object
+ * representation. Because it is used directly as storage data using
+ * serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class ShipmentData implements Serializable {
+
+ private int quantity;
+
+ public ShipmentData(int quantity) {
+
+ this.quantity = quantity;
+ }
+
+ public final int getQuantity() {
+
+ return quantity;
+ }
+
+ public String toString() {
+
+ return "[ShipmentData: quantity=" + quantity + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/tuple/ShipmentKey.java b/examples_java/src/collections/ship/tuple/ShipmentKey.java
new file mode 100644
index 0000000..83d4a18
--- /dev/null
+++ b/examples_java/src/collections/ship/tuple/ShipmentKey.java
@@ -0,0 +1,46 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.tuple;
+
+/**
+ * A ShipmentKey serves as the key in the key/data pair for a shipment entity.
+ *
+ * <p> In this sample, ShipmentKey is bound to the key's tuple storage entry
+ * using a TupleBinding. Because it is not used directly as storage data, it
+ * does not need to be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class ShipmentKey {
+
+ private String partNumber;
+ private String supplierNumber;
+
+ public ShipmentKey(String partNumber, String supplierNumber) {
+
+ this.partNumber = partNumber;
+ this.supplierNumber = supplierNumber;
+ }
+
+ public final String getPartNumber() {
+
+ return partNumber;
+ }
+
+ public final String getSupplierNumber() {
+
+ return supplierNumber;
+ }
+
+ public String toString() {
+
+ return "[ShipmentKey: supplier=" + supplierNumber +
+ " part=" + partNumber + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/tuple/Supplier.java b/examples_java/src/collections/ship/tuple/Supplier.java
new file mode 100644
index 0000000..8466271
--- /dev/null
+++ b/examples_java/src/collections/ship/tuple/Supplier.java
@@ -0,0 +1,63 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.tuple;
+
+/**
+ * A Supplier represents the combined key/data pair for a supplier entity.
+ *
+ * <p> In this sample, Supplier is created from the stored key/data entry
+ * using a SerialSerialBinding. See {@link SampleViews.SupplierBinding} for
+ * details. Since this class is not used directly for data storage, it does
+ * not need to be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Supplier {
+
+ private String number;
+ private String name;
+ private int status;
+ private String city;
+
+ public Supplier(String number, String name, int status, String city) {
+
+ this.number = number;
+ this.name = name;
+ this.status = status;
+ this.city = city;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final int getStatus() {
+
+ return status;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[Supplier: number=" + number +
+ " name=" + name +
+ " status=" + status +
+ " city=" + city + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/tuple/SupplierData.java b/examples_java/src/collections/ship/tuple/SupplierData.java
new file mode 100644
index 0000000..6e863b9
--- /dev/null
+++ b/examples_java/src/collections/ship/tuple/SupplierData.java
@@ -0,0 +1,58 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.tuple;
+
+import java.io.Serializable;
+
+/**
+ * A SupplierData serves as the value in the key/value pair for a supplier
+ * entity.
+ *
+ * <p> In this sample, SupplierData is used only as the storage data for the
+ * value, while the Supplier object is used as the value's object
+ * representation. Because it is used directly as storage data using
+ * serial format, it must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class SupplierData implements Serializable {
+
+ private String name;
+ private int status;
+ private String city;
+
+ public SupplierData(String name, int status, String city) {
+
+ this.name = name;
+ this.status = status;
+ this.city = city;
+ }
+
+ public final String getName() {
+
+ return name;
+ }
+
+ public final int getStatus() {
+
+ return status;
+ }
+
+ public final String getCity() {
+
+ return city;
+ }
+
+ public String toString() {
+
+ return "[SupplierData: name=" + name +
+ " status=" + status +
+ " city=" + city + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/tuple/SupplierKey.java b/examples_java/src/collections/ship/tuple/SupplierKey.java
new file mode 100644
index 0000000..afc1fa0
--- /dev/null
+++ b/examples_java/src/collections/ship/tuple/SupplierKey.java
@@ -0,0 +1,38 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.tuple;
+
+/**
+ * A SupplierKey serves as the key in the key/data pair for a supplier entity.
+ *
+ * <p> In this sample, SupplierKey is bound to the key's tuple storage entry
+ * using a TupleBinding. Because it is not used directly as storage data, it
+ * does not need to be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class SupplierKey {
+
+ private String number;
+
+ public SupplierKey(String number) {
+
+ this.number = number;
+ }
+
+ public final String getNumber() {
+
+ return number;
+ }
+
+ public String toString() {
+
+ return "[SupplierKey: number=" + number + ']';
+ }
+}
diff --git a/examples_java/src/collections/ship/tuple/Weight.java b/examples_java/src/collections/ship/tuple/Weight.java
new file mode 100644
index 0000000..850e5c4
--- /dev/null
+++ b/examples_java/src/collections/ship/tuple/Weight.java
@@ -0,0 +1,49 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2002-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package collections.ship.tuple;
+
+import java.io.Serializable;
+
+/**
+ * Weight represents a weight amount and unit of measure.
+ *
+ * <p> In this sample, Weight is embedded in part data values which are stored
+ * as Java serialized objects; therefore Weight must be Serializable. </p>
+ *
+ * @author Mark Hayes
+ */
+public class Weight implements Serializable {
+
+ public final static String GRAMS = "grams";
+ public final static String OUNCES = "ounces";
+
+ private double amount;
+ private String units;
+
+ public Weight(double amount, String units) {
+
+ this.amount = amount;
+ this.units = units;
+ }
+
+ public final double getAmount() {
+
+ return amount;
+ }
+
+ public final String getUnits() {
+
+ return units;
+ }
+
+ public String toString() {
+
+ return "[" + amount + ' ' + units + ']';
+ }
+}