/** * Opens any secondary indexes defined in the given entity metadata that are not already open. * This method is called when a new entity subclass is encountered when an instance of that class * is stored, and the EntityStore.getSubclassIndex has not been previously called for that class. * [#15247] */ synchronized void openSecondaryIndexes( Transaction txn, EntityMetadata entityMeta, PrimaryOpenState priOpenState) throws DatabaseException { String entityClassName = entityMeta.getClassName(); PrimaryIndex<Object, Object> priIndex = priIndexMap.get(entityClassName); assert priIndex != null; Class<Object> entityClass = priIndex.getEntityClass(); for (SecondaryKeyMetadata secKeyMeta : entityMeta.getSecondaryKeys().values()) { String keyName = secKeyMeta.getKeyName(); String secName = makeSecName(entityClassName, keyName); SecondaryIndex<Object, Object, Object> secIndex = secIndexMap.get(secName); if (secIndex == null) { String keyClassName = getSecKeyClass(secKeyMeta); /* RawMode: should not require class. */ Class keyClass = SimpleCatalog.keyClassForName(keyClassName); openSecondaryIndex( txn, priIndex, entityClass, entityMeta, keyClass, keyClassName, secKeyMeta, makeSecName(entityClassName, secKeyMeta.getKeyName()), storeConfig.getSecondaryBulkLoad() /*doNotCreate*/, priOpenState); } } }
/** * Creates a secondary index without using an <code>EntityStore</code>. When using an {@link * EntityStore}, call {@link EntityStore#getSecondaryIndex getSecondaryIndex} instead. * * <p>This constructor is not normally needed and is provided for applications that wish to use * custom bindings along with the Direct Persistence Layer. Normally, {@link * EntityStore#getSecondaryIndex getSecondaryIndex} is used instead. * * @param database the secondary database used for all access other than via a {@link #keysIndex}. * @param keysDatabase another handle on the secondary database, opened without association to the * primary, and used only for access via a {@link #keysIndex}. If this argument is null and * the {@link #keysIndex} method is called, then the keys database will be opened * automatically; however, the user is then responsible for closing the keys database. To get * the keys database in order to close it, call {@link #getKeysDatabase}. * @param primaryIndex the primary index associated with this secondary index. * @param secondaryKeyClass the class of the secondary key. * @param secondaryKeyBinding the binding to be used for secondary keys. */ public SecondaryIndex( SecondaryDatabase database, Database keysDatabase, PrimaryIndex<PK, E> primaryIndex, Class<SK> secondaryKeyClass, EntryBinding secondaryKeyBinding) throws DatabaseException { super( database, secondaryKeyClass, secondaryKeyBinding, new EntityValueAdapter( primaryIndex.getEntityClass(), primaryIndex.getEntityBinding(), true)); secDb = database; keysDb = keysDatabase; priIndex = primaryIndex; entityBinding = primaryIndex.getEntityBinding(); }
/** * A getSecondaryIndex with extra parameters for opening a raw store. keyClassName is used for * consistency checking and should be null for a raw store only. */ public synchronized <SK, PK, E1, E2 extends E1> SecondaryIndex<SK, PK, E2> getSecondaryIndex( PrimaryIndex<PK, E1> primaryIndex, Class<E2> entityClass, String entityClassName, Class<SK> keyClass, String keyClassName, String keyName) throws DatabaseException { assert (rawAccess && keyClassName == null) || (!rawAccess && keyClassName != null); checkOpen(); EntityMetadata entityMeta = null; SecondaryKeyMetadata secKeyMeta = null; /* Validate the subclass for a subclass index. */ if (entityClass != primaryIndex.getEntityClass()) { entityMeta = model.getEntityMetadata(entityClassName); assert entityMeta != null; secKeyMeta = checkSecKey(entityMeta, keyName); String subclassName = entityClass.getName(); String declaringClassName = secKeyMeta.getDeclaringClassName(); if (!subclassName.equals(declaringClassName)) { throw new IllegalArgumentException( "Key for subclass " + subclassName + " is declared in a different class: " + makeSecName(declaringClassName, keyName)); } } /* * Even though the primary is already open, we can't assume the * secondary is open because we don't automatically open all * secondaries when the primary is read-only. Use auto-commit (a null * transaction) since we're opening only one database. */ String secName = makeSecName(entityClassName, keyName); SecondaryIndex<SK, PK, E2> secIndex = secIndexMap.get(secName); if (secIndex == null) { if (entityMeta == null) { entityMeta = model.getEntityMetadata(entityClassName); assert entityMeta != null; } if (secKeyMeta == null) { secKeyMeta = checkSecKey(entityMeta, keyName); } /* Check metadata. */ if (keyClassName == null) { keyClassName = getSecKeyClass(secKeyMeta); } else { String expectClsName = getSecKeyClass(secKeyMeta); if (!keyClassName.equals(expectClsName)) { throw new IllegalArgumentException( "Wrong secondary key class: " + keyClassName + " Correct class is: " + expectClsName); } } secIndex = openSecondaryIndex( null, primaryIndex, entityClass, entityMeta, keyClass, keyClassName, secKeyMeta, secName, false /*doNotCreate*/, null /*priOpenState*/); } return secIndex; }