diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfiguration.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfiguration.java index 931af86c5..ef067e405 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfiguration.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfiguration.java @@ -628,5 +628,25 @@ public interface JDBCConfiguration * @param util instance of the identifier utility */ public void setIdentifierUtil(DBIdentifierUtil util); + + /** + * Affirms if select statements are aggressively cached. + * An aggressive select cache assumes that {@link FetchConfiguration fetch plan} + * does not change between execution. + * + * @return false by default. + * + * @since 2.2.0 + */ + public boolean getSelectCacheEnabled(); + + /** + * Sets if select statements are aggressively cached. + * An aggressive select cache assumes that {@link FetchConfiguration fetch plan} + * does not change between execution. + * + * @since 2.2.0 + */ + public void setSelectCacheEnabled(boolean enable); } diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfigurationImpl.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfigurationImpl.java index f511705cb..1a6c68078 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfigurationImpl.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/conf/JDBCConfigurationImpl.java @@ -43,6 +43,8 @@ import org.apache.openjpa.jdbc.sql.MaxDBDictionary; import org.apache.openjpa.jdbc.sql.SQLFactory; import org.apache.openjpa.kernel.BrokerImpl; import org.apache.openjpa.kernel.StoreContext; +import org.apache.openjpa.lib.conf.BooleanValue; +import org.apache.openjpa.lib.conf.ImmutableBooleanValue; import org.apache.openjpa.lib.conf.IntValue; import org.apache.openjpa.lib.conf.ObjectValue; import org.apache.openjpa.lib.conf.PluginValue; @@ -87,6 +89,7 @@ public class JDBCConfigurationImpl public PluginValue driverDataSourcePlugin; public MappingFactoryValue mappingFactoryPlugin; public ObjectValue identifierUtilPlugin; + public ImmutableBooleanValue cacheSelect; // used internally private String firstUser = null; @@ -350,6 +353,9 @@ public class JDBCConfigurationImpl identifierUtilPlugin.setString(aliases[0]); identifierUtilPlugin.setInstantiatingGetter("getIdentifierUtilInstance"); + cacheSelect = new ImmutableBooleanValue("jdbc.CachesSelect"); + addValue(cacheSelect); + cacheSelect.setDefault("false"); // this static initializer is to get past a weird // ClassCircularityError that happens only under IBM's @@ -996,5 +1002,13 @@ public class JDBCConfigurationImpl public void setIdentifierUtil(DBIdentifierUtil util) { identifierUtilPlugin.set(util); } + + public boolean getSelectCacheEnabled() { + return cacheSelect.get(); + } + public void setSelectCacheEnabled(boolean enable) { + cacheSelect.set(enable); + } + } diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java index 75ed1a8e0..e4f230980 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java @@ -260,9 +260,9 @@ public class JDBCStoreManager implements StoreManager, JDBCStore { private boolean exists(ClassMapping mapping, Object oid, Object context) { // add where conditions on base class to avoid joins if subclass // doesn't use oid as identifier - Select sel = _sql.newSelect(); while (mapping.getJoinablePCSuperclassMapping() != null) mapping = mapping.getJoinablePCSuperclassMapping(); + Select sel = mapping.getSelect(); sel.wherePrimaryKey(oid, mapping, this); if (_log.isTraceEnabled()) { @@ -301,8 +301,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore { FetchConfiguration fetch, Object context) { ConnectionInfo info = (ConnectionInfo) context; try { - return initializeState(sm, state, (JDBCFetchConfiguration) fetch, - info); + return initializeState(sm, state, (JDBCFetchConfiguration) fetch, info); } catch (ClassNotFoundException cnfe) { throw new UserException(cnfe); } catch (SQLException se) { @@ -332,27 +331,24 @@ public class JDBCStoreManager implements StoreManager, JDBCStore { Boolean custom = customLoad(sm, mapping, state, fetch); if (custom != null) return custom.booleanValue(); - res = getInitializeStateResult(sm, mapping, fetch, - Select.SUBS_EXACT); + res = getInitializeStateResult(sm, mapping, fetch, Select.SUBS_EXACT); if (res == null && !selectPrimaryKey(sm, mapping, fetch)) return false; if (isEmptyResult(res)) return false; } else { - ClassMapping[] mappings = mapping. - getIndependentAssignableMappings(); + ClassMapping[] mappings = mapping.getIndependentAssignableMappings(); if (mappings.length == 1) { mapping = mappings[0]; Boolean custom = customLoad(sm, mapping, state, fetch); if (custom != null) return custom.booleanValue(); - res = getInitializeStateResult(sm, mapping, fetch, - Select.SUBS_ANY_JOINABLE); + res = getInitializeStateResult(sm, mapping, fetch, Select.SUBS_ANY_JOINABLE); if (res == null && !selectPrimaryKey(sm, mapping, fetch)) return false; - } else - res = getInitializeStateUnionResult(sm, mapping, mappings, - fetch); + } else { + res = getInitializeStateUnionResult(sm, mapping, mappings, fetch); + } if (isEmptyResult(res)) return false; } @@ -365,8 +361,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore { mapping = res.getBaseMapping(); res.startDataRequest(mapping.getDiscriminator()); try { - type = mapping.getDiscriminator().getClass(this, mapping, - res); + type = mapping.getDiscriminator().getClass(this, mapping, res); } finally { res.endDataRequest(); } @@ -378,19 +373,15 @@ public class JDBCStoreManager implements StoreManager, JDBCStore { sm.initialize(type, state); if (info != null && info.result != null) { - FieldMapping mappedByFieldMapping = info.result. - getMappedByFieldMapping(); + FieldMapping mappedByFieldMapping = info.result.getMappedByFieldMapping(); Object mappedByObject = info.result.getMappedByValue(); if (mappedByFieldMapping != null && mappedByObject != null) if (mappedByObject instanceof OpenJPAId && mapping.getExtraFieldDataIndex(mappedByFieldMapping.getIndex()) != -1) { - // The inverse relation can not be set since - // we are eagerly loading this sm for - // a sm owner that is still in the process of - // initializing itself. + // The inverse relation can not be set since we are eagerly loading this sm for + // an owner that is still in the process of initializing itself. // Remember owner oid by setIntermediate(). - // The inverse relation is set later by - // setInverseRelation() when the sm owner is fully + // The inverse relation is set later by setInverseRelation() when the owner is fully // initialized. int index = mappedByFieldMapping.getIndex(); if (sm.getLoaded().get(index)) { @@ -535,7 +526,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore { FinderQueryImpl fq = getFinder(mapping, fetch); if (fq != null) return fq.execute(sm, this, fetch); - Select sel = _sql.newSelect(); + Select sel = mapping.getSelect(); if (!select(sel, mapping, subs, sm, null, fetch, JDBCFetchConfiguration.EAGER_JOIN, true, false)) return null; @@ -563,7 +554,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore { final int eager = Math.min(fetch.getEagerFetchMode(), JDBCFetchConfiguration.EAGER_JOIN); - Union union = _sql.newUnion(mappings.length); + Union union = mapping.getUnion(mappings.length); union.setExpectedResultCount(1, false); if (fetch.getSubclassFetchMode(mapping) != EagerFetchModes.EAGER_JOIN) union.abortUnion(); @@ -592,7 +583,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore { while (base.getJoinablePCSuperclassMapping() != null) base = base.getJoinablePCSuperclassMapping(); - Select sel = _sql.newSelect(); + Select sel = mapping.getSelect(); sel.select(base.getPrimaryKeyColumns()); sel.wherePrimaryKey(sm.getObjectId(), base, this); if (_log.isTraceEnabled()) { @@ -645,7 +636,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore { //### use it... would it be worth it to have a small shell select //### object that only creates a real select when actually used? - Select sel = _sql.newSelect(); + Select sel = mapping.getSelect(); if (select(sel, mapping, Select.SUBS_EXACT, sm, fields, jfetch, EagerFetchModes.EAGER_JOIN, true, false)) { sel.wherePrimaryKey(sm.getObjectId(), mapping, this); @@ -818,7 +809,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore { if (rops[i] != null) continue; - Select sel = _sql.newSelect(); + Select sel = mapping.getSelect(); sel.setLRS(true); if (_log.isTraceEnabled()) { _log.trace("executeExtent: "+mappings[i].getDescribedType()); @@ -839,13 +830,12 @@ public class JDBCStoreManager implements StoreManager, JDBCStore { } // perform a union on all independent classes - Union union = _sql.newUnion(mappings.length); + Union union = mapping.getUnion(mappings.length); union.setLRS(true); final BitSet[] paged = new BitSet[mappings.length]; union.select(new Union.Selector() { public void select(Select sel, int idx) { - paged[idx] = selectExtent(sel, mappings[idx], jfetch, - subclasses); + paged[idx] = selectExtent(sel, mappings[idx], jfetch, subclasses); } }); @@ -1124,6 +1114,8 @@ public class JDBCStoreManager implements StoreManager, JDBCStore { public boolean select(Select sel, ClassMapping mapping, int subs, OpenJPAStateManager sm, BitSet fields, JDBCFetchConfiguration fetch, int eager, boolean ident, boolean outer) { + if (sel.isReadOnly()) + return true; // add class conditions so that they're cloned for any batched selects boolean joinedSupers = false; if(needClassCondition(mapping, subs, sm)) { @@ -1134,8 +1126,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore { // and cannot be reused during the actual eager select process, // preventing infinite recursion eager = Math.min(eager, fetch.getEagerFetchMode()); - FieldMapping eagerToMany = createEagerSelects(sel, mapping, sm, fields, - fetch, eager); + FieldMapping eagerToMany = createEagerSelects(sel, mapping, sm, fields, fetch, eager); // select all base class mappings; do this after batching so that // the joins needed by these selects don't get in the WHERE clause @@ -1145,10 +1136,9 @@ public class JDBCStoreManager implements StoreManager, JDBCStore { // select eager to-many relations last because during load they // advance the result set and could exhaust it, so no other mappings - // can load afterwords + // can load afterwards if (eagerToMany != null) - eagerToMany.selectEagerJoin(sel, sm, this, - fetch.traverseJDBC(eagerToMany), eager); + eagerToMany.selectEagerJoin(sel, sm, this, fetch.traverseJDBC(eagerToMany), eager); // optionally select subclass mappings if (subs == Select.SUBS_JOINABLE || subs == Select.SUBS_ANY_JOINABLE) @@ -1164,8 +1154,7 @@ public class JDBCStoreManager implements StoreManager, JDBCStore { return mapping.getDiscriminator().addClassConditions(sel, subs == Select.SUBS_JOINABLE, joins); } - private boolean needClassCondition(ClassMapping mapping, int subs, - OpenJPAStateManager sm) { + private boolean needClassCondition(ClassMapping mapping, int subs, OpenJPAStateManager sm) { boolean retVal = false; if(sm == null || sm.getPCState() == PCState.TRANSIENT) { if(subs == Select.SUBS_JOINABLE || subs == Select.SUBS_NONE) { diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java index f565fab8f..c59c632bb 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java @@ -31,6 +31,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.apache.openjpa.enhance.PersistenceCapable; import org.apache.openjpa.enhance.Reflection; +import org.apache.openjpa.jdbc.conf.JDBCConfiguration; import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; import org.apache.openjpa.jdbc.kernel.JDBCStore; import org.apache.openjpa.jdbc.meta.strats.NoneClassStrategy; @@ -44,6 +45,8 @@ import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Result; import org.apache.openjpa.jdbc.sql.RowManager; import org.apache.openjpa.jdbc.sql.Select; +import org.apache.openjpa.jdbc.sql.SelectExecutor; +import org.apache.openjpa.jdbc.sql.Union; import org.apache.openjpa.kernel.FetchConfiguration; import org.apache.openjpa.kernel.OpenJPAStateManager; import org.apache.openjpa.kernel.PCState; @@ -60,17 +63,22 @@ import org.apache.openjpa.util.OpenJPAId; /** * Specialization of metadata for relational databases. + *
+ * The mapping may reuse the same {@link SelectExecutor select} if the + * {@link JDBCConfiguration#getSelectCacheEnabled() configuration option} + * instructs to do so. * * @author Abe White + * @author Pinaki Poddar (select caching) */ +@SuppressWarnings("serial") public class ClassMapping extends ClassMetaData implements ClassStrategy { public static final ClassMapping[] EMPTY_MAPPINGS = new ClassMapping[0]; - private static final Localizer _loc = Localizer.forPackage - (ClassMapping.class); + private static final Localizer _loc = Localizer.forPackage(ClassMapping.class); private final ClassMappingInfo _info; private final Discriminator _discrim; @@ -88,6 +96,9 @@ public class ClassMapping // maps columns to joinables private final Map _joinables = new ConcurrentHashMap(); + + private Select _select; + private Union _union; /** * Constructor. Supply described type and owning repository. @@ -1109,4 +1120,48 @@ public class ClassMapping return true; return false; } + + /** + * Gets the {@link Select select} used for selecting instances of this mapping. + * If {@link JDBCConfiguration#getSelectCacheEnabled() aggressive caching} of + * select statements is enabled, then a select is generated for the first call, + * cached in this mapping and subsequently returned. A cached select becomes + * {@link Select#isReadOnly() immutable} i.e. no structural modification is + * allowed after its corresponding SQL has been executed on the database. + * + * @return a new or cached select to select instances of this mapping. + */ + public Select getSelect() { + Select result = _select; + if (result == null) { + JDBCConfiguration conf = (JDBCConfiguration)getMappingRepository().getConfiguration(); + result = conf.getSQLFactoryInstance().newSelect(); + if (conf.getSelectCacheEnabled()) { + _select = result; + } + } + return result; + } + + /** + * Gets the {@link Union union} used for selecting instances of this mapping. + * If {@link JDBCConfiguration#getSelectCacheEnabled() aggressive caching} of + * union statements is enabled, then a union is generated for the first call, + * cached in this mapping and subsequently returned. A cached union becomes + * {@link Select#isReadOnly() immutable} i.e. no structural modification is + * allowed after its corresponding SQL has been executed on the database. + * + * @return a new or cached union to select instances of this mapping. + */ + public Union getUnion(int selects) { + Union result = _union; + if (result == null) { + JDBCConfiguration conf = (JDBCConfiguration)getMappingRepository().getConfiguration(); + result = conf.getSQLFactoryInstance().newUnion(selects); + if (conf.getSelectCacheEnabled()) { + _union = result; + } + } + return result; + } } diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java index 68cf48392..1cdc9f44a 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java @@ -81,19 +81,19 @@ public class FieldMapping private boolean _outer = false; private int _fetchMode = Integer.MAX_VALUE; private Unique[] _joinTableUniques; // Unique constraints on JoinTable - private Boolean _bidirectionalJoinTableOwner = null; - private Boolean _bidirectionalJoinTableNonOwner = null; + private Boolean _bidirectionalJoinTableOwner; + private Boolean _bidirectionalJoinTableNonOwner; - private Boolean _bi_MTo1_JT = null; - private Boolean _uni_1ToM_FK = null; - private Boolean _uni_MTo1_JT = null; - private Boolean _uni_1To1_JT = null; - private Boolean _bi_1To1_JT = null; + private Boolean _bidirectionalManyToOneJoinTable; + private Boolean _unidirectionalOneToManyForeignKey; + private Boolean _unidirectionalManyToOneJoinTable; + private Boolean _unidirectionalOneToOneJoinTable; + private Boolean _bidirectionalOneToOneJoinTable; - private FieldMapping _bi_1ToM_JT_Field = null; - private FieldMapping _bi_MTo1_JT_Field = null; - private ForeignKey _bi_1ToM_Join_FK = null; - private ForeignKey _bi_1ToM_Elem_FK = null; + private FieldMapping _bidirectionalOneToManyJoinTableField; + private FieldMapping _bidirectionalManyToOneJoinTableField; + private ForeignKey _bidirectionalOneToManyJoinForeignKey; + private ForeignKey _bidirectionalOneToManyElementForeignKey; private boolean _hasMapsIdCols = false; @@ -1271,85 +1271,90 @@ public class FieldMapping return _bidirectionalJoinTableNonOwner.booleanValue(); } - public boolean isBiMTo1JT() { - if (_bi_MTo1_JT == null) { - _bi_MTo1_JT = getMappingRepository().isBiMTo1JT(this); + public boolean isBidirectionalManyToOneJoinTable() { + if (_bidirectionalManyToOneJoinTable == null) { + _bidirectionalManyToOneJoinTable = getMappingRepository().isBidirectionalManyToOneJoinTable(this); } - return _bi_MTo1_JT; + return _bidirectionalManyToOneJoinTable; } - public boolean isUni1ToMFK() { - if (_uni_1ToM_FK == null) - _uni_1ToM_FK = getMappingRepository().isUni1ToMFK(this); - return _uni_1ToM_FK; + public boolean isUnidirectionalOneToManyForeignKey() { + if (_unidirectionalOneToManyForeignKey == null) + _unidirectionalOneToManyForeignKey = getMappingRepository().isUnidirectionalOneToManyForeignKey(this); + return _unidirectionalOneToManyForeignKey; } - public boolean isUniMTo1JT() { - if (_uni_MTo1_JT == null) - _uni_MTo1_JT = getMappingRepository().isUniMTo1JT(this); - return _uni_MTo1_JT; + public boolean isUnidirectionalManyToOneJoinTable() { + if (_unidirectionalManyToOneJoinTable == null) + _unidirectionalManyToOneJoinTable = getMappingRepository().isUnidirectionalManyToOneJoinTable(this); + return _unidirectionalManyToOneJoinTable; } - public boolean isUni1To1JT() { - if (_uni_1To1_JT == null) - _uni_1To1_JT = getMappingRepository().isUni1To1JT(this); - return _uni_1To1_JT; + public boolean isUnidirectionalOneToOneJoinTable() { + if (_unidirectionalOneToOneJoinTable == null) + _unidirectionalOneToOneJoinTable = getMappingRepository().isUnidirectionalOneToOneJoinTable(this); + return _unidirectionalOneToOneJoinTable; } - public boolean isBi1To1JT() { - if (_bi_1To1_JT == null) - _bi_1To1_JT = getMappingRepository().isBi1To1JT(this); - return _bi_1To1_JT; + public boolean isBidirectionalOneToOneJoinTable() { + if (_bidirectionalOneToOneJoinTable == null) + _bidirectionalOneToOneJoinTable = getMappingRepository().isBidirectionalOneToOneJoinTable(this); + return _bidirectionalOneToOneJoinTable; } - public FieldMapping getBi_1ToM_JTField() { - if (_bi_1ToM_JT_Field == null) { - _bi_1ToM_JT_Field = getMappingRepository().getBi_1ToM_JoinTableField(this); + public FieldMapping getBidirectionalOneToManyJoinTableField() { + if (_bidirectionalOneToManyJoinTableField == null) { + _bidirectionalOneToManyJoinTableField = + getMappingRepository().getBidirectionalOneToManyJoinTableField(this); } - return _bi_1ToM_JT_Field; + return _bidirectionalOneToManyJoinTableField; } - public FieldMapping getBi_MTo1_JTField() { - if (_bi_MTo1_JT_Field == null) { - _bi_MTo1_JT_Field = getMappingRepository().getBi_MTo1_JoinTableField(this); + public FieldMapping getBidirectionalManyToOneJoinTableField() { + if (_bidirectionalManyToOneJoinTableField == null) { + _bidirectionalManyToOneJoinTableField = + getMappingRepository().getBidirectionalManyToOneJoinTableField(this); } - return _bi_MTo1_JT_Field; + return _bidirectionalManyToOneJoinTableField; } - public ForeignKey getBi1ToMJoinFK() { - if (_bi_1ToM_Join_FK == null) { - getBi_1ToM_JTField(); - if (_bi_1ToM_JT_Field != null) - _bi_1ToM_Join_FK = _bi_1ToM_JT_Field.getJoinForeignKey(); + public ForeignKey getBidirectionalOneToManyJoinForeignKey() { + if (_bidirectionalOneToManyJoinForeignKey == null) { + getBidirectionalOneToManyJoinTableField(); + if (_bidirectionalOneToManyJoinTableField != null) + _bidirectionalOneToManyJoinForeignKey = _bidirectionalOneToManyJoinTableField.getJoinForeignKey(); } - return _bi_1ToM_Join_FK; + return _bidirectionalOneToManyJoinForeignKey; } - public ForeignKey getBi1ToMElemFK() { - if (_bi_1ToM_Elem_FK == null) { - getBi_1ToM_JTField(); - if (_bi_1ToM_JT_Field != null) - _bi_1ToM_Elem_FK = _bi_1ToM_JT_Field.getElementMapping().getForeignKey(); + public ForeignKey getBidirectionalOneToManyElementForeignKey() { + if (_bidirectionalOneToManyElementForeignKey == null) { + getBidirectionalOneToManyJoinTableField(); + if (_bidirectionalOneToManyJoinTableField != null) + _bidirectionalOneToManyElementForeignKey = + _bidirectionalOneToManyJoinTableField.getElementMapping().getForeignKey(); } - return _bi_1ToM_Elem_FK; + return _bidirectionalOneToManyElementForeignKey; } - public void setBi1MJoinTableInfo() { + public void setBidirectionalOneToManyJoinTableInfo() { if (getAssociationType() == FieldMetaData.ONE_TO_MANY) { - FieldMapping mapped = getBi_MTo1_JTField(); + FieldMapping mapped = getBidirectionalManyToOneJoinTableField(); if (mapped != null) { FieldMappingInfo info = getMappingInfo(); FieldMappingInfo mappedInfo = mapped.getMappingInfo(); info.setTableIdentifier(mappedInfo.getTableIdentifier()); info.setColumns(mapped.getElementMapping().getValueInfo().getColumns()); - getElementMapping().getValueInfo().setColumns( - mappedInfo.getColumns()); + getElementMapping().getValueInfo().setColumns(mappedInfo.getColumns()); } } } public boolean isNonDefaultMappingUsingJoinTableStrategy() { - return isBi1To1JT() || isUni1To1JT() || isUniMTo1JT() || isBiMTo1JT(); + return isBidirectionalOneToOneJoinTable() + || isUnidirectionalOneToOneJoinTable() + || isUnidirectionalManyToOneJoinTable() + || isBidirectionalManyToOneJoinTable(); } public void setMapsIdCols(boolean hasMapsIdCols) { diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMappingInfo.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMappingInfo.java index ced9c7c0a..63a3637a2 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMappingInfo.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMappingInfo.java @@ -165,7 +165,7 @@ public class FieldMappingInfo public ForeignKey getJoinForeignKey (final FieldMapping field, Table table, boolean adapt) { - if (field.isUni1ToMFK()) { + if (field.isUnidirectionalOneToManyForeignKey()) { List cols = field.getElementMapping().getValueInfo().getColumns(); return getJoin(field, table, adapt, cols); } diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java index 64dc05340..2b8685e46 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java @@ -105,15 +105,14 @@ import org.apache.openjpa.util.UserException; * * @author Abe White */ +@SuppressWarnings("serial") public class MappingRepository extends MetaDataRepository { - private static final Localizer _loc = Localizer.forPackage - (MappingRepository.class); + private static final Localizer _loc = Localizer.forPackage(MappingRepository.class); private transient DBDictionary _dict = null; private transient MappingDefaults _defaults = null; - // object->queryresultmapping private Map _results = new HashMap(); private SchemaGroup _schema = null; private StrategyInstaller _installer = null; @@ -260,12 +259,10 @@ public class MappingRepository extends MetaDataRepository { public QueryResultMapping[] getQueryResultMappings() { if (_locking) { synchronized (this) { - Collection values = _results.values(); - return (QueryResultMapping[]) values.toArray(new QueryResultMapping[values.size()]); + return _results.values().toArray(new QueryResultMapping[_results.size()]); } } else { - Collection values = _results.values(); - return (QueryResultMapping[]) values.toArray(new QueryResultMapping[values.size()]); + return _results.values().toArray(new QueryResultMapping[_results.size()]); } } @@ -273,7 +270,7 @@ public class MappingRepository extends MetaDataRepository { * Return the cached query result mapping with the given name, or null if * none. */ - public QueryResultMapping getCachedQueryResultMapping(Class cls, String name) { + public QueryResultMapping getCachedQueryResultMapping(Class cls, String name) { if (_locking) { synchronized (this) { return (QueryResultMapping) _results.get(getQueryResultKey(cls, name)); @@ -286,7 +283,7 @@ public class MappingRepository extends MetaDataRepository { /** * Add a query result mapping. */ - public QueryResultMapping addQueryResultMapping(Class cls, String name) { + public QueryResultMapping addQueryResultMapping(Class cls, String name) { if (_locking) { synchronized (this) { return addQueryResultMappingInternal(cls, name); @@ -296,7 +293,7 @@ public class MappingRepository extends MetaDataRepository { } } - private QueryResultMapping addQueryResultMappingInternal(Class cls, String name) { + private QueryResultMapping addQueryResultMappingInternal(Class cls, String name) { QueryResultMapping res = new QueryResultMapping(name, this); res.setDefiningType(cls); _results.put(getQueryResultKey(res), res); @@ -319,7 +316,7 @@ public class MappingRepository extends MetaDataRepository { /** * Remove a query result mapping. */ - public boolean removeQueryResultMapping(Class cls, String name) { + public boolean removeQueryResultMapping(Class cls, String name) { if (_locking) { synchronized (this) { if (name == null) @@ -1008,8 +1005,7 @@ public class MappingRepository extends MetaDataRepository { protected FieldStrategy handlerCollectionStrategy(FieldMapping field, ValueHandler ehandler, boolean installHandlers) { // TODO: JPA 2.0 should ignore this flag and not to serialize - if (getConfiguration().getCompatibilityInstance() - .getStoreMapCollectionInEntityAsBlob()) + if (getConfiguration().getCompatibilityInstance().getStoreMapCollectionInEntityAsBlob()) return null; if (installHandlers) field.getElementMapping().setHandler(ehandler); @@ -1024,8 +1020,7 @@ public class MappingRepository extends MetaDataRepository { ValueHandler khandler, ValueHandler vhandler, boolean krel, boolean vrel, boolean installHandlers) { // TODO: JPA 2.0 should ignore this flag and not to serialize - if (getConfiguration().getCompatibilityInstance() - .getStoreMapCollectionInEntityAsBlob()) + if (getConfiguration().getCompatibilityInstance().getStoreMapCollectionInEntityAsBlob()) return null; if (installHandlers) { field.getKeyMapping().setHandler(khandler); @@ -1048,14 +1043,13 @@ public class MappingRepository extends MetaDataRepository { FieldMapping mapped = field.getMappedByMapping(); if (mapped != null) { //bi-/M-1/JoinTable ==> join table strategy - if (isBiMTo1JT(field)) + if (isBidirectionalManyToOneJoinTable(field)) return false; if (mapped.getTypeCode() == JavaTypes.PC || mapped.getTypeCode() == JavaTypes.PC_UNTYPED) return true; if (mapped.getElement().getTypeCode() == JavaTypes.PC) return false; - throw new MetaDataException(_loc.get("bad-mapped-by", field, - mapped)); + throw new MetaDataException(_loc.get("bad-mapped-by", field, mapped)); } // without a mapped-by, we have to look for clues as to the mapping. @@ -1064,82 +1058,84 @@ public class MappingRepository extends MetaDataRepository { // an association table FieldMappingInfo info = field.getMappingInfo(); ValueMapping elem = field.getElementMapping(); - boolean useInverseKeyMapping = DBIdentifier.isNull(info.getTableIdentifier()) && info.getColumns().isEmpty() - && !elem.getValueInfo().getColumns().isEmpty(); + boolean useInverseKeyMapping = DBIdentifier.isNull(info.getTableIdentifier()) + && info.getColumns().isEmpty() + && !elem.getValueInfo().getColumns().isEmpty(); // JPA 2.0: non-default mapping: uni-/1-M/JoinColumn ==> foreign key strategy - if (isUni1ToMFK(field)) { + if (isUnidirectionalOneToManyForeignKey(field)) { return true; } return useInverseKeyMapping; } public boolean isNonDefaultMappingAllowed() { - OpenJPAConfiguration conf = getConfiguration(); - return getMetaDataFactory().getDefaults().isNonDefaultMappingAllowed(conf); + return getMetaDataFactory().getDefaults().isNonDefaultMappingAllowed(getConfiguration()); } - public boolean isUniMTo1JT(FieldMapping field) { - if (isNonDefaultMappingAllowed() && - field.getAssociationType() == FieldMetaData.MANY_TO_ONE && - hasJoinTable(field) && - !isBidirectional(field)) { + public boolean isUnidirectionalManyToOneJoinTable(FieldMapping field) { + if (isNonDefaultMappingAllowed() + && field.getAssociationType() == FieldMetaData.MANY_TO_ONE + && hasJoinTable(field) + && !isBidirectional(field)) { field.getValueMapping().getValueInfo().setColumns(field.getElementMapping().getValueInfo().getColumns()); return true; } return false; } - public boolean isUni1To1JT(FieldMapping field) { - if (isNonDefaultMappingAllowed() && - field.getAssociationType() == FieldMetaData.ONE_TO_ONE && - hasJoinTable(field) && - !isBidirectional(field)) { + public boolean isUnidirectionalOneToOneJoinTable(FieldMapping field) { + if (isNonDefaultMappingAllowed() + && field.getAssociationType() == FieldMetaData.ONE_TO_ONE + && hasJoinTable(field) + && !isBidirectional(field)) { field.getValueMapping().getValueInfo().setColumns(field.getElementMapping().getValueInfo().getColumns()); return true; } return false; } - public boolean isBi1To1JT(FieldMapping field) { - if (isNonDefaultMappingAllowed() && - field.getAssociationType() == FieldMetaData.ONE_TO_ONE && - hasJoinTable(field) && - isBidirectional(field)) { + public boolean isBidirectionalOneToOneJoinTable(FieldMapping field) { + if (isNonDefaultMappingAllowed() + && field.getAssociationType() == FieldMetaData.ONE_TO_ONE + && hasJoinTable(field) + && isBidirectional(field)) { field.getValueMapping().getValueInfo().setColumns(field.getElementMapping().getValueInfo().getColumns()); return true; } return false; } - public boolean isUni1ToMFK(FieldMapping field) { - if (isNonDefaultMappingAllowed() && - field.getAssociationType() == FieldMetaData.ONE_TO_MANY && - hasJoinColumn(field) && - !isBidirectional(field)) { + public boolean isUnidirectionalOneToManyForeignKey(FieldMapping field) { + if (isNonDefaultMappingAllowed() + && field.getAssociationType() == FieldMetaData.ONE_TO_MANY + && hasJoinColumn(field) + && !isBidirectional(field)) { field.getElementMapping().getValueInfo().setColumns(field.getValueInfo().getColumns()); return true; } return false; } - public boolean isBiMTo1JT(FieldMapping field) { + public boolean isBidirectionalManyToOneJoinTable(FieldMapping field) { FieldMapping mapped = field.getMappedByMapping(); if (isNonDefaultMappingAllowed()) { if (field.getAssociationType() == FieldMetaData.ONE_TO_MANY ) { if (mapped != null && hasJoinTable(mapped)) return true; } else if (field.getAssociationType() == FieldMetaData.MANY_TO_ONE) { - if (getBi_1ToM_JoinTableField(field) != null) + if (getBidirectionalOneToManyJoinTableField(field) != null) return true; } } return false; } - // return the inverse field of bidirectional many to one - // relation using join table strategy - public FieldMapping getBi_1ToM_JoinTableField(FieldMapping field) { + /** + * Gets the inverse field of bidirectional many to one relation using join table strategy + * for the given field. + */ + public FieldMapping getBidirectionalOneToManyJoinTableField(FieldMapping field) { if (isNonDefaultMappingAllowed()) { if (field.getAssociationType() == FieldMetaData.ONE_TO_MANY) { FieldMapping mappedBy = field.getMappedByMapping(); @@ -1159,9 +1155,10 @@ public class MappingRepository extends MetaDataRepository { return null; } - // return the owning field of bidirectional one to many - // relation using join table strategy - public FieldMapping getBi_MTo1_JoinTableField(FieldMapping field) { + /** + * Gets the owning field of bidirectional one to many relation using join table strategy of the given field. + */ + public FieldMapping getBidirectionalManyToOneJoinTableField(FieldMapping field) { if (isNonDefaultMappingAllowed()) { if (field.getAssociationType() == FieldMetaData.MANY_TO_ONE) { if (!hasJoinTable(field)) diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/HandlerRelationMapTableFieldStrategy.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/HandlerRelationMapTableFieldStrategy.java index 65b77cce5..1e5636e4e 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/HandlerRelationMapTableFieldStrategy.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/HandlerRelationMapTableFieldStrategy.java @@ -87,7 +87,7 @@ public class HandlerRelationMapTableFieldStrategy union.select(new Union.Selector() { public void select(Select sel, int idx) { sel.select(_kcols); - if (field.isUni1ToMFK()) { + if (field.isUnidirectionalOneToManyForeignKey()) { sel.whereForeignKey(field.getElementMapping().getForeignKey(), sm.getObjectId(), field.getElementMapping().getDeclaredTypeMapping(), store); sel.select(vals[idx], field.getElementMapping(). @@ -146,10 +146,11 @@ public class HandlerRelationMapTableFieldStrategy throw new MetaDataException(_loc.get("not-relation", val)); FieldMapping mapped = field.getMappedByMapping(); - if (field.isUni1ToMFK() || (!field.isBiMTo1JT() && mapped != null)) { + if (field.isUnidirectionalOneToManyForeignKey() + || (!field.isBidirectionalManyToOneJoinTable() && mapped != null)) { // map to the owner table handleMappedByForeignKey(adapt); - } else if (field.isBiMTo1JT() || mapped == null) { + } else if (field.isBidirectionalManyToOneJoinTable() || mapped == null) { // map to a separate table field.mapJoin(adapt, true); if (val.getTypeMapping().isMapped()) { @@ -186,11 +187,11 @@ public class HandlerRelationMapTableFieldStrategy if (map == null || map.isEmpty()) return; - if (!field.isBiMTo1JT() && field.getMappedBy() != null) + if (!field.isBidirectionalManyToOneJoinTable() && field.getMappedBy() != null) return; Row row = null; - if (!field.isUni1ToMFK()) { + if (!field.isUnidirectionalOneToManyForeignKey()) { row = rm.getSecondaryRow(field.getTable(), Row.ACTION_INSERT); row.setForeignKey(field.getJoinForeignKey(), field.getJoinColumnIO(), sm); @@ -204,7 +205,7 @@ public class HandlerRelationMapTableFieldStrategy entry = (Map.Entry) itr.next(); valsm = RelationStrategies.getStateManager(entry.getValue(), ctx); - if (field.isUni1ToMFK()){ + if (field.isUnidirectionalOneToManyForeignKey()){ row = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), Row.ACTION_UPDATE, valsm, true); row.wherePrimaryKey(valsm); @@ -223,7 +224,7 @@ public class HandlerRelationMapTableFieldStrategy // from the view point of the owned side PersistenceCapable obj = sm.getPersistenceCapable(); if (!populateKey(row, valsm, obj, ctx, rm, store)) { - if (!field.isUni1ToMFK()) + if (!field.isUnidirectionalOneToManyForeignKey()) rm.flushSecondaryRow(row); } } @@ -238,7 +239,7 @@ public class HandlerRelationMapTableFieldStrategy public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm) throws SQLException { - if (field.getMappedBy() != null && !field.isBiMTo1JT()) + if (field.getMappedBy() != null && !field.isBidirectionalManyToOneJoinTable()) return; Map map = (Map) sm.fetchObject(field.getIndex()); @@ -269,7 +270,7 @@ public class HandlerRelationMapTableFieldStrategy Object mkey; if (canChange && !change.isEmpty()) { Row changeRow = null; - if (!field.isUni1ToMFK()) { + if (!field.isUnidirectionalOneToManyForeignKey()) { changeRow = rm.getSecondaryRow(field.getTable(), Row.ACTION_UPDATE); changeRow.whereForeignKey(field.getJoinForeignKey(), sm); @@ -278,7 +279,7 @@ public class HandlerRelationMapTableFieldStrategy for (Iterator itr = change.iterator(); itr.hasNext();) { mkey = itr.next(); valsm = RelationStrategies.getStateManager(map.get(mkey), ctx); - if (field.isUni1ToMFK()){ + if (field.isUnidirectionalOneToManyForeignKey()){ changeRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), Row.ACTION_UPDATE, valsm, true); changeRow.wherePrimaryKey(valsm); @@ -288,7 +289,7 @@ public class HandlerRelationMapTableFieldStrategy } HandlerStrategies.where(key, mkey, store, changeRow, _kcols); - if (!field.isUni1ToMFK()) + if (!field.isUnidirectionalOneToManyForeignKey()) rm.flushSecondaryRow(changeRow); } } @@ -297,14 +298,14 @@ public class HandlerRelationMapTableFieldStrategy Collection rem = ct.getRemoved(); if (!rem.isEmpty() || (!canChange && !change.isEmpty())) { Row delRow = null; - if (!field.isUni1ToMFK()) { + if (!field.isUnidirectionalOneToManyForeignKey()) { delRow = rm.getSecondaryRow(field.getTable(), Row.ACTION_DELETE); delRow.whereForeignKey(field.getJoinForeignKey(), sm); } for (Iterator itr = rem.iterator(); itr.hasNext();) { mkey = itr.next(); - if (field.isUni1ToMFK()){ + if (field.isUnidirectionalOneToManyForeignKey()){ updateSetNull(sm, mkey, store, rm); } else { HandlerStrategies.where(key, mkey, store, delRow, _kcols); @@ -314,7 +315,7 @@ public class HandlerRelationMapTableFieldStrategy if (!canChange && !change.isEmpty()) { for (Iterator itr = change.iterator(); itr.hasNext();) { mkey = itr.next(); - if (field.isUni1ToMFK()){ + if (field.isUnidirectionalOneToManyForeignKey()){ updateSetNull(sm, mkey, store, rm); } else { HandlerStrategies.where(key, itr.next(), store, delRow, _kcols); @@ -328,7 +329,7 @@ public class HandlerRelationMapTableFieldStrategy Collection add = ct.getAdded(); if (!add.isEmpty() || (!canChange && !change.isEmpty())) { Row addRow = null; - if (!field.isUni1ToMFK()) { + if (!field.isUnidirectionalOneToManyForeignKey()) { addRow = rm.getSecondaryRow(field.getTable(), Row.ACTION_INSERT); addRow.setForeignKey(field.getJoinForeignKey(), @@ -337,7 +338,7 @@ public class HandlerRelationMapTableFieldStrategy for (Iterator itr = add.iterator(); itr.hasNext();) { mkey = itr.next(); valsm = RelationStrategies.getStateManager(map.get(mkey), ctx); - if (field.isUni1ToMFK()){ + if (field.isUnidirectionalOneToManyForeignKey()){ addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), Row.ACTION_UPDATE, valsm, true); addRow.wherePrimaryKey(valsm); @@ -348,14 +349,14 @@ public class HandlerRelationMapTableFieldStrategy HandlerStrategies.set(key, mkey, store, addRow, _kcols, _kio, true); - if (!field.isUni1ToMFK()) + if (!field.isUnidirectionalOneToManyForeignKey()) rm.flushSecondaryRow(addRow); } if (!canChange && !change.isEmpty()) { for (Iterator itr = change.iterator(); itr.hasNext();) { mkey = itr.next(); valsm = RelationStrategies.getStateManager(map.get(mkey), ctx); - if (field.isUni1ToMFK()){ + if (field.isUnidirectionalOneToManyForeignKey()){ addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), Row.ACTION_UPDATE, valsm, true); addRow.wherePrimaryKey(valsm); @@ -366,7 +367,7 @@ public class HandlerRelationMapTableFieldStrategy HandlerStrategies.set(key, mkey, store, addRow, _kcols, _kio, true); - if (!field.isUni1ToMFK()) + if (!field.isUnidirectionalOneToManyForeignKey()) rm.flushSecondaryRow(addRow); } } @@ -413,9 +414,9 @@ public class HandlerRelationMapTableFieldStrategy public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm) throws SQLException { - if ((field.getMappedBy() != null && !field.isBiMTo1JT())) + if ((field.getMappedBy() != null && !field.isBidirectionalManyToOneJoinTable())) return; - if (field.isUni1ToMFK()) { + if (field.isUnidirectionalOneToManyForeignKey()) { Map mapObj = (Map)sm.fetchObject(field.getIndex()); updateSetNull(sm, store, rm, mapObj.keySet()); return; diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/MapTableFieldStrategy.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/MapTableFieldStrategy.java index a9af073ae..8fcb0c81f 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/MapTableFieldStrategy.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/MapTableFieldStrategy.java @@ -112,10 +112,10 @@ public abstract class MapTableFieldStrategy throw new MetaDataException(_loc.get("mapped-by-key", field)); // Non-default mapping Uni-/OneToMany/ForeignKey allows schema components - if (field.isUni1ToMFK()) + if (field.isUnidirectionalOneToManyForeignKey()) return; - if (field.isBiMTo1JT()) - field.setBi1MJoinTableInfo(); + if (field.isBidirectionalManyToOneJoinTable()) + field.setBidirectionalOneToManyJoinTableInfo(); field.getValueInfo().assertNoSchemaComponents(field, !adapt); } diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java index f1726ef77..09d10a561 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java @@ -28,6 +28,7 @@ import java.util.Set; import org.apache.openjpa.enhance.PersistenceCapable; import org.apache.openjpa.enhance.ReflectingPersistenceCapable; +import org.apache.openjpa.jdbc.conf.JDBCConfiguration; import org.apache.openjpa.jdbc.identifier.DBIdentifier; import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; import org.apache.openjpa.jdbc.kernel.JDBCStore; @@ -37,7 +38,6 @@ import org.apache.openjpa.jdbc.meta.FieldMapping; import org.apache.openjpa.jdbc.meta.FieldStrategy; import org.apache.openjpa.jdbc.meta.Joinable; import org.apache.openjpa.jdbc.meta.MappingInfo; -import org.apache.openjpa.jdbc.meta.ValueHandler; import org.apache.openjpa.jdbc.meta.ValueMapping; import org.apache.openjpa.jdbc.meta.ValueMappingImpl; import org.apache.openjpa.jdbc.meta.ValueMappingInfo; @@ -55,13 +55,13 @@ import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.SelectExecutor; import org.apache.openjpa.jdbc.sql.Union; -import org.apache.openjpa.kernel.LockManager; import org.apache.openjpa.kernel.OpenJPAStateManager; import org.apache.openjpa.lib.log.Log; import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.FieldMetaData; import org.apache.openjpa.meta.JavaTypes; +import org.apache.openjpa.meta.MetaDataModes; import org.apache.openjpa.util.ApplicationIds; import org.apache.openjpa.util.ImplHelper; import org.apache.openjpa.util.InternalException; @@ -74,27 +74,33 @@ import org.apache.openjpa.util.UnsupportedException; /** * Mapping for a single-valued relation to another entity. * + *
+ * The strategy may reuse the same {@link SelectExecutor select} if the + * {@link JDBCConfiguration#getSelectCacheEnabled() configuration option} + * instructs to do so. + * @author Abe White + * @author Pinaki Poddar (select caching) * @since 0.4.0 */ +@SuppressWarnings("serial") public class RelationFieldStrategy extends AbstractFieldStrategy implements Joinable, Embeddable { - private static final Localizer _loc = Localizer.forPackage - (RelationFieldStrategy.class); + private static final Localizer _loc = Localizer.forPackage(RelationFieldStrategy.class); private Boolean _fkOid = null; + private SelectExecutor _executor; + public void map(boolean adapt) { if (field.getTypeCode() != JavaTypes.PC || field.isEmbeddedPC()) throw new MetaDataException(_loc.get("not-relation", field)); - field.getKeyMapping().getValueInfo().assertNoSchemaComponents - (field.getKey(), !adapt); + field.getKeyMapping().getValueInfo().assertNoSchemaComponents(field.getKey(), !adapt); if (!field.isNonDefaultMappingUsingJoinTableStrategy()) - field.getElementMapping().getValueInfo().assertNoSchemaComponents - (field.getElement(), !adapt); + field.getElementMapping().getValueInfo().assertNoSchemaComponents(field.getElement(), !adapt); boolean criteria = field.getValueInfo().getUseClassCriteria(); // check for named inverse @@ -102,40 +108,33 @@ public class RelationFieldStrategy if (mapped != null) { field.getMappingInfo().assertNoSchemaComponents(field, !adapt); field.getValueInfo().assertNoSchemaComponents(field, !adapt); - mapped.resolve(mapped.MODE_META | mapped.MODE_MAPPING); + mapped.resolve(MetaDataModes.MODE_META | MetaDataModes.MODE_MAPPING); if (!mapped.isMapped() || mapped.isSerialized()) - throw new MetaDataException(_loc.get("mapped-by-unmapped", - field, mapped)); + throw new MetaDataException(_loc.get("mapped-by-unmapped", field, mapped)); if (mapped.getTypeCode() == JavaTypes.PC) { - if (mapped.getJoinDirection() == mapped.JOIN_FORWARD) { - field.setJoinDirection(field.JOIN_INVERSE); - field.setColumns(mapped.getDefiningMapping(). - getPrimaryKeyColumns()); + if (mapped.getJoinDirection() == FieldMapping.JOIN_FORWARD) { + field.setJoinDirection(FieldMapping.JOIN_INVERSE); + field.setColumns(mapped.getDefiningMapping().getPrimaryKeyColumns()); } else if (isTypeUnjoinedSubclass(mapped)) throw new MetaDataException(_loc.get - ("mapped-inverse-unjoined", field.getName(), - field.getDefiningMapping(), mapped)); + ("mapped-inverse-unjoined", field.getName(), field.getDefiningMapping(), mapped)); - field.setForeignKey(mapped.getForeignKey - (field.getDefiningMapping())); + field.setForeignKey(mapped.getForeignKey(field.getDefiningMapping())); } else if (mapped.getElement().getTypeCode() == JavaTypes.PC) { if (isTypeUnjoinedSubclass(mapped.getElementMapping())) throw new MetaDataException(_loc.get - ("mapped-inverse-unjoined", field.getName(), - field.getDefiningMapping(), mapped)); + ("mapped-inverse-unjoined", field.getName(), field.getDefiningMapping(), mapped)); // warn the user about making the collection side the owner Log log = field.getRepository().getLog(); if (log.isInfoEnabled()) log.info(_loc.get("coll-owner", field, mapped)); - field.setForeignKey(mapped.getElementMapping(). - getForeignKey()); - } else - throw new MetaDataException(_loc.get("not-inv-relation", - field, mapped)); - + field.setForeignKey(mapped.getElementMapping().getForeignKey()); + } else { + throw new MetaDataException(_loc.get("not-inv-relation", field, mapped)); + } field.setUseClassCriteria(criteria); return; } @@ -157,24 +156,22 @@ public class RelationFieldStrategy field.getMappingInfo().setColumns(null); } - if (!field.isBiMTo1JT()) + if (!field.isBidirectionalManyToOneJoinTable()) field.mapJoin(adapt, false); if (field.getTypeMapping().isMapped()) { if (field.getMappedByIdValue() != null) setMappedByIdColumns(); - if (!field.isBiMTo1JT()) { - ForeignKey fk = vinfo.getTypeJoin(field, field.getName(), true, - adapt); + if (!field.isBidirectionalManyToOneJoinTable()) { + ForeignKey fk = vinfo.getTypeJoin(field, field.getName(), true, adapt); field.setForeignKey(fk); } field.setColumnIO(vinfo.getColumnIO()); - if (vinfo.getJoinDirection() == vinfo.JOIN_INVERSE) - field.setJoinDirection(field.JOIN_INVERSE); - } else - RelationStrategies.mapRelationToUnmappedPC(field, field.getName(), - adapt); - + if (vinfo.getJoinDirection() == MappingInfo.JOIN_INVERSE) + field.setJoinDirection(FieldMapping.JOIN_INVERSE); + } else { + RelationStrategies.mapRelationToUnmappedPC(field, field.getName(), adapt); + } field.setUseClassCriteria(criteria); field.mapPrimaryKey(adapt); PrimaryKey pk = field.getTable().getPrimaryKey(); @@ -209,11 +206,10 @@ public class RelationFieldStrategy } } - private List getMappedByIdColumns(FieldMapping pk) { - ClassMetaData embeddedId = ((ValueMappingImpl)pk.getValue()). - getEmbeddedMetaData(); + private List getMappedByIdColumns(FieldMapping pk) { + ClassMetaData embeddedId = ((ValueMappingImpl)pk.getValue()).getEmbeddedMetaData(); Column[] pkCols = null; - List cols = new ArrayList(); + List cols = new ArrayList(); String mappedByIdValue = field.getMappedByIdValue(); if (embeddedId != null) { FieldMetaData[] fmds = embeddedId.getFields(); @@ -221,20 +217,19 @@ public class RelationFieldStrategy if ((fmds[i].getName().equals(mappedByIdValue)) || mappedByIdValue.length() == 0) { if (fmds[i].getValue().getEmbeddedMetaData() != null) { - EmbedValueHandler.getEmbeddedIdCols( - (FieldMapping)fmds[i], cols); - } else - EmbedValueHandler.getIdColumns( - (FieldMapping)fmds[i], cols); + EmbedValueHandler.getEmbeddedIdCols((FieldMapping)fmds[i], cols); + } else { + EmbedValueHandler.getIdColumns((FieldMapping)fmds[i], cols); + } } } return cols; } else { // primary key is single-value - Class pkType = pk.getDeclaredType(); + Class pkType = pk.getDeclaredType(); FieldMetaData[] pks = field.getValue().getDeclaredTypeMetaData(). getPrimaryKeyFields(); if (pks.length != 1 || pks[0].getDeclaredType() != pkType) - return Collections.EMPTY_LIST; + return Collections.emptyList(); pkCols = pk.getColumns(); for (int i = 0; i < pkCols.length; i++) cols.add(pkCols[i]); @@ -271,11 +266,11 @@ public class RelationFieldStrategy OpenJPAStateManager rel = RelationStrategies.getStateManager (sm.fetchObjectField(field.getIndex()), store.getContext()); - if (field.getJoinDirection() == field.JOIN_INVERSE) + if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE) updateInverse(sm, rel, store, rm); else { Row row = field.getRow(sm, store, rm, Row.ACTION_INSERT); - if (row != null && !field.isBiMTo1JT()) { + if (row != null && !field.isBidirectionalManyToOneJoinTable()) { field.setForeignKey(row, rel); // this is for bi-directional maps, the key and value of the // map are stored in the table of the mapped-by entity @@ -295,7 +290,7 @@ public class RelationFieldStrategy if (mapField == null) return; - Map mapObj = (Map)rel.fetchObjectField(mapField.getIndex()); + Map mapObj = (Map)rel.fetchObjectField(mapField.getIndex()); Object keyObj = getMapKeyObj(mapObj, sm.getPersistenceCapable()); ValueMapping key = mapField.getKeyMapping(); if (!key.isEmbedded()) { @@ -311,14 +306,11 @@ public class RelationFieldStrategy } else { // key is an embeddable or basic type FieldStrategy strategy = mapField.getStrategy(); - if (strategy instanceof - HandlerRelationMapTableFieldStrategy) { - HandlerRelationMapTableFieldStrategy strat = - (HandlerRelationMapTableFieldStrategy) strategy; + if (strategy instanceof HandlerRelationMapTableFieldStrategy) { + HandlerRelationMapTableFieldStrategy strat = (HandlerRelationMapTableFieldStrategy) strategy; Column[] kcols = strat.getKeyColumns((ClassMapping)meta); ColumnIO kio = strat.getKeyColumnIO(); - HandlerStrategies.set(key, keyObj, store, row, kcols, - kio, true); + HandlerStrategies.set(key, keyObj, store, row, kcols, kio, true); } } } @@ -327,19 +319,18 @@ public class RelationFieldStrategy FieldMapping[] fields = ((ClassMapping)meta).getFieldMappings(); for (int i = 0; i < fields.length; i++) { FieldMetaData mappedBy = fields[i].getMappedByMetaData(); - if (fields[i].getDeclaredTypeCode() == JavaTypes.MAP && - mappedBy == field) + if (fields[i].getDeclaredTypeCode() == JavaTypes.MAP && mappedBy == field) return fields[i]; } return null; } - private Object getMapKeyObj(Map mapObj, Object value) { + private Object getMapKeyObj(Map mapObj, Object value) { if (value instanceof ReflectingPersistenceCapable) value = ((ReflectingPersistenceCapable)value).getManagedInstance(); - Set entries = mapObj.entrySet(); - for (Map.Entry entry : entries) { + Set> entries = mapObj.entrySet(); + for (Map.Entry entry : entries) { if (entry.getValue() == value) return entry.getKey(); } @@ -355,7 +346,7 @@ public class RelationFieldStrategy OpenJPAStateManager rel = RelationStrategies.getStateManager (sm.fetchObjectField(field.getIndex()), store.getContext()); - if (field.getJoinDirection() == field.JOIN_INVERSE) { + if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE) { nullInverse(sm, rm); updateInverse(sm, rel, store, rm); } else { @@ -363,22 +354,22 @@ public class RelationFieldStrategy field.isBidirectionalJoinTableMappingNonOwner()) ? Row.ACTION_DELETE : Row.ACTION_UPDATE; Row row = field.getRow(sm, store, rm, action); - if (row != null && !field.isBiMTo1JT()) { + if (row != null && !field.isBidirectionalManyToOneJoinTable()) { field.setForeignKey(row, rel); // this is for bi-directional maps, the key and value of the // map are stored in the table of the mapped-by entity setMapKey(sm, rel, store, row); } - if (field.isBiMTo1JT()) { // also need to update the join table + if (field.isBidirectionalManyToOneJoinTable()) { // also need to update the join table PersistenceCapable invPC = (PersistenceCapable)sm.fetchObject( - field.getBi_1ToM_JTField().getIndex()); + field.getBidirectionalOneToManyJoinTableField().getIndex()); Row secondaryRow = null; if (invPC != null) { - secondaryRow = rm.getSecondaryRow(field.getBi1ToMJoinFK().getTable(), + secondaryRow = rm.getSecondaryRow(field.getBidirectionalOneToManyJoinForeignKey().getTable(), Row.ACTION_INSERT); - secondaryRow.setForeignKey(field.getBi1ToMElemFK(), null, sm); - secondaryRow.setForeignKey(field.getBi1ToMJoinFK(), null, + secondaryRow.setForeignKey(field.getBidirectionalOneToManyElementForeignKey(), null, sm); + secondaryRow.setForeignKey(field.getBidirectionalOneToManyJoinForeignKey(), null, RelationStrategies.getStateManager(invPC, store.getContext())); rm.flushSecondaryRow(secondaryRow); @@ -392,7 +383,7 @@ public class RelationFieldStrategy if (field.getMappedBy() != null) return; - if (field.getJoinDirection() == field.JOIN_INVERSE) { + if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE) { if (sm.getLoaded().get(field.getIndex())) { OpenJPAStateManager rel = RelationStrategies.getStateManager(sm. fetchObjectField(field.getIndex()), store.getContext()); @@ -504,7 +495,7 @@ public class RelationFieldStrategy public int supportsSelect(Select sel, int type, OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch) { if (type == Select.TYPE_JOINLESS) - return (field.getJoinDirection() != field.JOIN_INVERSE + return (field.getJoinDirection() != FieldMapping.JOIN_INVERSE && sel.isSelected(field.getTable())) ? 1 : 0; if (type == Select.TYPE_TWO_PART) return 1; @@ -535,17 +526,15 @@ public class RelationFieldStrategy final OpenJPAStateManager sm, final JDBCStore store, final JDBCFetchConfiguration fetch, final int eagerMode) { final ClassMapping[] clss = field.getIndependentTypeMappings(); - if (!(sel instanceof Union)) + if (!(sel instanceof Union)) { selectEagerParallel((Select) sel, clss[0], store, fetch, eagerMode); - else { + } else { Union union = (Union) sel; - if (fetch.getSubclassFetchMode (field.getTypeMapping()) - != JDBCFetchConfiguration.EAGER_JOIN) + if (fetch.getSubclassFetchMode (field.getTypeMapping()) != JDBCFetchConfiguration.EAGER_JOIN) union.abortUnion(); union.select(new Union.Selector() { public void select(Select sel, int idx) { - selectEagerParallel(sel, clss[idx], store, fetch, - eagerMode); + selectEagerParallel(sel, clss[idx], store, fetch, eagerMode); } }); } @@ -556,7 +545,7 @@ public class RelationFieldStrategy */ private void selectEagerParallel(Select sel, ClassMapping cls, JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) { - if (field.isBiMTo1JT()) + if (field.isBidirectionalManyToOneJoinTable()) return; sel.selectPrimaryKey(field.getDefiningMapping()); // set a variable name that does not conflict with any in the query; @@ -571,7 +560,7 @@ public class RelationFieldStrategy public void selectEagerJoin(Select sel, OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) { - if (field.isBiMTo1JT()) + if (field.isBidirectionalManyToOneJoinTable()) return; // limit the eager mode to single on recursive eager fetching b/c @@ -590,7 +579,7 @@ public class RelationFieldStrategy * Add the joins needed to select/load eager data. */ private Joins eagerJoin(Joins joins, ClassMapping cls, boolean forceInner) { - boolean inverse = field.getJoinDirection() == field.JOIN_INVERSE; + boolean inverse = field.getJoinDirection() == FieldMapping.JOIN_INVERSE; if (!inverse) { joins = join(joins, false); joins = setEmbeddedVariable(joins); @@ -618,7 +607,7 @@ public class RelationFieldStrategy public int select(Select sel, OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) { - if (field.getJoinDirection() == field.JOIN_INVERSE) + if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE) return -1; // already cached oid? if (sm != null && sm.getIntermediate(field.getIndex()) != null) @@ -633,11 +622,11 @@ public class RelationFieldStrategy JDBCFetchConfiguration fetch, Object res) throws SQLException { // process batched results if we haven't already - Map rels; + Map rels; if (res instanceof Result) rels = processEagerParallelResult(sm, store, fetch, (Result) res); else - rels = (Map) res; + rels = (Map) res; // store object for this oid in instance sm.storeObject(field.getIndex(), rels.remove(sm.getObjectId())); @@ -647,7 +636,7 @@ public class RelationFieldStrategy /** * Process the given batched result. */ - private Map processEagerParallelResult(OpenJPAStateManager sm, + private Map processEagerParallelResult(OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, Result res) throws SQLException { // do same joins as for load @@ -657,7 +646,7 @@ public class RelationFieldStrategy Joins joins = res.newJoins().setVariable("*"); eagerJoin(joins, clss[0], true); - Map rels = new HashMap(); + Map rels = new HashMap(); ClassMapping owner = field.getDefiningMapping(); ClassMapping cls; Object oid; @@ -676,7 +665,7 @@ public class RelationFieldStrategy public void loadEagerJoin(OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, Result res) throws SQLException { - if (field.isBiMTo1JT()) + if (field.isBidirectionalManyToOneJoinTable()) return; ClassMapping cls = field.getIndependentTypeMappings()[0]; @@ -719,7 +708,7 @@ public class RelationFieldStrategy public void load(OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, Result res) throws SQLException { - if (field.getJoinDirection() == field.JOIN_INVERSE) + if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE) return; // cached oid? if (sm != null && sm.getIntermediate(field.getIndex()) != null) @@ -732,7 +721,7 @@ public class RelationFieldStrategy // get the related object's oid ClassMapping relMapping = field.getTypeMapping(); Object oid = null; - if (relMapping.isMapped() && !field.isBiMTo1JT()) { + if (relMapping.isMapped() && !field.isBidirectionalManyToOneJoinTable()) { oid = relMapping.getObjectId(store, res, field.getForeignKey(), field.getPolymorphic() != ValueMapping.POLY_FALSE, null); } else { @@ -746,8 +735,7 @@ public class RelationFieldStrategy if (cols.length == 1) { Object val = res.getObject(cols[0], null, null); if (val != null) - oid = ApplicationIds.fromPKValues(new Object[]{ val }, - relMapping); + oid = ApplicationIds.fromPKValues(new Object[]{ val }, relMapping); } else { Object[] vals = new Object[cols.length]; for (int i = 0; i < cols.length; i++) { @@ -767,8 +755,7 @@ public class RelationFieldStrategy sm.setIntermediate(field.getIndex(), oid); } - public void load(final OpenJPAStateManager sm, final JDBCStore store, - final JDBCFetchConfiguration fetch) + public void load(final OpenJPAStateManager sm, final JDBCStore store, final JDBCFetchConfiguration fetch) throws SQLException { // check for cached oid value, or load oid if no way to join if (Boolean.TRUE.equals(_fkOid)) { @@ -787,41 +774,54 @@ public class RelationFieldStrategy // select related mapping columns; joining from the related type // back to our fk table if not an inverse mapping (in which case we // can just make sure the inverse cols == our pk values) - Union union = store.getSQLFactory().newUnion(rels.length); - union.setExpectedResultCount(1, false); - if (fetch.getSubclassFetchMode(field.getTypeMapping()) - != JDBCFetchConfiguration.EAGER_JOIN) - union.abortUnion(); + Union union; + if (_executor == null) { + union = store.getSQLFactory().newUnion(rels.length); + union.setExpectedResultCount(1, false); + if (fetch.getSubclassFetchMode(field.getTypeMapping()) != JDBCFetchConfiguration.EAGER_JOIN) + union.abortUnion(); + if (((JDBCConfiguration)field.getMappingRepository().getConfiguration()).getSelectCacheEnabled()) { + _executor = union; + } + } else { + union = (Union)_executor; + } union.select(new Union.Selector() { public void select(Select sel, int idx) { - if (field.getJoinDirection() == field.JOIN_INVERSE) - sel.whereForeignKey(field.getForeignKey(rels[idx]), - sm.getObjectId(), field.getDefiningMapping(), store); - else { - if (!field.isBiMTo1JT()) { - resJoins[idx] = sel.newJoins().joinRelation(field.getName(), - field.getForeignKey(rels[idx]), rels[idx], - field.getSelectSubclasses(), false, false); + ForeignKey fk = field.getForeignKey(rels[idx]); + ClassMapping mapping = field.getDefiningMapping(); + Object oid = sm.getObjectId(); + if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE) { + sel.whereForeignKey(fk, oid, mapping, store); + } else { + if (!field.isBidirectionalManyToOneJoinTable()) { + if (sel.isReadOnly()) { + resJoins[idx] = sel.getJoins(); + } else { + resJoins[idx] = sel.newJoins().joinRelation(field.getName(), fk, rels[idx], + subs, false, false); + } field.wherePrimaryKey(sel, sm, store); } else { - resJoins[idx] = sel.newJoins().joinRelation(null, - field.getBi1ToMJoinFK(), rels[idx], - field.getSelectSubclasses(), false, false); - sel.whereForeignKey(field.getBi1ToMElemFK(), sm.getObjectId(), - field.getDefiningMapping(), store); + if (sel.isReadOnly()) { + resJoins[idx] = sel.getJoins(); + } else { + resJoins[idx] = sel.newJoins().joinRelation(null, + field.getBidirectionalOneToManyJoinForeignKey(), rels[idx], + subs, false, false); + } + sel.whereForeignKey(field.getBidirectionalOneToManyElementForeignKey(), oid, mapping, store); } } - sel.select(rels[idx], subs, store, fetch, fetch.EAGER_JOIN, - resJoins[idx]); + if (!sel.isReadOnly()) { + sel.select(rels[idx], subs, store, fetch, JDBCFetchConfiguration.EAGER_JOIN, resJoins[idx]); + } } }); Result res = union.execute(store, fetch); try { - Object val = null; - if (res.next()) - val = res.load(rels[res.indexOf()], store, fetch, - resJoins[res.indexOf()]); + Object val = (res.next()) ? res.load(rels[res.indexOf()], store, fetch, resJoins[res.indexOf()]) : null; sm.storeObject(field.getIndex(), val); } finally { res.close(); @@ -837,7 +837,7 @@ public class RelationFieldStrategy // because it'll be in the primary table) and see if fk cols are null; // if inverse, then we have to do a sub-select to see if any inverse // objects point back to this field's owner - if (field.getJoinDirection() != field.JOIN_INVERSE) { + if (field.getJoinDirection() != FieldMapping.JOIN_INVERSE) { //### probably need some sort of subselect here on fk constants joins = join(joins, false); Column[] cols = field.getColumns(); @@ -846,8 +846,9 @@ public class RelationFieldStrategy else sql.append(sel.getColumnAlias(cols[0], joins)). append(" IS ").appendValue(null, cols[0]); - } else + } else { testInverseNull(sql, sel, joins, true); + } } public void appendIsNotNull(SQLBuffer sql, Select sel, Joins joins) { @@ -855,7 +856,7 @@ public class RelationFieldStrategy // because it'll be in the primary table) and see if fk cols aren't // null; if inverse, then we have to do a sub-select to see if any // inverse objects point back to this field's owner - if (field.getJoinDirection() != field.JOIN_INVERSE) { + if (field.getJoinDirection() != FieldMapping.JOIN_INVERSE) { //### probably need some sort of subselect here on fk constants joins = join(joins, false); Column[] cols = field.getColumns(); @@ -886,30 +887,27 @@ public class RelationFieldStrategy sql.append("0 < "); ForeignKey fk = field.getForeignKey(); - ContainerFieldStrategy.appendJoinCount(sql, sel, joins, dict, field, - fk); + ContainerFieldStrategy.appendJoinCount(sql, sel, joins, dict, field, fk); } public Joins join(Joins joins, boolean forceOuter) { // if we're not in an inverse object table join normally, otherwise // already traversed the relation; just join back to owner table - if (field.getJoinDirection() != field.JOIN_INVERSE) + if (field.getJoinDirection() != FieldMapping.JOIN_INVERSE) return field.join(joins, forceOuter, false); ClassMapping[] clss = field.getIndependentTypeMappings(); if (clss.length != 1) throw RelationStrategies.uninversable(field); if (forceOuter) return joins.outerJoinRelation(field.getName(), - field.getForeignKey(), clss[0], field.getSelectSubclasses(), - true, false); + field.getForeignKey(), clss[0], field.getSelectSubclasses(), true, false); return joins.joinRelation(field.getName(), field.getForeignKey(), clss[0], field.getSelectSubclasses(), true, false); } - public Joins joinRelation(Joins joins, boolean forceOuter, - boolean traverse) { + public Joins joinRelation(Joins joins, boolean forceOuter, boolean traverse) { // if this is an inverse mapping it's already joined to the relation - if (field.getJoinDirection() == field.JOIN_INVERSE) + if (field.getJoinDirection() == FieldMapping.JOIN_INVERSE) return joins; ClassMapping[] clss = field.getIndependentTypeMappings(); if (clss.length != 1) { @@ -946,8 +944,7 @@ public class RelationFieldStrategy long id = res.getLong(col, joins); if (field.getObjectIdFieldTypeCode() == JavaTypes.LONG) return id; - return store.newDataStoreId(id, relmapping, field.getPolymorphic() - != ValueMapping.POLY_FALSE); + return store.newDataStoreId(id, relmapping, field.getPolymorphic() != ValueMapping.POLY_FALSE); } if (relmapping.isOpenJPAIdentity()) @@ -1000,27 +997,21 @@ public class RelationFieldStrategy fieldVal = store.getContext().getObjectId(fieldVal); if (fieldVal instanceof OpenJPAId) fieldVal = ((OpenJPAId) fieldVal).getIdObject(); - if (relmapping.getObjectIdType() != null - && relmapping.getObjectIdType().isInstance(fieldVal)) { + if (relmapping.getObjectIdType() != null && relmapping.getObjectIdType().isInstance(fieldVal)) { Object[] pks = ApplicationIds.toPKValues(fieldVal, relmapping); - fieldVal = pks[relmapping.getField(j.getFieldIndex()). - getPrimaryKeyIndex()]; + fieldVal = pks[relmapping.getField(j.getFieldIndex()).getPrimaryKeyIndex()]; } else if (relmapping.getObjectIdType() == ObjectId.class && relmapping.getPrimaryKeyFieldMappings()[0].getValueMapping().isEmbedded()) { - if (fieldVal == null) - return j.getJoinValue(savedFieldVal, col, store); - return j.getJoinValue(fieldVal, col, store); + return j.getJoinValue((fieldVal == null) ? savedFieldVal : fieldVal, col, store); } return j.getJoinValue(fieldVal, col, store); } - public Object getJoinValue(OpenJPAStateManager sm, Column col, - JDBCStore store) { + public Object getJoinValue(OpenJPAStateManager sm, Column col, JDBCStore store) { return getJoinValue(sm.fetch(field.getIndex()), col, store); } - public void setAutoAssignedValue(OpenJPAStateManager sm, JDBCStore store, - Column col, Object autoInc) { + public void setAutoAssignedValue(OpenJPAStateManager sm, JDBCStore store, Column col, Object autoInc) { throw new UnsupportedException(); } @@ -1048,8 +1039,7 @@ public class RelationFieldStrategy return UNSUPPORTED; } - public void loadEmbedded(OpenJPAStateManager sm, JDBCStore store, - JDBCFetchConfiguration fetch, Object val) + public void loadEmbedded(OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, Object val) throws SQLException { ClassMapping relMapping = field.getTypeMapping(); Object oid; @@ -1059,8 +1049,7 @@ public class RelationFieldStrategy oid = store.newDataStoreId(((Number) val).longValue(), relMapping, field.getPolymorphic() != ValueMapping.POLY_FALSE); else { - Object[] pks = (getColumns().length == 1) ? new Object[]{ val } - : (Object[]) val; + Object[] pks = (getColumns().length == 1) ? new Object[]{ val } : (Object[]) val; boolean nulls = true; for (int i = 0; nulls && i < pks.length; i++) nulls = pks[i] == null; @@ -1068,17 +1057,15 @@ public class RelationFieldStrategy oid = null; else { oid = ApplicationIds.fromPKValues(pks, relMapping); - if (field.getPolymorphic() == ValueMapping.POLY_FALSE - && oid instanceof OpenJPAId) { - ((OpenJPAId) oid).setManagedInstanceType(relMapping. - getDescribedType()); + if (field.getPolymorphic() == ValueMapping.POLY_FALSE && oid instanceof OpenJPAId) { + ((OpenJPAId) oid).setManagedInstanceType(relMapping.getDescribedType()); } } } - if (oid == null) + if (oid == null) { sm.storeObject(field.getIndex(), null); - else { + } else { if (JavaTypes.maybePC(field.getValue()) && field.getElement().getEmbeddedMetaData() == null) { Object obj = store.find(oid, field, fetch); diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationRelationMapTableFieldStrategy.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationRelationMapTableFieldStrategy.java index b4bdc01c4..53c55eee7 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationRelationMapTableFieldStrategy.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationRelationMapTableFieldStrategy.java @@ -82,7 +82,7 @@ public class RelationRelationMapTableFieldStrategy kunion.select(new Union.Selector() { public void select(Select sel, int idx) { ForeignKey joinFK = null; - if (field.isUni1ToMFK()) { + if (field.isUnidirectionalOneToManyForeignKey()) { ValueMapping val = field.getElementMapping(); ValueMappingInfo vinfo = val.getValueInfo(); Table table = vinfo.getTable(val); @@ -117,7 +117,7 @@ public class RelationRelationMapTableFieldStrategy vunion.setLRS(lrs); vunion.select(new Union.Selector() { public void select(Select sel, int idx) { - if (field.isUni1ToMFK()) { + if (field.isUnidirectionalOneToManyForeignKey()) { sel.orderBy(field.getKeyMapping().getColumns(), true, true); sel.select(vals[idx], field.getElementMapping(). getSelectSubclasses(), store, fetch, eagerMode, null); @@ -203,10 +203,11 @@ public class RelationRelationMapTableFieldStrategy FieldMapping mapped = field.getMappedByMapping(); DBDictionary dict = field.getMappingRepository().getDBDictionary(); DBIdentifier keyName = null; - if (field.isUni1ToMFK() || (!field.isBiMTo1JT() && mapped != null)) { + if (field.isUnidirectionalOneToManyForeignKey() + || (!field.isBidirectionalManyToOneJoinTable() && mapped != null)) { handleMappedByForeignKey(adapt); keyName = dict.getValidColumnName(DBIdentifier.newColumn("vkey"), field.getTable()); - } else if (field.isBiMTo1JT() || mapped == null) { + } else if (field.isBidirectionalManyToOneJoinTable() || mapped == null) { field.mapJoin(adapt, true); mapTypeJoin(val, DBIdentifier.newColumn("value"), adapt); keyName = dict.getValidColumnName(DBIdentifier.newColumn("key"), field.getTable()); @@ -245,11 +246,11 @@ public class RelationRelationMapTableFieldStrategy if (map == null || map.isEmpty()) return; - if (!field.isBiMTo1JT() && field.getMappedBy() != null) + if (!field.isBidirectionalManyToOneJoinTable() && field.getMappedBy() != null) return; Row row = null; - if (!field.isUni1ToMFK()) { + if (!field.isUnidirectionalOneToManyForeignKey()) { row = rm.getSecondaryRow(field.getTable(), Row.ACTION_INSERT); row.setForeignKey(field.getJoinForeignKey(), field.getJoinColumnIO(), sm); @@ -263,7 +264,7 @@ public class RelationRelationMapTableFieldStrategy entry = (Map.Entry) itr.next(); keysm = RelationStrategies.getStateManager(entry.getKey(), ctx); valsm = RelationStrategies.getStateManager(entry.getValue(), ctx); - if (field.isUni1ToMFK()){ + if (field.isUnidirectionalOneToManyForeignKey()){ row = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), Row.ACTION_UPDATE, valsm, true); row.wherePrimaryKey(valsm); @@ -281,14 +282,14 @@ public class RelationRelationMapTableFieldStrategy // from the view point of the owned side PersistenceCapable obj = sm.getPersistenceCapable(); if (!populateKey(row, valsm, obj, ctx, rm, store)) - if (!field.isUni1ToMFK()) + if (!field.isUnidirectionalOneToManyForeignKey()) rm.flushSecondaryRow(row); } } public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm) throws SQLException { - if (field.getMappedBy() != null && !field.isBiMTo1JT()) + if (field.getMappedBy() != null && !field.isBidirectionalManyToOneJoinTable()) return; Map map = (Map) sm.fetchObject(field.getIndex()); @@ -319,7 +320,7 @@ public class RelationRelationMapTableFieldStrategy Object mkey; if (canChange && !change.isEmpty()) { Row changeRow = null; - if (!field.isUni1ToMFK()) { + if (!field.isUnidirectionalOneToManyForeignKey()) { changeRow = rm.getSecondaryRow(field.getTable(), Row.ACTION_UPDATE); changeRow.whereForeignKey(field.getJoinForeignKey(), sm); @@ -339,7 +340,7 @@ public class RelationRelationMapTableFieldStrategy keysm = RelationStrategies.getStateManager(mkey, ctx); valsm = RelationStrategies.getStateManager(mval, ctx); key.whereForeignKey(changeRow, keysm); - if (field.isUni1ToMFK()){ + if (field.isUnidirectionalOneToManyForeignKey()){ changeRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), Row.ACTION_UPDATE, valsm, true); changeRow.wherePrimaryKey(valsm); @@ -355,7 +356,7 @@ public class RelationRelationMapTableFieldStrategy Collection rem = ct.getRemoved(); if (!rem.isEmpty() || (!canChange && !change.isEmpty())) { Row delRow = null; - if (!field.isUni1ToMFK()) { + if (!field.isUnidirectionalOneToManyForeignKey()) { delRow = rm.getSecondaryRow(field.getTable(), Row.ACTION_DELETE); delRow.whereForeignKey(field.getJoinForeignKey(), sm); @@ -363,7 +364,7 @@ public class RelationRelationMapTableFieldStrategy for (Iterator itr = rem.iterator(); itr.hasNext();) { Object pc = itr.next(); - if (field.isUni1ToMFK()){ + if (field.isUnidirectionalOneToManyForeignKey()){ updateSetNull(sm, rm, pc); } else { keysm = RelationStrategies.getStateManager(pc, ctx); @@ -374,7 +375,7 @@ public class RelationRelationMapTableFieldStrategy if (!canChange && !change.isEmpty()) { for (Iterator itr = change.iterator(); itr.hasNext();) { Object pc = itr.next(); - if (field.isUni1ToMFK()){ + if (field.isUnidirectionalOneToManyForeignKey()){ updateSetNull(sm, rm, pc); } else { keysm = RelationStrategies.getStateManager(pc, ctx); @@ -389,7 +390,7 @@ public class RelationRelationMapTableFieldStrategy Collection add = ct.getAdded(); if (!add.isEmpty() || (!canChange && !change.isEmpty())) { Row addRow = null; - if (!field.isUni1ToMFK()) { + if (!field.isUnidirectionalOneToManyForeignKey()) { addRow = rm.getSecondaryRow(field.getTable(), Row.ACTION_INSERT); addRow.setForeignKey(field.getJoinForeignKey(), @@ -409,7 +410,7 @@ public class RelationRelationMapTableFieldStrategy continue; keysm = RelationStrategies.getStateManager(mkey, ctx); valsm = RelationStrategies.getStateManager(mval, ctx); - if (field.isUni1ToMFK()){ + if (field.isUnidirectionalOneToManyForeignKey()){ addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), Row.ACTION_UPDATE, valsm, true); addRow.wherePrimaryKey(valsm); @@ -436,7 +437,7 @@ public class RelationRelationMapTableFieldStrategy continue; keysm = RelationStrategies.getStateManager(mkey, ctx); valsm = RelationStrategies.getStateManager(mval, ctx); - if (field.isUni1ToMFK()){ + if (field.isUnidirectionalOneToManyForeignKey()){ addRow = rm.getRow(field.getElementMapping().getDeclaredTypeMapping().getTable(), Row.ACTION_UPDATE, valsm, true); addRow.wherePrimaryKey(valsm); @@ -503,7 +504,7 @@ public class RelationRelationMapTableFieldStrategy public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm) throws SQLException { - if (field.isUni1ToMFK()) { + if (field.isUnidirectionalOneToManyForeignKey()) { Map mapObj = (Map)sm.fetchObject(field.getIndex()); updateSetNull(sm, store, rm, mapObj.keySet()); return; diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationToManyTableFieldStrategy.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationToManyTableFieldStrategy.java index 55514b0ce..5e6746fe3 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationToManyTableFieldStrategy.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationToManyTableFieldStrategy.java @@ -113,7 +113,7 @@ public abstract class RelationToManyTableFieldStrategy // Bi-directional oneToMany relation with join table strategy // ==> should not mapped in the owner's table if (mapped != null) { - if (!field.isBiMTo1JT()) { + if (!field.isBidirectionalManyToOneJoinTable()) { if (mapped.getElement().getTypeCode() != JavaTypes.PC) { throw new MetaDataException(_loc.get("not-inv-relation-coll", field, mapped)); @@ -134,9 +134,9 @@ public abstract class RelationToManyTableFieldStrategy } } - if (mapped == null || field.isBiMTo1JT()) { - if (field.isBiMTo1JT()) - field.setBi1MJoinTableInfo(); + if (mapped == null || field.isBidirectionalManyToOneJoinTable()) { + if (field.isBidirectionalManyToOneJoinTable()) + field.setBidirectionalOneToManyJoinTableInfo(); field.mapJoin(adapt, true); if (elem.getTypeMapping().isMapped()) { ForeignKey fk = vinfo.getTypeJoin(elem, "element", false, adapt); @@ -157,7 +157,7 @@ public abstract class RelationToManyTableFieldStrategy public void insert(OpenJPAStateManager sm, JDBCStore store, RowManager rm) throws SQLException { - if (field.getMappedBy() == null || field.isBiMTo1JT()) + if (field.getMappedBy() == null || field.isBidirectionalManyToOneJoinTable()) insert(sm, rm, sm.fetchObject(field.getIndex())); } @@ -188,7 +188,7 @@ public abstract class RelationToManyTableFieldStrategy public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm) throws SQLException { - if (field.getMappedBy() != null && !field.isBiMTo1JT()) + if (field.getMappedBy() != null && !field.isBidirectionalManyToOneJoinTable()) return; Object obj = sm.fetchObject(field.getIndex()); diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java index f8ddeb4ac..56f471ec3 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; import org.apache.openjpa.enhance.PersistenceCapable; +import org.apache.openjpa.jdbc.conf.JDBCConfiguration; import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; import org.apache.openjpa.jdbc.kernel.JDBCStore; import org.apache.openjpa.jdbc.meta.ClassMapping; @@ -57,8 +58,13 @@ import org.apache.openjpa.util.Proxy; * insert/update/delete behavior as well as overriding * {@link FieldStrategy#toDataStoreValue}, {@link FieldStrategy#join}, and * {@link FieldStrategy#joinRelation} if necessary. + *
+ * The strategy may reuse the same {@link SelectExecutor select} if the + * {@link JDBCConfiguration#getSelectCacheEnabled() configuration option} + * instructs to do so. * * @author Abe White + * @author Pinaki Poddar (select caching) */ @SuppressWarnings("serial") public abstract class StoreCollectionFieldStrategy @@ -194,6 +200,7 @@ public abstract class StoreCollectionFieldStrategy private void selectEager(Select sel, ClassMapping elem, OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode, boolean selectOid, boolean outer) { + if (sel.isReadOnly()) return; // force distinct if there was a to-many join to avoid duplicates, but // if this is a parallel select don't make distinct based on the // eager joins alone if the original wasn't distinct @@ -523,7 +530,9 @@ public abstract class StoreCollectionFieldStrategy Union union; if (_executor == null) { union = store.getSQLFactory().newUnion(Math.max(1, elems.length)); - _executor = union; + if (store.getConfiguration().getSelectCacheEnabled()) { + _executor = union; + } } else { union = (Union)_executor; } @@ -571,25 +580,24 @@ public abstract class StoreCollectionFieldStrategy } /** - * Select data for loading, starting in field table. + * Selects data for loading, starting in field table. + * */ protected Joins selectAll(Select sel, ClassMapping elem, - OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, - int eagerMode) { + OpenJPAStateManager sm, JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) { ForeignKey fk = getJoinForeignKey(elem); Object oid = getObjectIdForJoin(fk, sm); sel.whereForeignKey(fk, oid, field.getDefiningMapping(), store); - Joins joins; - if (!sel.isReadOnly()) { - // order first, then select so that if the projection introduces - // additional ordering, it will be after our required ordering - field.orderLocal(sel, elem, null); - joins = joinElementRelation(sel.newJoins(), elem); - field.orderRelation(sel, elem, joins); - selectElement(sel, elem, store, fetch, eagerMode, joins); - } else { - joins = joinElementRelation(sel.newJoins(), elem); + if (sel.isReadOnly()) { + return sel.getJoins(); } + // order first, then select so that if the projection introduces + // additional ordering, it will be after our required ordering + field.orderLocal(sel, elem, null); + Joins joins = joinElementRelation(sel.newJoins(), elem); + field.orderRelation(sel, elem, joins); + selectElement(sel, elem, store, fetch, eagerMode, joins); + return joins; } diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java index 8dcf990bd..e1fbde2d6 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java @@ -1894,7 +1894,8 @@ public class DBDictionary public SQLBuffer toSelectCount(Select sel) { SQLBuffer selectSQL = new SQLBuffer(this); SQLBuffer from; - sel.addJoinClassConditions(); + if (!sel.isReadOnly()) + sel.addJoinClassConditions(); if (sel.getFromSelect() != null) from = getFromSelect(sel, false); else diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java index 7cf8a382e..250f0b054 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectImpl.java @@ -255,6 +255,8 @@ public class SelectImpl } public SQLBuffer toSelect(boolean forUpdate, JDBCFetchConfiguration fetch) { + if (_readOnly) + return _full; _full = _dict.toSelect(this, forUpdate, fetch); return _full; } @@ -378,12 +380,10 @@ public class SelectImpl throws SQLException { if (fetch == null) fetch = store.getFetchConfiguration(); - return execute(store.getContext(), store, fetch, - fetch.getReadLockLevel()); + return execute(store.getContext(), store, fetch, fetch.getReadLockLevel()); } - public Result execute(JDBCStore store, JDBCFetchConfiguration fetch, - int lockLevel) + public Result execute(JDBCStore store, JDBCFetchConfiguration fetch, int lockLevel) throws SQLException { if (fetch == null) fetch = store.getFetchConfiguration(); @@ -394,8 +394,7 @@ public class SelectImpl * Execute this select in the context of the given store manager. The * context is passed in separately for profiling purposes. */ - protected Result execute(StoreContext ctx, JDBCStore store, - JDBCFetchConfiguration fetch, int lockLevel) + protected Result execute(StoreContext ctx, JDBCStore store, JDBCFetchConfiguration fetch, int lockLevel) throws SQLException { boolean forUpdate = false; if (!isAggregate() && _grouping == null) { @@ -678,6 +677,7 @@ public class SelectImpl } public void addJoinClassConditions() { + assertMutable(); if (_joins == null || _joins.joins() == null) return; @@ -806,6 +806,7 @@ public class SelectImpl } public void clearSelects() { + assertMutable(); _selects.clear(); } @@ -873,6 +874,7 @@ public class SelectImpl * to count from the back of the select list. */ public void insertPlaceholder(String sql, int pos) { + assertMutable(); Object holder = (_placeholders >= PLACEHOLDERS.length) ? new Placeholder() : PLACEHOLDERS[_placeholders++]; _selects.insertAlias(pos, holder, sql); @@ -882,14 +884,17 @@ public class SelectImpl * Clear selected placeholders, and return removed select indexes. */ public void clearPlaceholderSelects() { + assertMutable(); _selects.clearPlaceholders(); } public boolean select(Column col) { + assertMutable(); return select(col, (Joins) null); } public boolean select(Column col, Joins joins) { + assertMutable(); if (!isGrouping()) return select(col, getJoins(joins, true), false); groupBy(col, joins); @@ -897,10 +902,12 @@ public class SelectImpl } public int select(Column[] cols) { + assertMutable(); return select(cols, null); } public int select(Column[] cols, Joins joins) { + assertMutable(); if (cols == null || cols.length == 0) return 0; if (isGrouping()) { @@ -919,6 +926,7 @@ public class SelectImpl * Select the given column after making the given joins. */ private boolean select(Column col, PathJoins pj, boolean ident) { + assertMutable(); // we cache on column object if there are no joins so that when // looking up columns in the result we don't have to create a string // buffer for the table + column alias; if there are joins, then @@ -940,12 +948,14 @@ public class SelectImpl public void select(ClassMapping mapping, int subclasses, JDBCStore store, JDBCFetchConfiguration fetch, int eager) { + assertMutable(); select(mapping, subclasses, store, fetch, eager, null); } public void select(ClassMapping mapping, int subclasses, JDBCStore store, JDBCFetchConfiguration fetch, int eager, Joins joins) { + assertMutable(); select(this, mapping, subclasses, store, fetch, eager, joins, false); } @@ -994,10 +1004,12 @@ public class SelectImpl } public boolean selectIdentifier(Column col) { + assertMutable(); return selectIdentifier(col, (Joins) null); } public boolean selectIdentifier(Column col, Joins joins) { + assertMutable(); if (!isGrouping()) return select(col, getJoins(joins, true), true); groupBy(col, joins); @@ -1005,10 +1017,12 @@ public class SelectImpl } public int selectIdentifier(Column[] cols) { + assertMutable(); return selectIdentifier(cols, null); } public int selectIdentifier(Column[] cols, Joins joins) { + assertMutable(); if (cols == null || cols.length == 0) return 0; if (isGrouping()) { @@ -1025,20 +1039,24 @@ public class SelectImpl public void selectIdentifier(ClassMapping mapping, int subclasses, JDBCStore store, JDBCFetchConfiguration fetch, int eager) { + assertMutable(); selectIdentifier(mapping, subclasses, store, fetch, eager, null); } public void selectIdentifier(ClassMapping mapping, int subclasses, JDBCStore store, JDBCFetchConfiguration fetch, int eager, Joins joins) { + assertMutable(); select(this, mapping, subclasses, store, fetch, eager, joins, true); } public int selectPrimaryKey(ClassMapping mapping) { + assertMutable(); return selectPrimaryKey(mapping, null); } public int selectPrimaryKey(ClassMapping mapping, Joins joins) { + assertMutable(); return primaryKeyOperation(mapping, true, null, joins, false); } @@ -1047,6 +1065,7 @@ public class SelectImpl */ private int primaryKeyOperation(ClassMapping mapping, boolean sel, Boolean asc, Joins joins, boolean aliasOrder) { + assertMutable(); if (!sel && asc == null) return 0; @@ -1134,6 +1153,7 @@ public class SelectImpl * Append ordering information to our internal buffer. */ private void appendOrdering(Object orderBy, boolean asc) { + assertMutable(); if (_ordering == null) _ordering = new SQLBuffer(_dict); else @@ -1169,10 +1189,12 @@ public class SelectImpl } public boolean orderBy(Column col, boolean asc, boolean sel) { + assertMutable(); return orderBy(col, asc, null, sel); } public boolean orderBy(Column col, boolean asc, Joins joins, boolean sel) { + assertMutable(); return orderBy(col, asc, joins, sel, false); } @@ -1181,15 +1203,18 @@ public class SelectImpl */ boolean orderBy(Column col, boolean asc, Joins joins, boolean sel, boolean aliasOrder) { + assertMutable(); return columnOperation(col, sel, (asc) ? Boolean.TRUE : Boolean.FALSE, getJoins(joins, true), aliasOrder); } public int orderBy(Column[] cols, boolean asc, boolean sel) { + assertMutable(); return orderBy(cols, asc, null, sel); } public int orderBy(Column[] cols, boolean asc, Joins joins, boolean sel) { + assertMutable(); return orderBy(cols, asc, joins, sel, false); } @@ -1198,6 +1223,7 @@ public class SelectImpl */ int orderBy(Column[] cols, boolean asc, Joins joins, boolean sel, boolean aliasOrder) { + assertMutable(); PathJoins pj = getJoins(joins, true); int seld = 0; for (int i = 0; i < cols.length; i++) @@ -1207,29 +1233,28 @@ public class SelectImpl return seld; } - public boolean orderBy(SQLBuffer sql, boolean asc, boolean sel, Value selAs) - { + public boolean orderBy(SQLBuffer sql, boolean asc, boolean sel, Value selAs) { + assertMutable(); return orderBy(sql, asc, (Joins) null, sel, selAs); } - public boolean orderBy(SQLBuffer sql, boolean asc, Joins joins, - boolean sel, Value selAs) { + public boolean orderBy(SQLBuffer sql, boolean asc, Joins joins, boolean sel, Value selAs) { + assertMutable(); return orderBy(sql, asc, joins, sel, false, selAs); } /** * Allow unions to set aliases on order columns. */ - boolean orderBy(SQLBuffer sql, boolean asc, Joins joins, boolean sel, - boolean aliasOrder, Value selAs) { + boolean orderBy(SQLBuffer sql, boolean asc, Joins joins, boolean sel, boolean aliasOrder, Value selAs) { + assertMutable(); return orderBy((Object) sql, asc, joins, sel, aliasOrder, selAs); } /** * Order on a SQL buffer or string. */ - private boolean orderBy(Object sql, boolean asc, Joins joins, boolean sel, - boolean aliasOrder, Value selAs) { + private boolean orderBy(Object sql, boolean asc, Joins joins, boolean sel, boolean aliasOrder, Value selAs) { assertMutable(); Object order = sql; if (aliasOrder) { @@ -1255,22 +1280,25 @@ public class SelectImpl } public boolean orderBy(String sql, boolean asc, boolean sel) { + assertMutable(); return orderBy(sql, asc, null, sel); } public boolean orderBy(String sql, boolean asc, Joins joins, boolean sel) { + assertMutable(); return orderBy(sql, asc, joins, sel, false); } /** * Allow unions to set aliases on order columns. */ - boolean orderBy(String sql, boolean asc, Joins joins, boolean sel, - boolean aliasOrder) { + boolean orderBy(String sql, boolean asc, Joins joins, boolean sel, boolean aliasOrder) { + assertMutable(); return orderBy((Object) sql, asc, joins, sel, aliasOrder, null); } public void clearOrdering() { + assertMutable(); _ordering = null; _orders = 0; } @@ -1279,9 +1307,9 @@ public class SelectImpl * Allow unions to record the select list indexes of items we order by. */ void setRecordOrderedIndexes(boolean record) { - if (record) + if (record) { _flags |= RECORD_ORDERED; - else { + } else { _ordered = null; _flags &= ~RECORD_ORDERED; } @@ -1300,8 +1328,7 @@ public class SelectImpl return idxs; } - public void wherePrimaryKey(Object oid, ClassMapping mapping, - JDBCStore store) { + public void wherePrimaryKey(Object oid, ClassMapping mapping, JDBCStore store) { wherePrimaryKey(oid, mapping, null, store); } @@ -1311,8 +1338,7 @@ public class SelectImpl * primary key, we will recursively join to its superclass until we find * an ancestor that does. */ - private void wherePrimaryKey(Object oid, ClassMapping mapping, Joins joins, - JDBCStore store) { + private void wherePrimaryKey(Object oid, ClassMapping mapping, Joins joins, JDBCStore store) { // if this mapping's identifiers include something other than // the pk values, join to super and recurse if (!mapping.isPrimaryKeyObjectId(false)) { @@ -1325,12 +1351,10 @@ public class SelectImpl } Column[] cols = mapping.getPrimaryKeyColumns(); - where(oid, mapping, cols, cols, null, null, getJoins(joins, true), - store); + where(oid, mapping, cols, cols, null, null, getJoins(joins, true), store); } - public void whereForeignKey(ForeignKey fk, Object oid, - ClassMapping mapping, JDBCStore store) { + public void whereForeignKey(ForeignKey fk, Object oid, ClassMapping mapping, JDBCStore store) { whereForeignKey(fk, oid, mapping, null, store); } @@ -1340,8 +1364,7 @@ public class SelectImpl * * @see #wherePrimaryKey */ - private void whereForeignKey(ForeignKey fk, Object oid, - ClassMapping mapping, Joins joins, JDBCStore store) { + private void whereForeignKey(ForeignKey fk, Object oid, ClassMapping mapping, Joins joins, JDBCStore store) { // if this mapping's identifiers include something other than // the pk values, or if this foreign key doesn't link to only // identifiers, join to table and do a getPrimaryKey @@ -1364,8 +1387,7 @@ public class SelectImpl } where(oid, mapping, fk.getPrimaryKeyColumns(), fk.getColumns(), - fk.getConstants(), fk.getConstantColumns(), - getJoins(joins, true), store); + fk.getConstants(), fk.getConstantColumns(), getJoins(joins, true), store); } /** @@ -1505,10 +1527,12 @@ public class SelectImpl public void having(SQLBuffer sql) { + assertMutable(); having(sql, (Joins) null); } public void having(SQLBuffer sql, Joins joins) { + assertMutable(); having(sql, getJoins(joins, true)); } @@ -1516,6 +1540,7 @@ public class SelectImpl * Add the given condition to the HAVING clause. */ private void having(SQLBuffer sql, PathJoins pj) { + assertMutable(); // no need to use joins... if (sql == null || sql.isEmpty()) return; @@ -1528,37 +1553,45 @@ public class SelectImpl } public void groupBy(SQLBuffer sql) { + assertMutable(); groupBy(sql, (Joins) null); } public void groupBy(SQLBuffer sql, Joins joins) { + assertMutable(); getJoins(joins, true); groupByAppend(sql.getSQL()); } public void groupBy(String sql) { + assertMutable(); groupBy(sql, (Joins) null); } public void groupBy(String sql, Joins joins) { + assertMutable(); getJoins(joins, true); groupByAppend(sql); } public void groupBy(Column col) { + assertMutable(); groupBy(col, null); } public void groupBy(Column col, Joins joins) { + assertMutable(); PathJoins pj = getJoins(joins, true); groupByAppend(getColumnAlias(col, pj)); } public void groupBy(Column[] cols) { + assertMutable(); groupBy(cols, null); } public void groupBy(Column[] cols, Joins joins) { + assertMutable(); PathJoins pj = getJoins(joins, true); for (int i = 0; i < cols.length; i++) { groupByAppend(getColumnAlias(cols[i], pj)); @@ -1566,6 +1599,7 @@ public class SelectImpl } private void groupByAppend(String sql) { + assertMutable(); if (_grouped == null || !_grouped.contains(sql)) { if (_grouping == null) { _grouping = new SQLBuffer(_dict); @@ -1580,11 +1614,13 @@ public class SelectImpl public void groupBy(ClassMapping mapping, int subclasses, JDBCStore store, JDBCFetchConfiguration fetch) { + assertMutable(); groupBy(mapping, subclasses, store, fetch, null); } public void groupBy(ClassMapping mapping, int subclasses, JDBCStore store, JDBCFetchConfiguration fetch, Joins joins) { + assertMutable(); // we implement this by putting ourselves into grouping mode, where // all select invocations are re-routed to group-by invocations instead. // this allows us to utilize the same select APIs of the store manager @@ -1593,8 +1629,7 @@ public class SelectImpl boolean wasGrouping = isGrouping(); _flags |= GROUPING; try { - select(mapping, subclasses, store, fetch, - EagerFetchModes.EAGER_NONE, joins); + select(mapping, subclasses, store, fetch, EagerFetchModes.EAGER_NONE, joins); } finally { if (!wasGrouping) _flags &= ~GROUPING; @@ -1627,7 +1662,7 @@ public class SelectImpl else if (!pre) { if ((_flags & OUTER) != 0) pj = (PathJoins) outer(pj); - if (record) { + if (record && !_readOnly) { if (!pj.isEmpty()) { if (_joins == null) _joins = new SelectJoins(this); @@ -1818,6 +1853,7 @@ public class SelectImpl } public void append(SQLBuffer buf, Joins joins) { + assertMutable(); if (joins == null || joins.isEmpty()) return; if (_joinSyntax == JoinSyntaxes.SYNTAX_SQL92) @@ -1846,6 +1882,7 @@ public class SelectImpl } public Joins and(Joins joins1, Joins joins2) { + assertMutable(); return and((PathJoins) joins1, (PathJoins) joins2, true); } @@ -1857,6 +1894,7 @@ public class SelectImpl * Combine the given joins. */ private SelectJoins and(PathJoins j1, PathJoins j2, boolean nullJoins) { + assertMutable(); if ((j1 == null || j1.isEmpty()) && (j2 == null || j2.isEmpty())) return null; @@ -1894,6 +1932,7 @@ public class SelectImpl } public Joins or(Joins joins1, Joins joins2) { + assertMutable(); PathJoins j1 = (PathJoins) joins1; PathJoins j2 = (PathJoins) joins2; @@ -2190,32 +2229,38 @@ public class SelectImpl } public Joins join(ForeignKey fk, boolean inverse, boolean toMany) { + assertMutable(); return new SelectJoins(this).join(fk, inverse, toMany); } public Joins outerJoin(ForeignKey fk, boolean inverse, boolean toMany) { + assertMutable(); return new SelectJoins(this).outerJoin(fk, inverse, toMany); } public Joins joinRelation(String name, ForeignKey fk, ClassMapping target, int subs, boolean inverse, boolean toMany) { + assertMutable(); return new SelectJoins(this).joinRelation(name, fk, target, subs, inverse, toMany); } public Joins outerJoinRelation(String name, ForeignKey fk, ClassMapping target, int subs, boolean inverse, boolean toMany) { + assertMutable(); return new SelectJoins(this).outerJoinRelation(name, fk, target, subs, inverse, toMany); } public Joins setVariable(String var) { + assertMutable(); if (var == null) return this; return new SelectJoins(this).setVariable(var); } public Joins setSubselect(String alias) { + assertMutable(); if (alias == null) return this; return new SelectJoins(this).setSubselect(alias); @@ -2312,6 +2357,10 @@ public class SelectImpl */ public void setSelect(SelectImpl sel) { _sel = sel; + if (_sel.isReadOnly()) { + _preJoins = new Stack(); + _preJoins.push(_sel.getJoins()); + } } public Object getEager(FieldMapping key) { @@ -3016,6 +3065,7 @@ public class SelectImpl } protected Selects newSelects() { + assertMutable(); return new Selects(); } @@ -3235,6 +3285,7 @@ public class SelectImpl } public void moveJoinsToParent() { + assertMutable(); } /** diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InheritanceComparator.java b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InheritanceComparator.java index 12e185627..c5ff6f2a0 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InheritanceComparator.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InheritanceComparator.java @@ -27,19 +27,20 @@ import java.util.Comparator; * @author Abe White * @nojavadoc */ +@SuppressWarnings("serial") public class InheritanceComparator implements Comparator, Serializable { - private Class _base = Object.class; + private Class _base = Object.class; /** * Set the least-derived type possible; defaults to null. */ - public void setBase(Class base) { + public void setBase(Class base) { _base = base; } - public Class getBase() { + public Class getBase() { return _base; } @@ -47,8 +48,8 @@ public class InheritanceComparator * Subclasses can override this method to extract the class to compare * on from the elements of the collection. */ - protected Class toClass(Object elem) { - return (Class) elem; + protected Class toClass(Object elem) { + return (Class) elem; } public int compare(Object o1, Object o2) { @@ -59,8 +60,8 @@ public class InheritanceComparator if (o2 == null) return 1; - Class c1 = toClass(o1); - Class c2 = toClass(o2); + Class c1 = toClass(o1); + Class c2 = toClass(o2); if (c1 == c2) return 0; if (c1 == null) @@ -89,7 +90,7 @@ public class InheritanceComparator /** * Count the levels of inheritance between this class and our base class. */ - private int levels(Class to) { + private int levels(Class to) { if (to.isInterface()) return to.getInterfaces().length; for (int i = 0; to != null; i++, to = to.getSuperclass()) diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataInheritanceComparator.java b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataInheritanceComparator.java index 13e72dec8..7a84be954 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataInheritanceComparator.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataInheritanceComparator.java @@ -25,10 +25,11 @@ package org.apache.openjpa.meta; * @author Abe White * @nojavadoc */ +@SuppressWarnings("serial") public class MetaDataInheritanceComparator extends InheritanceComparator { - protected Class toClass(Object elem) { + protected Class toClass(Object elem) { if (elem == null) return null; return ((ClassMetaData) elem).getDescribedType(); diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java index 2e1a63142..cbbc197c5 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java @@ -106,8 +106,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con // system sequence private SequenceMetaData _sysSeq = null; - // cache of parsed metadata, oid class to class, and interface class - // to metadatas + // cache of parsed metadata, oid class to class, and interface class to metadatas private Map, ClassMetaData> _metas = new HashMap, ClassMetaData>(); private Map _metaStringMap = new ConcurrentHashMap(); private Map, Class> _oids = Collections.synchronizedMap(new HashMap, Class>()); @@ -124,7 +123,8 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con private Map, Class> _metamodel = Collections.synchronizedMap(new HashMap, Class>()); // map of classes to lists of their subclasses - private Map, List>> _subs = Collections.synchronizedMap(new HashMap, List>>()); + private Map, Collection>> _subs = + Collections.synchronizedMap(new HashMap, Collection>>()); // xml mapping protected final XMLMetaData[] EMPTY_XMLMETAS; @@ -283,7 +283,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con } /** - * Sets whether this repository will load all known persistent classes at initialization. + * Affirms if this repository will load all known persistent classes at initialization. * Defaults to false. */ public boolean getPreload() { @@ -304,11 +304,11 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con * MetaData for all persistent classes and will remove locking from this class. */ public synchronized void preload() { - if (_preload == false) { + if (!_preload) { return; } // If pooling EMFs, this method may be invoked more than once. Only perform this work once. - if (_preloadComplete == true) { + if (_preloadComplete) { return; } @@ -316,7 +316,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con MultiClassLoader multi = AccessController.doPrivileged(J2DoPrivHelper.newMultiClassLoaderAction()); multi.addClassLoader(AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction())); multi.addClassLoader(AccessController.doPrivileged(J2DoPrivHelper - .getClassLoaderAction(MetaDataRepository.class))); + .getClassLoaderAction(MetaDataRepository.class))); // If a ClassLoader was passed into Persistence.createContainerEntityManagerFactory on the PersistenceUnitInfo // we need to add that loader to the chain of classloaders ClassResolver resolver = _conf.getClassResolverInstance(); @@ -359,8 +359,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con } } - // Hook in this class as a listener and process registered classes list to populate _aliases - // list. + // Hook in this class as a listener and process registered classes list to populate _aliases list. PCRegistry.addRegisterClassListener(this); processRegisteredClasses(multi); _locking = false; @@ -856,9 +855,8 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con } private ClassMetaData[] getMetaDatasInternal() { - // prevent concurrent mod errors when resolving one metadata - // introduces others - ClassMetaData[] metas = (ClassMetaData[]) _metas.values().toArray(new ClassMetaData[_metas.size()]); + // prevent concurrent modification errors when resolving one metadata introduces others + ClassMetaData[] metas = _metas.values().toArray(new ClassMetaData[_metas.size()]); for (int i = 0; i < metas.length; i++) if (metas[i] != null) getMetaData(metas[i].getDescribedType(), metas[i].getEnvClassLoader(), true); @@ -1800,7 +1798,8 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con /** * Add the given value to the collection cached in the given map under the given key. */ - private void addToCollection(Map map, Class key, Class value, boolean inheritance) { + private void addToCollection(Map, Collection>> map, Class key, Class value, + boolean inheritance) { if (_locking) { synchronized (map) { addToCollectionInternal(map, key, value, inheritance); @@ -1810,15 +1809,17 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con } } - private void addToCollectionInternal(Map map, Class key, Class value, boolean inheritance) { - Collection coll = (Collection) map.get(key); + private void addToCollectionInternal(Map, Collection>> map, Class key, + Class value, boolean inheritance) { + Collection> coll = map.get(key); if (coll == null) { if (inheritance) { InheritanceComparator comp = new InheritanceComparator(); comp.setBase(key); coll = new TreeSet>(comp); - } else + } else { coll = new LinkedList>(); + } map.put(key, coll); } coll.add(value); @@ -1892,7 +1893,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con _aliases = new HashMap>>(); _pawares = new HashMap, NonPersistentMetaData>(); _nonMapped = new HashMap, NonPersistentMetaData>(); - _subs = new HashMap, List>>(); + _subs = new HashMap, Collection>>(); // Wait till we're done loading MetaData to flip _lock boolean. } } diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ImmutableBooleanValue.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ImmutableBooleanValue.java new file mode 100644 index 000000000..8625d00a4 --- /dev/null +++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ImmutableBooleanValue.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.lib.conf; + +/** + * An immutable boolean value can be set only once and can never be modified to a different value. + * + * @author Pinaki Poddar + * + */ +public class ImmutableBooleanValue extends BooleanValue { + private boolean _dirty; + + public ImmutableBooleanValue(String prop) { + super(prop); + } + + public void set(boolean value) { + if (_dirty) { + if (value != get().booleanValue()) + throw new IllegalStateException(this + " can not be changed from " + get() + " to " + value); + } else { + _dirty = true; + super.set(value); + } + } + + +} diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataSerializer.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataSerializer.java index 4475089ea..9d5341649 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataSerializer.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataSerializer.java @@ -1511,11 +1511,9 @@ public class AnnotationPersistenceMetaDataSerializer * then name order. */ private class FieldComparator - implements Comparator { + implements Comparator { - public int compare(Object o1, Object o2) { - FieldMetaData fmd1 = (FieldMetaData) o1; - FieldMetaData fmd2 = (FieldMetaData) o2; + public int compare(FieldMetaData fmd1, FieldMetaData fmd2) { if (fmd1.isPrimaryKey()) { if (fmd2.isPrimaryKey()) return fmd1.compareTo(fmd2);