001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: EntityStore.java,v 1.28.2.3 2008/01/07 15:14:18 cwl Exp $
007: */
008:
009: package com.sleepycat.persist;
010:
011: import java.util.Set;
012:
013: import com.sleepycat.je.Database; // for javadoc
014: import com.sleepycat.je.DatabaseConfig;
015: import com.sleepycat.je.DatabaseException;
016: import com.sleepycat.je.Environment;
017: import com.sleepycat.je.SecondaryConfig;
018: import com.sleepycat.je.Sequence;
019: import com.sleepycat.je.SequenceConfig;
020: import com.sleepycat.je.Transaction;
021: import com.sleepycat.persist.evolve.EvolveConfig;
022: import com.sleepycat.persist.evolve.EvolveStats;
023: import com.sleepycat.persist.evolve.IncompatibleClassException;
024: import com.sleepycat.persist.evolve.Mutations;
025: import com.sleepycat.persist.impl.Store;
026: import com.sleepycat.persist.model.DeleteAction;
027: import com.sleepycat.persist.model.Entity; // for javadoc
028: import com.sleepycat.persist.model.EntityModel;
029: import com.sleepycat.persist.model.PrimaryKey;
030: import com.sleepycat.persist.model.SecondaryKey;
031:
032: /**
033: * A store for managing persistent entity objects.
034: *
035: * <p>{@code EntityStore} objects are thread-safe. Multiple threads may safely
036: * call the methods of a shared {@code EntityStore} object.</p>
037: *
038: * <p>See the {@link <a href="package-summary.html#example">package
039: * summary example</a>} for an example of using an {@code EntityStore}.</p>
040: *
041: * <p>Before creating an <code>EntityStore</code> you must create an {@link
042: * Environment} object using the Berkeley DB engine API. The environment may
043: * contain any number of entity stores and their associated databases, as well
044: * as other databases not associated with an entity store.</p>
045: *
046: * <p>An entity store is based on an {@link EntityModel}: a data model which
047: * defines persistent classes (<em>entity classes</em>), primary keys,
048: * secondary keys, and relationships between entities. A primary index is
049: * created for each entity class. An associated secondary index is created for
050: * each secondary key. The {@link Entity}, {@link PrimaryKey} and {@link
051: * SecondaryKey} annotations may be used to define entities and keys.</p>
052: *
053: * <p>To use an <code>EntityStore</code>, first obtain {@link PrimaryIndex} and
054: * {@link SecondaryIndex} objects by calling {@link #getPrimaryIndex
055: * getPrimaryIndex} and {@link #getSecondaryIndex getSecondaryIndex}. Then use
056: * these indices to store and access entity records by key.</p>
057: *
058: * <p>Although not normally needed, you can also use the entity store along
059: * with the {@link com.sleepycat.je Base API}. Methods in the {@link
060: * PrimaryIndex} and {@link SecondaryIndex} classes may be used to obtain
061: * databases and bindings. The databases may be used directly for accessing
062: * entity records. The bindings should be called explicitly to translate
063: * between {@link com.sleepycat.je.DatabaseEntry} objects and entity model
064: * objects.</p>
065: *
066: * <p>Each primary and secondary index is associated internally with a {@link
067: * Database}. With any of the above mentioned use cases, methods are provided
068: * that may be used for database performance tuning. The {@link
069: * #setPrimaryConfig setPrimaryConfig} and {@link #setSecondaryConfig
070: * setSecondaryConfig} methods may be called anytime before a database is
071: * opened via {@link #getPrimaryIndex getPrimaryIndex} or {@link
072: * #getSecondaryIndex getSecondaryIndex}. The {@link #setSequenceConfig
073: * setSequenceConfig} method may be called anytime before {@link #getSequence
074: * getSequence} is called or {@link #getPrimaryIndex getPrimaryIndex} is called
075: * for a primary index associated with that sequence.</p>
076: *
077: * <h3>Database Names</h3>
078: *
079: * <p>The database names of primary and secondary indices are designed to be
080: * unique within the environment and identifiable for debugging and use with
081: * tools such as {@link com.sleepycat.je.util.DbDump} and {@link
082: * com.sleepycat.je.util.DbLoad}.</p>
083: *
084: * <p>The syntax of a primary index database name is:</p>
085: * <pre> persist#STORE_NAME#ENTITY_CLASS</pre>
086: * <p>Where STORE_NAME is the name parameter passed to {@link #EntityStore
087: * EntityStore} and ENTITY_CLASS is name of the class passed to {@link
088: * #getPrimaryIndex getPrimaryIndex}.</p>
089: *
090: * <p>The syntax of a secondary index database name is:</p>
091: * <pre> persist#STORE_NAME#ENTITY_CLASS#KEY_NAME</pre>
092: * <p>Where KEY_NAME is the secondary key name passed to {@link
093: * #getSecondaryIndex getSecondaryIndex}.</p>
094: *
095: * <p>Although you should never have to construct these names manually,
096: * understanding their syntax is useful for several reasons:</p>
097: * <ul>
098: * <li>Exception messages sometimes contain the database name, from which you
099: * can identify the entity class and secondary key.</li>
100: * <li>If you create other databases in the same environment that are not
101: * part of an <code>EntityStore</code>, to avoid naming conflicts the other
102: * database names should not begin with <code>"persist#"</code>.</li>
103: * <li>If you are using {@link com.sleepycat.je.util.DbDump} or {@link
104: * com.sleepycat.je.util.DbLoad} to perform a backup or copy databases between
105: * environments, knowing the database names can be useful. Normally you will
106: * dump or load all database names starting with
107: * <code>"persist#STORE_NAME#"</code>.</li>
108: * </ul>
109: *
110: * <p>If you are copying all databases in a store as mentioned in the last
111: * point above, there is one further consideration. There are two internal
112: * databases that must be kept with the other databases in the store in order
113: * for the store to be used. These contain the data formats and sequences for
114: * the store:</p>
115: * <pre> persist#STORE_NAME#com.sleepycat.persist.formats</pre>
116: * <pre> persist#STORE_NAME#com.sleepycat.persist.sequences</pre>
117: * <p>These databases should normally be included with copies of other
118: * databases in the store. They should not be modified by the application.</p>
119: *
120: * @author Mark Hayes
121: */
122: public class EntityStore {
123:
124: private Store store;
125:
126: /**
127: * Opens an entity store in a given environment.
128: *
129: * @param env an open Berkeley DB Environment.
130: *
131: * @param storeName the name of the entity store within the given
132: * environment. An empty string is allowed. Named stores may be used to
133: * distinguish multiple sets of persistent entities for the same entity
134: * classes in a single environment. Underlying database names are prefixed
135: * with the store name.
136: *
137: * @param config the entity store configuration, or null to use default
138: * configuration properties.
139: *
140: * @throws IncompatibleClassException if an incompatible class change has
141: * been made and mutations are not configured for handling the change. See
142: * {@link com.sleepycat.persist.evolve Class Evolution} for more
143: * information.
144: */
145: public EntityStore(Environment env, String storeName,
146: StoreConfig config) throws DatabaseException,
147: IncompatibleClassException {
148:
149: store = new Store(env, storeName, config, false /*rawAccess*/);
150: }
151:
152: /**
153: * Only public for debugging.
154: */
155: void dumpCatalog() {
156: store.dumpCatalog();
157: }
158:
159: /**
160: * Returns the environment associated with this store.
161: *
162: * @return the environment.
163: */
164: public Environment getEnvironment() {
165: return store.getEnvironment();
166: }
167:
168: /**
169: * Returns a copy of the entity store configuration.
170: *
171: * @return the config.
172: */
173: public StoreConfig getConfig() {
174: return store.getConfig();
175: }
176:
177: /**
178: * Returns the name of this store.
179: *
180: * @return the name.
181: */
182: public String getStoreName() {
183: return store.getStoreName();
184: }
185:
186: /**
187: * Returns the names of all entity stores in the given environment.
188: *
189: * @return the store names. An empty set is returned if no stores are
190: * present.
191: */
192: public static Set<String> getStoreNames(Environment env)
193: throws DatabaseException {
194:
195: return Store.getStoreNames(env);
196: }
197:
198: /**
199: * Returns the current entity model for this store. The current model is
200: * derived from the configured entity model and the live entity class
201: * definitions.
202: *
203: * @return the model.
204: */
205: public EntityModel getModel() {
206: return store.getModel();
207: }
208:
209: /**
210: * Returns the set of mutations that were configured when the store was
211: * opened, or if none were configured, the set of mutations that were
212: * configured and stored previously.
213: *
214: * @return the mutations.
215: */
216: public Mutations getMutations() {
217: return store.getMutations();
218: }
219:
220: /**
221: * Returns the primary index for a given entity class, opening it if
222: * necessary.
223: *
224: * <p>If they are not already open, the primary and secondary databases for
225: * the entity class are created/opened together in a single internal
226: * transaction. When the secondary indices are opened, that can cascade to
227: * open other related primary indices.</p>
228: *
229: * @param primaryKeyClass the class of the entity's primary key field, or
230: * the corresponding primitive wrapper class if the primary key field type
231: * is a primitive.
232: *
233: * @param entityClass the entity class for which to open the primary index.
234: *
235: * @return the primary index.
236: *
237: * @throws IllegalArgumentException if the entity class or classes
238: * referenced by it are not persistent, or the primary key class does not
239: * match the entity's primary key field, or if metadata for the entity or
240: * primary key is invalid.
241: */
242: public <PK, E> PrimaryIndex<PK, E> getPrimaryIndex(
243: Class<PK> primaryKeyClass, Class<E> entityClass)
244: throws DatabaseException {
245:
246: return store.getPrimaryIndex(primaryKeyClass, primaryKeyClass
247: .getName(), entityClass, entityClass.getName());
248: }
249:
250: /**
251: * Returns a secondary index for a given primary index and secondary key,
252: * opening it if necessary.
253: *
254: * <p><em>NOTE:</em> If the secondary key field is declared in a subclass
255: * of the entity class, use {@link #getSubclassIndex} instead.</p>
256: *
257: * <p>If a {@link SecondaryKey#relatedEntity} is used and the primary index
258: * for the related entity is not already open, it will be opened by this
259: * method. That will, in turn, open its secondary indices, which can
260: * casade to open other primary indices.</p>
261: *
262: * @param primaryIndex the primary index associated with the returned
263: * secondary index. The entity class of the primary index, or one of its
264: * superclasses, must contain a secondary key with the given secondary key
265: * class and key name.
266: *
267: * @param keyClass the class of the secondary key field, or the
268: * corresponding primitive wrapper class if the secondary key field type is
269: * a primitive.
270: *
271: * @param keyName the name of the secondary key field, or the {@link
272: * SecondaryKey#name} if this name annotation property was specified.
273: *
274: * @return the secondary index.
275: *
276: * @throws IllegalArgumentException if the entity class or one of its
277: * superclasses does not contain a key field of the given key class and key
278: * name, or if the metadata for the secondary key is invalid.
279: */
280: public <SK, PK, E> SecondaryIndex<SK, PK, E> getSecondaryIndex(
281: PrimaryIndex<PK, E> primaryIndex, Class<SK> keyClass,
282: String keyName) throws DatabaseException {
283:
284: return store.getSecondaryIndex(primaryIndex, primaryIndex
285: .getEntityClass(), primaryIndex.getEntityClass()
286: .getName(), keyClass, keyClass.getName(), keyName);
287: }
288:
289: /**
290: * Returns a secondary index for a secondary key in an entity subclass,
291: * opening it if necessary.
292: *
293: * <p>If a {@link SecondaryKey#relatedEntity} is used and the primary index
294: * for the related entity is not already open, it will be opened by this
295: * method. That will, in turn, open its secondary indices, which can
296: * casade to open other primary indices.</p>
297: *
298: * @param primaryIndex the primary index associated with the returned
299: * secondary index. The entity class of the primary index, or one of its
300: * superclasses, must contain a secondary key with the given secondary key
301: * class and key name.
302: *
303: * @param entitySubclass a subclass of the entity class for the primary
304: * index. The entity subclass must contain a secondary key with the given
305: * secondary key class and key name.
306: *
307: * @param keyClass the class of the secondary key field, or the
308: * corresponding primitive wrapper class if the secondary key field type is
309: * a primitive.
310: *
311: * @param keyName the name of the secondary key field, or the {@link
312: * SecondaryKey#name} if this name annotation property was specified.
313: *
314: * @return the secondary index.
315: *
316: * @throws IllegalArgumentException if the given entity subclass does not
317: * contain a key field of the given key class and key name, or if the
318: * metadata for the secondary key is invalid.
319: */
320: public <SK, PK, E1, E2 extends E1> SecondaryIndex<SK, PK, E2> getSubclassIndex(
321: PrimaryIndex<PK, E1> primaryIndex,
322: Class<E2> entitySubclass, Class<SK> keyClass, String keyName)
323: throws DatabaseException {
324:
325: /* Make subclass metadata available before getting the index. */
326: getModel().getClassMetadata(entitySubclass.getName());
327:
328: return store.getSecondaryIndex(primaryIndex, entitySubclass,
329: primaryIndex.getEntityClass().getName(), keyClass,
330: keyClass.getName(), keyName);
331: }
332:
333: /**
334: * Performs conversion of unevolved objects in order to reduce lazy
335: * conversion overhead. Evolution may be performed concurrently with
336: * normal access to the store.
337: *
338: * <p>Conversion is performed one entity class at a time. An entity class
339: * is converted only if it has {@link Mutations} associated with it via
340: * {@link StoreConfig#setMutations StoreConfig.setMutations}.</p>
341: *
342: * <p>Conversion of an entity class is performed by reading each entity,
343: * converting it if necessary, and updating it if conversion was performed.
344: * When all instances of an entity class are converted, references to the
345: * appropriate {@link Mutations} are deleted. Therefore, if this method is
346: * called twice successfully without changing class definitions, the second
347: * call will do nothing.</p>
348: *
349: * @see com.sleepycat.persist.evolve Class Evolution
350: */
351: public EvolveStats evolve(EvolveConfig config)
352: throws DatabaseException {
353:
354: return store.evolve(config);
355: }
356:
357: /**
358: * Deletes all instances of this entity class and its (non-entity)
359: * subclasses.
360: *
361: * <p>This is the equivalent of {@link Environment#truncateDatabase
362: * Environment.truncateDatabase}. The primary and secondary databases
363: * associated with the entity class must not be open except by this store,
364: * since database truncation is only possible when the database is not
365: * open. The databases to be truncated will be closed before performing
366: * this operation, if they were previously opened by this store.</p>
367: *
368: * <p>Auto-commit is used implicitly if the store is transactional.</p>
369: *
370: * @param entityClass the entity class whose instances are to be deleted.
371: */
372: public void truncateClass(Class entityClass)
373: throws DatabaseException {
374:
375: store.truncateClass(null, entityClass);
376: }
377:
378: /**
379: * Deletes all instances of this entity class and its (non-entity)
380: * subclasses.
381: *
382: * <p>This is the equivalent of {@link Environment#truncateDatabase
383: * Environment.truncateDatabase}. The primary and secondary databases
384: * associated with the entity class must not be open except by this store,
385: * since database truncation is only possible when the database is not
386: * open. The databases to be truncated will be closed before performing
387: * this operation, if they were previously opened by this store.</p>
388: *
389: * @param txn the transaction used to protect this operation, null to use
390: * auto-commit, or null if the store is non-transactional.
391: *
392: * @param entityClass the entity class whose instances are to be deleted.
393: */
394: public void truncateClass(Transaction txn, Class entityClass)
395: throws DatabaseException {
396:
397: store.truncateClass(txn, entityClass);
398: }
399:
400: /**
401: * Flushes each modified index to disk that was opened in deferred-write
402: * mode.
403: *
404: * <p>All indexes are opened in deferred-write mode if true was passed to
405: * {@link StoreConfig#setDeferredWrite} for the store.</p>
406: *
407: * <p>Alternatively, individual databases may be configured for deferred
408: * write using {@link DatabaseConfig#setDeferredWrite} along with {@link
409: * #getPrimaryConfig} and {@link #setPrimaryConfig}. Caution should be used
410: * when configuring only some databases for deferred-write, since durability
411: * will be different for these databases than for other databases in the
412: * same store.</p>
413: *
414: * <p>This method is functionally equivalent to calling {@link
415: * Database#sync} for each deferred-write index Database that is open for
416: * this store. However, while {@link Database#sync} flushes the log to disk
417: * each time it is called, this method flushes the log only once after
418: * syncing all databases; this method therefore causes less I/O than calling
419: * {@link Database#sync} multiple times.</p>
420: *
421: * <p>Instead of calling this method, {@link Environment#sync} may be used.
422: * The difference is that this method will only flush the databases for this
423: * store, while {@link Environment#sync} will sync all deferred-write
424: * databases currently open for the environment and will also perform a full
425: * checkpoint. This method is therefore less expensive than a full sync of
426: * the environment.</p>
427: */
428: public void sync() throws DatabaseException {
429:
430: store.sync();
431: }
432:
433: /**
434: * Closes the primary and secondary databases for the given entity class
435: * that were opened via this store. The caller must ensure that the
436: * primary and secondary indices obtained from this store are no longer in
437: * use.
438: *
439: * @param entityClass the entity class whose databases are to be closed.
440: */
441: public void closeClass(Class entityClass) throws DatabaseException {
442:
443: store.closeClass(entityClass);
444: }
445:
446: /**
447: * Closes all databases and sequences that were opened via this store. The
448: * caller must ensure that no databases opened via this store are in use.
449: */
450: public void close() throws DatabaseException {
451:
452: store.close();
453: }
454:
455: /**
456: * Returns a named sequence for using Berkeley DB engine API directly,
457: * opening it if necessary.
458: *
459: * @param name the sequence name, which is normally defined using the
460: * {@link PrimaryKey#sequence} annotation property.
461: *
462: * @return the open sequence for the given sequence name.
463: */
464: public Sequence getSequence(String name) throws DatabaseException {
465:
466: return store.getSequence(name);
467: }
468:
469: /**
470: * Returns the default Berkeley DB engine API configuration for a named key
471: * sequence.
472: *
473: * </p>The returned configuration is as follows. All other properties have
474: * default values.</p>
475: * <ul>
476: * <li>The {@link SequenceConfig#setInitialValue InitialValue} is one.</li>
477: * <li>The {@link SequenceConfig#setRange Range} minimum is one.</li>
478: * <li>The {@link SequenceConfig#setCacheSize CacheSize} is 100.</li>
479: * <li>{@link SequenceConfig#setAutoCommitNoSync AutoCommitNoSync} is
480: * true.</li>
481: * <li>{@link SequenceConfig#setAllowCreate AllowCreate} is set to true
482: * if the store is not {@link StoreConfig#setReadOnly ReadOnly}.</li>
483: * </ul>
484: *
485: * @param name the sequence name, which is normally defined using the
486: * {@link PrimaryKey#sequence} annotation property.
487: *
488: * @return the default configuration for the given sequence name.
489: */
490: public SequenceConfig getSequenceConfig(String name) {
491: return store.getSequenceConfig(name);
492: }
493:
494: /**
495: * Configures a named key sequence using the Berkeley DB engine API.
496: *
497: * <p>To be compatible with the entity model and the Direct Persistence
498: * Layer, the configuration should be retrieved using {@link
499: * #getSequenceConfig getSequenceConfig}, modified, and then passed to this
500: * method.</p>
501: *
502: * <p>If the range is changed to include the value zero, see {@link
503: * PrimaryKey} for restrictions.</p>
504: *
505: * @param name the sequence name, which is normally defined using the
506: * {@link PrimaryKey#sequence} annotation property.
507: *
508: * @param config the configuration to use for the given sequence name.
509: *
510: * @throws IllegalArgumentException if the configuration is incompatible
511: * with the entity model or the Direct Persistence Layer.
512: *
513: * @throws IllegalStateException if the sequence has already been opened.
514: */
515: public void setSequenceConfig(String name, SequenceConfig config) {
516: store.setSequenceConfig(name, config);
517: }
518:
519: /**
520: * Returns the default primary database Berkeley DB engine API
521: * configuration for an entity class.
522: *
523: * </p>The returned configuration is as follows. All other properties have
524: * default values.</p>
525: * <ul>
526: * <li>{@link DatabaseConfig#setTransactional Transactional} is set to
527: * match {@link StoreConfig#setTransactional StoreConfig}.</li>
528: * <li>{@link DatabaseConfig#setAllowCreate AllowCreate} is set to true
529: * if the store is not {@link StoreConfig#setReadOnly ReadOnly}.</li>
530: * <li>{@link DatabaseConfig#setReadOnly ReadOnly} is set to match
531: * {@link StoreConfig#setReadOnly StoreConfig}.</li>
532: * <li>{@link DatabaseConfig#setDeferredWrite DeferredWrite} is set to
533: * match {@link StoreConfig#setDeferredWrite StoreConfig}.</li>
534: * <li>{@link DatabaseConfig#setBtreeComparator BtreeComparator} is set to
535: * an internal class if a key comparator is used.</li>
536: * </ul>
537: *
538: * @param entityClass the entity class identifying the primary database.
539: *
540: * @return the default configuration for the given entity class.
541: */
542: public DatabaseConfig getPrimaryConfig(Class entityClass) {
543: return store.getPrimaryConfig(entityClass);
544: }
545:
546: /**
547: * Configures the primary database for an entity class using the Berkeley
548: * DB engine API.
549: *
550: * <p>To be compatible with the entity model and the Direct Persistence
551: * Layer, the configuration should be retrieved using {@link
552: * #getPrimaryConfig getPrimaryConfig}, modified, and then passed to this
553: * method. The following configuration properties may not be changed:</p>
554: * <ul>
555: * <li>{@link DatabaseConfig#setSortedDuplicates SortedDuplicates}</li>
556: * <li>{@link DatabaseConfig#setBtreeComparator BtreeComparator}</li>
557: * </ul>
558: *
559: * @param entityClass the entity class identifying the primary database.
560: *
561: * @param config the configuration to use for the given entity class.
562: *
563: * @throws IllegalArgumentException if the configuration is incompatible
564: * with the entity model or the Direct Persistence Layer.
565: *
566: * @throws IllegalStateException if the database has already been opened.
567: */
568: public void setPrimaryConfig(Class entityClass,
569: DatabaseConfig config) {
570: store.setPrimaryConfig(entityClass, config);
571: }
572:
573: /**
574: * Returns the default secondary database Berkeley DB engine API
575: * configuration for an entity class and key name.
576: *
577: * </p>The returned configuration is as follows. All other properties have
578: * default values.</p>
579: * <ul>
580: * <li>{@link DatabaseConfig#setTransactional Transactional} is set to
581: * match the primary database.</li>
582: * <li>{@link DatabaseConfig#setAllowCreate AllowCreate} is set to true
583: * if the primary database is not {@link StoreConfig#setReadOnly
584: * ReadOnly}.</li>
585: * <li>{@link DatabaseConfig#setReadOnly ReadOnly} is set to match
586: * the primary database.</li>
587: * <li>{@link DatabaseConfig#setDeferredWrite DeferredWrite} is set to
588: * match the primary database.</li>
589: * <li>{@link DatabaseConfig#setBtreeComparator BtreeComparator} is set to
590: * an internal class if a key comparator is used.</li>
591: * <li>{@link DatabaseConfig#setSortedDuplicates SortedDuplicates} is set
592: * according to {@link SecondaryKey#relate}.</p>
593: * <li>{@link SecondaryConfig#setAllowPopulate AllowPopulate} is set to
594: * true when a secondary key is added to an existing primary index.</li>
595: * <li>{@link SecondaryConfig#setKeyCreator KeyCreator} or {@link
596: * SecondaryConfig#setMultiKeyCreator MultiKeyCreator} is set to an
597: * internal instance.</p>
598: * <li>{@link SecondaryConfig#setForeignMultiKeyNullifier
599: * ForeignMultiKeyNullifier} is set to an internal instance if {@link
600: * SecondaryKey#onRelatedEntityDelete} is {@link DeleteAction#NULLIFY}.</li>
601: * </ul>
602: *
603: * @param entityClass the entity class containing the given secondary key
604: * name.
605: *
606: * @param keyName the name of the secondary key field, or the {@link
607: * SecondaryKey#name} if this name annotation property was specified.
608: *
609: * @return the default configuration for the given secondary key.
610: */
611: public SecondaryConfig getSecondaryConfig(Class entityClass,
612: String keyName) {
613: return store.getSecondaryConfig(entityClass, keyName);
614: }
615:
616: /**
617: * Configures a secondary database for an entity class and key name using
618: * the Berkeley DB engine API.
619: *
620: * <p>To be compatible with the entity model and the Direct Persistence
621: * Layer, the configuration should be retrieved using {@link
622: * #getSecondaryConfig getSecondaryConfig}, modified, and then passed to
623: * this method. The following configuration properties may not be
624: * changed:</p>
625: * <ul>
626: * <li>{@link DatabaseConfig#setSortedDuplicates SortedDuplicates}</li>
627: * <li>{@link DatabaseConfig#setBtreeComparator BtreeComparator}</li>
628: * <li>{@link DatabaseConfig#setDuplicateComparator
629: * DuplicateComparator}</li>
630: * <li>{@link SecondaryConfig#setAllowPopulate AllowPopulate}</li>
631: * <li>{@link SecondaryConfig#setKeyCreator KeyCreator}</li>
632: * <li>{@link SecondaryConfig#setMultiKeyCreator MultiKeyCreator}</li>
633: * <li>{@link SecondaryConfig#setForeignKeyNullifier
634: * ForeignKeyNullifier}</li>
635: * <li>{@link SecondaryConfig#setForeignMultiKeyNullifier
636: * ForeignMultiKeyNullifier}</li>
637: * <li>{@link SecondaryConfig#setForeignKeyDeleteAction
638: * ForeignKeyDeleteAction}</li>
639: * <li>{@link SecondaryConfig#setForeignKeyDatabase
640: * ForeignKeyDatabase}</li>
641: * </ul>
642: *
643: * @param entityClass the entity class containing the given secondary key
644: * name.
645: *
646: * @param keyName the name of the secondary key field, or the {@link
647: * SecondaryKey#name} if this name annotation property was specified.
648: *
649: * @param config the configuration to use for the given secondary key.
650: *
651: * @throws IllegalArgumentException if the configuration is incompatible
652: * with the entity model or the Direct Persistence Layer.
653: *
654: * @throws IllegalStateException if the database has already been opened.
655: */
656: public void setSecondaryConfig(Class entityClass, String keyName,
657: SecondaryConfig config) {
658: store.setSecondaryConfig(entityClass, keyName, config);
659: }
660: }
|