1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2002,2008 Oracle.  All rights reserved.
5 *
6 * $Id: SampleDatabase.java,v 12.8 2008/02/07 17:12:22 mark Exp $
7 */
8
9package collections.ship.marshal;
10
11import java.io.File;
12import java.io.FileNotFoundException;
13
14import com.sleepycat.bind.serial.ClassCatalog;
15import com.sleepycat.bind.serial.StoredClassCatalog;
16import com.sleepycat.bind.serial.TupleSerialKeyCreator;
17import com.sleepycat.bind.tuple.TupleInput;
18import com.sleepycat.bind.tuple.TupleOutput;
19import com.sleepycat.db.Database;
20import com.sleepycat.db.DatabaseConfig;
21import com.sleepycat.db.DatabaseException;
22import com.sleepycat.db.DatabaseType;
23import com.sleepycat.db.Environment;
24import com.sleepycat.db.EnvironmentConfig;
25import com.sleepycat.db.ForeignKeyDeleteAction;
26import com.sleepycat.db.SecondaryConfig;
27import com.sleepycat.db.SecondaryDatabase;
28
29/**
30 * SampleDatabase defines the storage containers, indices and foreign keys
31 * for the sample database.
32 *
33 * @author Mark Hayes
34 */
35public class SampleDatabase {
36
37    private static final String CLASS_CATALOG = "java_class_catalog";
38    private static final String SUPPLIER_STORE = "supplier_store";
39    private static final String PART_STORE = "part_store";
40    private static final String SHIPMENT_STORE = "shipment_store";
41    private static final String SHIPMENT_PART_INDEX = "shipment_part_index";
42    private static final String SHIPMENT_SUPPLIER_INDEX =
43	"shipment_supplier_index";
44    private static final String SUPPLIER_CITY_INDEX = "supplier_city_index";
45
46    private Environment env;
47    private Database partDb;
48    private Database supplierDb;
49    private Database shipmentDb;
50    private SecondaryDatabase supplierByCityDb;
51    private SecondaryDatabase shipmentByPartDb;
52    private SecondaryDatabase shipmentBySupplierDb;
53    private StoredClassCatalog javaCatalog;
54
55    /**
56     * Open all storage containers, indices, and catalogs.
57     */
58    public SampleDatabase(String homeDirectory)
59        throws DatabaseException, FileNotFoundException {
60
61        // Open the Berkeley DB environment in transactional mode.
62        //
63        System.out.println("Opening environment in: " + homeDirectory);
64        EnvironmentConfig envConfig = new EnvironmentConfig();
65        envConfig.setTransactional(true);
66        envConfig.setAllowCreate(true);
67        envConfig.setInitializeCache(true);
68        envConfig.setInitializeLocking(true);
69        env = new Environment(new File(homeDirectory), envConfig);
70
71        // Set the Berkeley DB config for opening all stores.
72        //
73        DatabaseConfig dbConfig = new DatabaseConfig();
74        dbConfig.setTransactional(true);
75        dbConfig.setAllowCreate(true);
76        dbConfig.setType(DatabaseType.BTREE);
77
78        // Create the Serial class catalog.  This holds the serialized class
79        // format for all database records of serial format.
80        //
81        Database catalogDb = env.openDatabase(null, CLASS_CATALOG, null,
82                                              dbConfig);
83        javaCatalog = new StoredClassCatalog(catalogDb);
84
85        // Open the Berkeley DB database for the part, supplier and shipment
86        // stores.  The stores are opened with no duplicate keys allowed.
87        //
88        partDb = env.openDatabase(null, PART_STORE, null, dbConfig);
89
90        supplierDb = env.openDatabase(null, SUPPLIER_STORE, null, dbConfig);
91
92        shipmentDb = env.openDatabase(null, SHIPMENT_STORE, null, dbConfig);
93
94        // Open the SecondaryDatabase for the city index of the supplier store,
95        // and for the part and supplier indices of the shipment store.
96        // Duplicate keys are allowed since more than one supplier may be in
97        // the same city, and more than one shipment may exist for the same
98        // supplier or part.  A foreign key constraint is defined for the
99        // supplier and part indices to ensure that a shipment only refers to
100        // existing part and supplier keys.  The CASCADE delete action means
101        // that shipments will be deleted if their associated part or supplier
102        // is deleted.
103        //
104        SecondaryConfig secConfig = new SecondaryConfig();
105        secConfig.setTransactional(true);
106        secConfig.setAllowCreate(true);
107        secConfig.setType(DatabaseType.BTREE);
108        secConfig.setSortedDuplicates(true);
109
110        secConfig.setKeyCreator(new MarshalledKeyCreator(javaCatalog,
111                                                         Supplier.class,
112                                                         Supplier.CITY_KEY));
113        supplierByCityDb = env.openSecondaryDatabase(null, SUPPLIER_CITY_INDEX,
114                                                     null, supplierDb,
115                                                     secConfig);
116
117        secConfig.setForeignKeyDatabase(partDb);
118        secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE);
119        secConfig.setKeyCreator(new MarshalledKeyCreator(javaCatalog,
120                                                         Shipment.class,
121                                                         Shipment.PART_KEY));
122        shipmentByPartDb = env.openSecondaryDatabase(null, SHIPMENT_PART_INDEX,
123                                                     null, shipmentDb,
124                                                     secConfig);
125
126        secConfig.setForeignKeyDatabase(supplierDb);
127        secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE);
128        secConfig.setKeyCreator(new MarshalledKeyCreator(javaCatalog,
129                                                         Shipment.class,
130                                                     Shipment.SUPPLIER_KEY));
131        shipmentBySupplierDb = env.openSecondaryDatabase(null,
132                                                     SHIPMENT_SUPPLIER_INDEX,
133                                                     null, shipmentDb,
134                                                     secConfig);
135    }
136
137    /**
138     * Return the storage environment for the database.
139     */
140    public final Environment getEnvironment() {
141
142        return env;
143    }
144
145    /**
146     * Return the class catalog.
147     */
148    public final StoredClassCatalog getClassCatalog() {
149
150        return javaCatalog;
151    }
152
153    /**
154     * Return the part storage container.
155     */
156    public final Database getPartDatabase() {
157
158        return partDb;
159    }
160
161    /**
162     * Return the supplier storage container.
163     */
164    public final Database getSupplierDatabase() {
165
166        return supplierDb;
167    }
168
169    /**
170     * Return the shipment storage container.
171     */
172    public final Database getShipmentDatabase() {
173
174        return shipmentDb;
175    }
176
177    /**
178     * Return the shipment-by-part index.
179     */
180    public final SecondaryDatabase getShipmentByPartDatabase() {
181
182        return shipmentByPartDb;
183    }
184
185    /**
186     * Return the shipment-by-supplier index.
187     */
188    public final SecondaryDatabase getShipmentBySupplierDatabase() {
189
190        return shipmentBySupplierDb;
191    }
192
193    /**
194     * Return the supplier-by-city index.
195     */
196    public final SecondaryDatabase getSupplierByCityDatabase() {
197
198        return supplierByCityDb;
199    }
200
201    /**
202     * Close all stores (closing a store automatically closes its indices).
203     */
204    public void close()
205        throws DatabaseException {
206
207        // Close secondary databases, then primary databases.
208        supplierByCityDb.close();
209        shipmentByPartDb.close();
210        shipmentBySupplierDb.close();
211        partDb.close();
212        supplierDb.close();
213        shipmentDb.close();
214        // And don't forget to close the catalog and the environment.
215        javaCatalog.close();
216        env.close();
217    }
218
219    /**
220     * The SecondaryKeyCreator for MarshalledEnt objects.  This is an
221     * extension of the abstract class TupleSerialKeyCreator, which implements
222     * SecondaryKeyCreator for the case where the data keys are of the format
223     * TupleFormat and the data values are of the format SerialFormat.
224     */
225    private static class MarshalledKeyCreator
226        extends TupleSerialKeyCreator {
227
228        private String keyName;
229
230        /**
231         * Construct the key creator.
232         * @param catalog is the class catalog.
233         * @param valueClass is the supplier value class.
234         * @param keyName is the key name passed to the marshalling methods.
235         */
236        private MarshalledKeyCreator(ClassCatalog catalog,
237                                     Class valueClass,
238                                     String keyName) {
239
240            super(catalog, valueClass);
241            this.keyName = keyName;
242        }
243
244        /**
245         * Extract the city key from a supplier key/value pair.  The city key
246         * is stored in the supplier value, so the supplier key is not used.
247         */
248        public boolean createSecondaryKey(TupleInput primaryKeyInput,
249                                          Object valueInput,
250                                          TupleOutput indexKeyOutput) {
251
252            // the primary key is unmarshalled before marshalling the index
253            // key, to account for cases where the index key is composed of
254            // data elements from the primary key
255            MarshalledEnt entity = (MarshalledEnt) valueInput;
256            entity.unmarshalPrimaryKey(primaryKeyInput);
257            return entity.marshalSecondaryKey(keyName, indexKeyOutput);
258        }
259    }
260}
261