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:21 mark Exp $
7 */
8
9package collections.ship.entity;
10
11import java.io.File;
12import java.io.FileNotFoundException;
13
14import com.sleepycat.bind.serial.ClassCatalog;
15import com.sleepycat.bind.serial.SerialSerialKeyCreator;
16import com.sleepycat.bind.serial.StoredClassCatalog;
17import com.sleepycat.db.Database;
18import com.sleepycat.db.DatabaseConfig;
19import com.sleepycat.db.DatabaseException;
20import com.sleepycat.db.DatabaseType;
21import com.sleepycat.db.Environment;
22import com.sleepycat.db.EnvironmentConfig;
23import com.sleepycat.db.ForeignKeyDeleteAction;
24import com.sleepycat.db.SecondaryConfig;
25import com.sleepycat.db.SecondaryDatabase;
26
27/**
28 * SampleDatabase defines the storage containers, indices and foreign keys
29 * for the sample database.
30 *
31 * @author Mark Hayes
32 */
33public class SampleDatabase {
34
35    private static final String CLASS_CATALOG = "java_class_catalog";
36    private static final String SUPPLIER_STORE = "supplier_store";
37    private static final String PART_STORE = "part_store";
38    private static final String SHIPMENT_STORE = "shipment_store";
39    private static final String SHIPMENT_PART_INDEX = "shipment_part_index";
40    private static final String SHIPMENT_SUPPLIER_INDEX =
41	"shipment_supplier_index";
42    private static final String SUPPLIER_CITY_INDEX = "supplier_city_index";
43
44    private Environment env;
45    private Database partDb;
46    private Database supplierDb;
47    private Database shipmentDb;
48    private SecondaryDatabase supplierByCityDb;
49    private SecondaryDatabase shipmentByPartDb;
50    private SecondaryDatabase shipmentBySupplierDb;
51    private StoredClassCatalog javaCatalog;
52
53    /**
54     * Open all storage containers, indices, and catalogs.
55     */
56    public SampleDatabase(String homeDirectory)
57        throws DatabaseException, FileNotFoundException {
58
59        // Open the Berkeley DB environment in transactional mode.
60        //
61        System.out.println("Opening environment in: " + homeDirectory);
62        EnvironmentConfig envConfig = new EnvironmentConfig();
63        envConfig.setTransactional(true);
64        envConfig.setAllowCreate(true);
65        envConfig.setInitializeCache(true);
66        envConfig.setInitializeLocking(true);
67        env = new Environment(new File(homeDirectory), envConfig);
68
69        // Set the Berkeley DB config for opening all stores.
70        //
71        DatabaseConfig dbConfig = new DatabaseConfig();
72        dbConfig.setTransactional(true);
73        dbConfig.setAllowCreate(true);
74        dbConfig.setType(DatabaseType.BTREE);
75
76        // Create the Serial class catalog.  This holds the serialized class
77        // format for all database records of serial format.
78        //
79        Database catalogDb = env.openDatabase(null, CLASS_CATALOG, null,
80                                              dbConfig);
81        javaCatalog = new StoredClassCatalog(catalogDb);
82
83        // Open the Berkeley DB database for the part, supplier and shipment
84        // stores.  The stores are opened with no duplicate keys allowed.
85        //
86        partDb = env.openDatabase(null, PART_STORE, null, dbConfig);
87
88        supplierDb = env.openDatabase(null, SUPPLIER_STORE, null, dbConfig);
89
90        shipmentDb = env.openDatabase(null, SHIPMENT_STORE, null, dbConfig);
91
92        // Open the SecondaryDatabase for the city index of the supplier store,
93        // and for the part and supplier indices of the shipment store.
94        // Duplicate keys are allowed since more than one supplier may be in
95        // the same city, and more than one shipment may exist for the same
96        // supplier or part.  A foreign key constraint is defined for the
97        // supplier and part indices to ensure that a shipment only refers to
98        // existing part and supplier keys.  The CASCADE delete action means
99        // that shipments will be deleted if their associated part or supplier
100        // is deleted.
101        //
102        SecondaryConfig secConfig = new SecondaryConfig();
103        secConfig.setTransactional(true);
104        secConfig.setAllowCreate(true);
105        secConfig.setType(DatabaseType.BTREE);
106        secConfig.setSortedDuplicates(true);
107
108        secConfig.setKeyCreator(
109            new SupplierByCityKeyCreator(javaCatalog,
110                                         SupplierKey.class,
111                                         SupplierData.class,
112                                         String.class));
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(
120            new ShipmentByPartKeyCreator(javaCatalog,
121                                         ShipmentKey.class,
122                                         ShipmentData.class,
123                                         PartKey.class));
124        shipmentByPartDb = env.openSecondaryDatabase(null, SHIPMENT_PART_INDEX,
125                                                     null, shipmentDb,
126                                                     secConfig);
127
128        secConfig.setForeignKeyDatabase(supplierDb);
129        secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE);
130        secConfig.setKeyCreator(
131            new ShipmentBySupplierKeyCreator(javaCatalog,
132                                             ShipmentKey.class,
133                                             ShipmentData.class,
134                                             SupplierKey.class));
135        shipmentBySupplierDb = env.openSecondaryDatabase(null,
136                                                     SHIPMENT_SUPPLIER_INDEX,
137                                                     null, shipmentDb,
138                                                     secConfig);
139    }
140
141    /**
142     * Return the storage environment for the database.
143     */
144    public final Environment getEnvironment() {
145
146        return env;
147    }
148
149    /**
150     * Return the class catalog.
151     */
152    public final StoredClassCatalog getClassCatalog() {
153
154        return javaCatalog;
155    }
156
157    /**
158     * Return the part storage container.
159     */
160    public final Database getPartDatabase() {
161
162        return partDb;
163    }
164
165    /**
166     * Return the supplier storage container.
167     */
168    public final Database getSupplierDatabase() {
169
170        return supplierDb;
171    }
172
173    /**
174     * Return the shipment storage container.
175     */
176    public final Database getShipmentDatabase() {
177
178        return shipmentDb;
179    }
180
181    /**
182     * Return the shipment-by-part index.
183     */
184    public final SecondaryDatabase getShipmentByPartDatabase() {
185
186        return shipmentByPartDb;
187    }
188
189    /**
190     * Return the shipment-by-supplier index.
191     */
192    public final SecondaryDatabase getShipmentBySupplierDatabase() {
193
194        return shipmentBySupplierDb;
195    }
196
197    /**
198     * Return the supplier-by-city index.
199     */
200    public final SecondaryDatabase getSupplierByCityDatabase() {
201
202        return supplierByCityDb;
203    }
204
205    /**
206     * Close all stores (closing a store automatically closes its indices).
207     */
208    public void close()
209        throws DatabaseException {
210
211        // Close secondary databases, then primary databases.
212        supplierByCityDb.close();
213        shipmentByPartDb.close();
214        shipmentBySupplierDb.close();
215        partDb.close();
216        supplierDb.close();
217        shipmentDb.close();
218        // And don't forget to close the catalog and the environment.
219        javaCatalog.close();
220        env.close();
221    }
222
223    /**
224     * The SecondaryKeyCreator for the SupplierByCity index.  This is an
225     * extension of the abstract class SerialSerialKeyCreator, which implements
226     * SecondaryKeyCreator for the case where the data keys and value are all
227     * of the serial format.
228     */
229    private static class SupplierByCityKeyCreator
230        extends SerialSerialKeyCreator {
231
232        /**
233         * Construct the city key extractor.
234         * @param catalog is the class catalog.
235         * @param primaryKeyClass is the supplier key class.
236         * @param valueClass is the supplier value class.
237         * @param indexKeyClass is the city key class.
238         */
239        private SupplierByCityKeyCreator(ClassCatalog catalog,
240                                         Class primaryKeyClass,
241                                         Class valueClass,
242                                         Class indexKeyClass) {
243
244            super(catalog, primaryKeyClass, valueClass, indexKeyClass);
245        }
246
247        /**
248         * Extract the city key from a supplier key/value pair.  The city key
249         * is stored in the supplier value, so the supplier key is not used.
250         */
251        public Object createSecondaryKey(Object primaryKeyInput,
252                                         Object valueInput) {
253
254            SupplierData supplierData = (SupplierData) valueInput;
255            return supplierData.getCity();
256        }
257    }
258
259    /**
260     * The SecondaryKeyCreator for the ShipmentByPart index.  This is an
261     * extension of the abstract class SerialSerialKeyCreator, which implements
262     * SecondaryKeyCreator for the case where the data keys and value are all
263     * of the serial format.
264     */
265    private static class ShipmentByPartKeyCreator
266        extends SerialSerialKeyCreator {
267
268        /**
269         * Construct the part key extractor.
270         * @param catalog is the class catalog.
271         * @param primaryKeyClass is the shipment key class.
272         * @param valueClass is the shipment value class.
273         * @param indexKeyClass is the part key class.
274         */
275        private ShipmentByPartKeyCreator(ClassCatalog catalog,
276                                         Class primaryKeyClass,
277                                         Class valueClass,
278                                         Class indexKeyClass) {
279
280            super(catalog, primaryKeyClass, valueClass, indexKeyClass);
281        }
282
283        /**
284         * Extract the part key from a shipment key/value pair.  The part key
285         * is stored in the shipment key, so the shipment value is not used.
286         */
287        public Object createSecondaryKey(Object primaryKeyInput,
288                                         Object valueInput) {
289
290            ShipmentKey shipmentKey = (ShipmentKey) primaryKeyInput;
291            return new PartKey(shipmentKey.getPartNumber());
292        }
293    }
294
295    /**
296     * The SecondaryKeyCreator for the ShipmentBySupplier index.  This is an
297     * extension of the abstract class SerialSerialKeyCreator, which implements
298     * SecondaryKeyCreator for the case where the data keys and value are all
299     * of the serial format.
300     */
301    private static class ShipmentBySupplierKeyCreator
302        extends SerialSerialKeyCreator {
303
304        /**
305         * Construct the supplier key extractor.
306         * @param catalog is the class catalog.
307         * @param primaryKeyClass is the shipment key class.
308         * @param valueClass is the shipment value class.
309         * @param indexKeyClass is the supplier key class.
310         */
311        private ShipmentBySupplierKeyCreator(ClassCatalog catalog,
312                                             Class primaryKeyClass,
313                                             Class valueClass,
314                                             Class indexKeyClass) {
315
316            super(catalog, primaryKeyClass, valueClass, indexKeyClass);
317        }
318
319        /**
320         * Extract the supplier key from a shipment key/value pair.  The part
321         * key is stored in the shipment key, so the shipment value is not
322         * used.
323         */
324        public Object createSecondaryKey(Object primaryKeyInput,
325                                         Object valueInput) {
326
327            ShipmentKey shipmentKey = (ShipmentKey) primaryKeyInput;
328            return new SupplierKey(shipmentKey.getSupplierNumber());
329        }
330    }
331}
332