1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002-2009 Oracle. All rights reserved. 5 * 6 * $Id$ 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