Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/QueryHints.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/QueryHints.java (revision 6403) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/QueryHints.java (working copy) @@ -116,7 +116,7 @@ *

Configures a randomization on the expiry invalidation time. * This can be used to avoid bottlenecks from the cached values expiring at the same time. * By default expiry is not randomized. - * Valid values are number of milliseconds, Integer or Strings that can be parsed to int values. + * Valid values are "true" and "false", false is the default. * @see org.eclipse.persistence.descriptors.invalidation.TimeToLiveCacheInvalidationPolicy#setInvalidationRandomized(boolean) */ public static final String QUERY_RESULTS_CACHE_RANDOMIZE_EXPIRY = "eclipselink.query-results-cache.randomize-expiry"; @@ -126,7 +126,7 @@ *

Configures null results to not be cached. * This can be used to use the query cache as a secondary key index, and allow inserts of new objects. * By default null results are cached. - * Valid values are number of milliseconds, Integer or Strings that can be parsed to int values. + * Valid values are "true" and "false", false is the default. * @see org.eclipse.persistence.queries.QueryResultsCachePolicy#setIsNullIgnored(boolean) */ public static final String QUERY_RESULTS_CACHE_IGNORE_NULL = "eclipselink.query-results-cache.ignore-null"; Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/descriptors/ClassDescriptor.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/descriptors/ClassDescriptor.java (revision 6420) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/descriptors/ClassDescriptor.java (working copy) @@ -2619,18 +2619,17 @@ Vector mappings = getMappings(); Object[] mappingsArray = new Object[mappings.size()]; for (int index = 0; index < mappings.size(); index++) { - mappingsArray[index] = mappings.elementAt(index); + mappingsArray[index] = mappings.get(index); } Arrays.sort(mappingsArray, new MappingCompare()); mappings = NonSynchronizedVector.newInstance(mappingsArray.length); for (int index = 0; index < mappingsArray.length; index++) { - mappings.addElement(mappingsArray[index]); + mappings.add(mappingsArray[index]); } setMappings(mappings); } - for (Enumeration mappingsEnum = getMappings().elements(); mappingsEnum.hasMoreElements();) { - DatabaseMapping mapping = (DatabaseMapping)mappingsEnum.nextElement(); + for (DatabaseMapping mapping : getMappings()) { validateMappingType(mapping); mapping.initialize(session); if (mapping.isLockableMapping()){ @@ -2650,14 +2649,14 @@ // JPA 2.0 Derived identities - build a map of derived id mappings. if (mapping.derivesId()) { - derivesIdMappings.put(mapping.getAttributeName(), mapping); + this.derivesIdMappings.put(mapping.getAttributeName(), mapping); } // Add all the fields in the mapping to myself. Helper.addAllUniqueToVector(getFields(), mapping.getFields()); } - if(hasMappingsPostCalculateChangesOnDeleted()) { + if (hasMappingsPostCalculateChangesOnDeleted()) { session.getProject().setHasMappingsPostCalculateChangesOnDeleted(true); } @@ -2682,15 +2681,13 @@ if (hasInheritance()) { getInheritancePolicy().initialize(session); if (getInheritancePolicy().isChildDescriptor()) { - for (Iterator iterator = getInheritancePolicy().getParentDescriptor().getMappings().iterator(); - iterator.hasNext();) { - DatabaseMapping mapping = (DatabaseMapping)iterator.next(); + for (DatabaseMapping mapping : getInheritancePolicy().getParentDescriptor().getMappings()) { if (mapping.isAggregateObjectMapping() || ((mapping.isForeignReferenceMapping() && (!mapping.isDirectCollectionMapping())) && (!((ForeignReferenceMapping)mapping).usesIndirection()))) { getLockableMappings().add(mapping);// add those mappings from the parent. } // JPA 2.0 Derived identities - build a map of derived id mappings. if (mapping.derivesId()) { - derivesIdMappings.put(mapping.getAttributeName(), mapping); + this.derivesIdMappings.put(mapping.getAttributeName(), mapping); } } } @@ -2705,12 +2702,12 @@ Vector mappings = getMappings(); Object[] mappingsArray = new Object[mappings.size()]; for (int index = 0; index < mappings.size(); index++) { - mappingsArray[index] = mappings.elementAt(index); + mappingsArray[index] = mappings.get(index); } Arrays.sort(mappingsArray, new MappingCompare()); mappings = NonSynchronizedVector.newInstance(mappingsArray.length); for (int index = 0; index < mappingsArray.length; index++) { - mappings.addElement(mappingsArray[index]); + mappings.add(mappingsArray[index]); } setMappings(mappings); } @@ -3238,7 +3235,7 @@ field.setIndex(index); } // Set cache key type. - if (getCacheKeyType() == null) { + if (getCacheKeyType() == null || (getCacheKeyType() == CacheKeyType.AUTO)) { if ((getPrimaryKeyFields().size() > 1) || getObjectBuilder().isXMLObjectBuilder()) { setCacheKeyType(CacheKeyType.CACHE_ID); } else if (getPrimaryKeyFields().size() == 1) { @@ -3251,6 +3248,8 @@ } else { setCacheKeyType(CacheKeyType.CACHE_ID); } + } else if ((getCacheKeyType() == CacheKeyType.ID_VALUE) && (getPrimaryKeyFields().size() > 1)) { + session.getIntegrityChecker().handleError(DescriptorException.cannotUseIdValueForCompositeId(this)); } getObjectBuilder().postInitialize(session); @@ -5255,8 +5254,8 @@ */ protected void validateAfterInitialization(AbstractSession session) { selfValidationAfterInitialization(session); - for (Enumeration mappings = getMappings().elements(); mappings.hasMoreElements();) { - ((DatabaseMapping)mappings.nextElement()).validateAfterInitialization(session); + for (DatabaseMapping mapping : getMappings()) { + mapping.validateAfterInitialization(session); } } @@ -5266,8 +5265,8 @@ */ protected void validateBeforeInitialization(AbstractSession session) { selfValidationBeforeInitialization(session); - for (Enumeration mappings = getMappings().elements(); mappings.hasMoreElements();) { - ((DatabaseMapping)mappings.nextElement()).validateBeforeInitialization(session); + for (DatabaseMapping mapping : getMappings()) { + mapping.validateBeforeInitialization(session); } } @@ -5276,17 +5275,12 @@ * Check that the qualifier on the table names are properly set. */ protected void verifyTableQualifiers(Platform platform) { - DatabaseTable table; - Enumeration tableEnumeration; String tableQualifier = platform.getTableQualifier(); - if (tableQualifier.length() == 0) { return; } - tableEnumeration = getTables().elements(); - while (tableEnumeration.hasMoreElements()) { - table = (DatabaseTable)tableEnumeration.nextElement(); + for (DatabaseTable table : getTables()) { if (table.getTableQualifier().length() == 0) { table.setTableQualifier(tableQualifier); } Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/descriptors/CMPPolicy.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/descriptors/CMPPolicy.java (revision 6420) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/descriptors/CMPPolicy.java (working copy) @@ -354,14 +354,14 @@ /** * INTERNAL: - * Create an instance of the composite primary key class for the key object. + * Create an instance of the Id class or value from the object. */ - public Object createPrimaryKeyInstance(Object key, AbstractSession session) { + public Object createPrimaryKeyInstance(Object object, AbstractSession session) { KeyElementAccessor[] pkElementArray = this.getKeyClassFields(getPKClass()); ObjectBuilder builder = getDescriptor().getObjectBuilder(); if (pkElementArray.length == 1 && pkElementArray[0] instanceof KeyIsElementAccessor){ DatabaseMapping mapping = builder.getMappingForAttributeName(pkElementArray[0].getAttributeName()); - Object fieldValue = mapping.getRealAttributeValueFromObject(key, session); + Object fieldValue = mapping.getRealAttributeValueFromObject(object, session); if (mapping.isObjectReferenceMapping()){ fieldValue = mapping.getReferenceDescriptor().getCMPPolicy().createPrimaryKeyInstance(fieldValue, session); } @@ -371,7 +371,7 @@ Object keyInstance = getPKClassInstance(); Set usedObjectReferenceMappings = new HashSet(); for (int index = 0; index < pkElementArray.length; index++) { - Object keyObj = key; + Object keyObj = object; KeyElementAccessor accessor = pkElementArray[index]; DatabaseField field = accessor.getDatabaseField(); DatabaseMapping mapping = builder.getMappingForField(field); Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/exceptions/DescriptorException.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/exceptions/DescriptorException.java (revision 6403) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/exceptions/DescriptorException.java (working copy) @@ -230,6 +230,7 @@ public final static int MULTIPLE_TARGET_FOREIGN_KEY_TABLES = 213; public final static int ONE_TO_ONE_MAPPING_CONFLICT = 214; public final static int NO_RELATION_TABLE_MECHANISM = 215; + public final static int CANNOT_USE_ID_VALUE_FOR_COMPOSITE_ID = 216; /** * INTERNAL: @@ -1993,11 +1994,20 @@ } public static DescriptorException noRelationTableMechanism(DatabaseMapping mapping) { - Object[] args = { }; + Object[] args = { mapping }; DescriptorException descriptorException = new DescriptorException(ExceptionMessageGenerator.buildMessage(DescriptorException.class, NO_RELATION_TABLE_MECHANISM, args), mapping); descriptorException.setErrorCode(NO_RELATION_TABLE_MECHANISM); return descriptorException; } + + public static DescriptorException cannotUseIdValueForCompositeId(ClassDescriptor descriptor) { + Object[] args = { }; + + DescriptorException descriptorException = new DescriptorException(ExceptionMessageGenerator.buildMessage(DescriptorException.class, CANNOT_USE_ID_VALUE_FOR_COMPOSITE_ID, args), descriptor); + descriptorException.setErrorCode(CANNOT_USE_ID_VALUE_FOR_COMPOSITE_ID); + return descriptorException; + } + } Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/exceptions/i18n/DescriptorExceptionResource.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/exceptions/i18n/DescriptorExceptionResource.java (revision 6403) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/exceptions/i18n/DescriptorExceptionResource.java (working copy) @@ -224,6 +224,7 @@ { "213", "{0} requires all target foreign key fields to belong to the same table, but several were found: {1}." }, { "214", "{0} specifies relation table, that is not compatible with addForeignKey(Name) method, or use addSourceRelationKeyField(Name) and addTargetRelationKeyFieldName methods instead."}, { "215", "{0} must have non-null RelationTableMechanism."}, + { "216", "CacheKeyType cannot be ID_VALUE for a composite primary key.."}, }; Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/descriptors/ObjectBuilder.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/descriptors/ObjectBuilder.java (revision 6420) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/descriptors/ObjectBuilder.java (working copy) @@ -570,10 +570,11 @@ CacheKey unitOfWorkCacheKey = unitOfWork.getIdentityMapAccessorInstance().acquireLock(primaryKey, concreteDescriptor.getJavaClass(), concreteDescriptor); Object clone = unitOfWorkCacheKey.getObject(); boolean found = clone != null; - Object original = null; + Object original = null; try { // Only check parent cache if not in unit of work, or if a refresh is required. if (!found || query.shouldRefreshIdentityMapResult() + || query.shouldCacheQueryResults() // Need to build original to cache it. || query.shouldRetrieveBypassCache() || (concreteDescriptor.hasFetchGroupManager() && concreteDescriptor.getFetchGroupManager().isPartialObject(clone))) { // This is normal case when we are not in transaction. Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/identitymaps/IdentityMapManager.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/identitymaps/IdentityMapManager.java (revision 6406) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/identitymaps/IdentityMapManager.java (working copy) @@ -927,7 +927,7 @@ * values of the parameters to the query so different parameters will have * different cached results. */ - public Object getQueryResult(ReadQuery query, Vector parameters, boolean shouldCheckExpiry) { + public Object getQueryResult(ReadQuery query, List parameters, boolean shouldCheckExpiry) { if (query.getQueryResultsCachePolicy() == null) { return null; } @@ -1226,7 +1226,12 @@ * Query results are cached based on the parameter values provided to the query * different parameter values access different caches. */ - public void putQueryResult(ReadQuery query, Vector parameters, Object results) { + public void putQueryResult(ReadQuery query, List parameters, Object results) { + if ((results == null) || (results == InvalidObject.instance())) { + if (query.getQueryResultsCachePolicy().isNullIgnored()) { + return; + } + } // PERF: use query name, unless no name. Object queryKey = query.getName(); if ((queryKey == null) || ((String)queryKey).length() == 0) { @@ -1257,9 +1262,6 @@ } // Bug 6138532 - store InvalidObject for "no results", do not store null if (results == null) { - if (query.getQueryResultsCachePolicy().isNullIgnored()) { - return; - } results = InvalidObject.instance(); } map.put(lookupParameters, results, null, queryTime); Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/IdentityMapAccessor.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/IdentityMapAccessor.java (revision 6406) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/IdentityMapAccessor.java (working copy) @@ -511,7 +511,7 @@ if (descriptor == null) { throw ValidationException.missingDescriptor(theClass.toString()); } - return this.getIdentityMap(descriptor); + return getIdentityMap(descriptor); } /** @@ -519,16 +519,24 @@ * Get the identity map for the given class from the IdentityMapManager */ public IdentityMap getIdentityMap(ClassDescriptor descriptor) { - return getIdentityMapManager().getIdentityMap(descriptor); + return getIdentityMap(descriptor, false); } /** * INTERNAL: + * Get the identity map for the given class from the IdentityMapManager + */ + public IdentityMap getIdentityMap(ClassDescriptor descriptor, boolean returnNullIfMissing) { + return getIdentityMapManager().getIdentityMap(descriptor, returnNullIfMissing); + } + + /** + * INTERNAL: * Get the cached results associated with a query. Results are cached by the * values of the parameters to the query so different parameters will have * different cached results. */ - public Object getQueryResult(ReadQuery query, Vector parameters, boolean checkExpiry) { + public Object getQueryResult(ReadQuery query, List parameters, boolean checkExpiry) { return getIdentityMapManager().getQueryResult(query, parameters, checkExpiry); } @@ -1003,7 +1011,7 @@ * Query results are cached based on the parameter values provided to the query * different parameter values access different caches. */ - public void putQueryResult(ReadQuery query, Vector parameters, Object results) { + public void putQueryResult(ReadQuery query, List parameters, Object results) { getIdentityMapManager().putQueryResult(query, parameters, results); } @@ -1131,9 +1139,11 @@ Iterator descriptors = getSession().getDescriptors().values().iterator(); while (descriptors.hasNext()) { ClassDescriptor descriptor = (ClassDescriptor)descriptors.next(); - for (Enumeration mapEnum = getIdentityMap(descriptor).elements(); - mapEnum.hasMoreElements();) { - iterator.startIterationOn(mapEnum.nextElement()); + IdentityMap cache = getIdentityMap(descriptor, true); + if (cache != null) { + for (Enumeration mapEnum = cache.elements(); mapEnum.hasMoreElements();) { + iterator.startIterationOn(mapEnum.nextElement()); + } } } } Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/IsolatedClientSessionIdentityMapAccessor.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/IsolatedClientSessionIdentityMapAccessor.java (revision 6403) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/IsolatedClientSessionIdentityMapAccessor.java (working copy) @@ -289,11 +289,11 @@ * Get the identity map for the given class from the IdentityMapManager */ @Override - public IdentityMap getIdentityMap(ClassDescriptor descriptor) { + public IdentityMap getIdentityMap(ClassDescriptor descriptor, boolean returnNullIfMissing) { if (descriptor.isIsolated()) { - return getIdentityMapManager().getIdentityMap(descriptor); + return getIdentityMapManager().getIdentityMap(descriptor, returnNullIfMissing); } else { - return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().getIdentityMap(descriptor); + return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().getIdentityMap(descriptor, returnNullIfMissing); } } @@ -304,7 +304,7 @@ * different cached results. */ @Override - public Object getQueryResult(ReadQuery query, Vector parameters, boolean checkExpiry) { + public Object getQueryResult(ReadQuery query, List parameters, boolean checkExpiry) { if (((IsolatedClientSession)session).isIsolatedQuery(query)) { return getIdentityMapManager().getQueryResult(query, parameters, checkExpiry); } else { @@ -412,7 +412,7 @@ * different parameter values access different caches. */ @Override - public void putQueryResult(ReadQuery query, Vector parameters, Object results) { + public void putQueryResult(ReadQuery query, List parameters, Object results) { if (((IsolatedClientSession)session).isIsolatedQuery(query)) { getIdentityMapManager().putQueryResult(query, parameters, results); } else { Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/UnitOfWorkIdentityMapAccessor.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/UnitOfWorkIdentityMapAccessor.java (revision 6403) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/UnitOfWorkIdentityMapAccessor.java (working copy) @@ -190,7 +190,7 @@ * results are only cached in the parent session for UnitOfWorks */ @Override - public Object getQueryResult(ReadQuery query, Vector parameters, boolean checkExpiry) { + public Object getQueryResult(ReadQuery query, List parameters, boolean checkExpiry) { return ((UnitOfWorkImpl)this.session).getParent().getIdentityMapAccessorInstance().getQueryResult(query, parameters, checkExpiry); } @@ -203,7 +203,7 @@ * Results are only cached in the parent session for UnitOfWorks */ @Override - public void putQueryResult(ReadQuery query, Vector parameters, Object results) { + public void putQueryResult(ReadQuery query, List parameters, Object results) { ((UnitOfWorkImpl)this.session).getParent().getIdentityMapAccessorInstance().putQueryResult(query, parameters, results); } Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/DataReadQuery.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/DataReadQuery.java (revision 6403) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/DataReadQuery.java (working copy) @@ -120,7 +120,7 @@ Object results = getQueryResults(session, row, true); // Bug6138532 - if results are "cached no results", return null immediately if (results == InvalidObject.instance) { - return null; + return getContainerPolicy().containerInstance(0); } if (results != null) { return results; Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/ObjectLevelReadQuery.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/ObjectLevelReadQuery.java (revision 6406) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/ObjectLevelReadQuery.java (working copy) @@ -105,12 +105,6 @@ */ protected int inMemoryQueryIndirectionPolicy; - /** - * Used to set the read time on objects that use this query. - * Should be set to the time the query returned from the database. - */ - protected long executionTime = 0; - /** Allow for a query level fetch group to be set. */ protected FetchGroup fetchGroup; @@ -2118,14 +2112,6 @@ } /** - * INTERNAL: - * Set the the time this query went to the database. - */ - public void setExecutionTime(long executionTime) { - this.executionTime = executionTime; - } - - /** * PUBLIC: * Set the example object of the query to be the newExampleObject. * The example object is used for Query By Example. Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/ReadAllQuery.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/ReadAllQuery.java (revision 6403) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/ReadAllQuery.java (working copy) @@ -444,18 +444,18 @@ protected Object executeObjectLevelReadQuery() throws DatabaseException { Object result = null; - if (getContainerPolicy().overridesRead()) { - return getContainerPolicy().execute(); + if (this.containerPolicy.overridesRead()) { + return this.containerPolicy.execute(); } if (this.descriptor.isDescriptorForInterface()) { Object returnValue = this.descriptor.getInterfacePolicy().selectAllObjectsUsingMultipleTableSubclassRead(this); - setExecutionTime(System.currentTimeMillis()); + this.executionTime = System.currentTimeMillis(); return returnValue; } List rows = getQueryMechanism().selectAllRows(); - setExecutionTime(System.currentTimeMillis()); + this.executionTime = System.currentTimeMillis(); // If using 1-m joins, must set all rows. if (hasJoining() && this.joinedAttributeManager.isToManyJoin()) { @@ -465,7 +465,7 @@ if (this.session.isUnitOfWork()) { result = registerResultInUnitOfWork(rows, (UnitOfWorkImpl)this.session, this.translationRow, true);// } else { - result = getContainerPolicy().containerInstance(rows.size()); + result = this.containerPolicy.containerInstance(rows.size()); this.descriptor.getObjectBuilder().buildObjectsInto(this, rows, result); } @@ -473,13 +473,18 @@ ComplexQueryResult complexResult = new ComplexQueryResult(); complexResult.setResult(result); complexResult.setData(rows); - return complexResult; + result = complexResult; } // Add the other (already registered) results and return them. - if (getDescriptor().hasTablePerClassPolicy()) { - result = containerPolicy.concatenateContainers(result, getDescriptor().getTablePerClassPolicy().selectAllObjectsUsingMultipleTableSubclassRead(this)); + if (this.descriptor.hasTablePerClassPolicy()) { + result = this.containerPolicy.concatenateContainers(result, this.descriptor.getTablePerClassPolicy().selectAllObjectsUsingMultipleTableSubclassRead(this)); } + + // If the results were empty, then ensure they get cached still. + if (shouldCacheQueryResults() && this.containerPolicy.isEmpty(result)) { + this.temporaryCachedQueryResults = InvalidObject.instance(); + } return result; } Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/ReadObjectQuery.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/ReadObjectQuery.java (revision 6406) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/ReadObjectQuery.java (working copy) @@ -156,12 +156,16 @@ * It will cause the original to be cached in the query results if the query * is set to do so. */ - public void cacheResult(Object unwrappedOriginal) { - Object cachableObject = unwrappedOriginal; - if (shouldUseWrapperPolicy()){ - cachableObject = getSession().wrapObject(unwrappedOriginal); + public void cacheResult(Object object) { + Object cachableObject = object; + if (object == null) { + this.temporaryCachedQueryResults = InvalidObject.instance(); + } else { + if (this.shouldUseWrapperPolicy) { + cachableObject = this.session.wrapObject(object); + } + this.temporaryCachedQueryResults = cachableObject; } - setTemporaryCachedQueryResults(cachableObject); } Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/ReadQuery.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/ReadQuery.java (revision 6403) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/queries/ReadQuery.java (working copy) @@ -12,6 +12,7 @@ ******************************************************************************/ package org.eclipse.persistence.queries; +import java.util.List; import java.util.Vector; import org.eclipse.persistence.internal.helper.NonSynchronizedVector; import org.eclipse.persistence.internal.sessions.AbstractRecord; @@ -107,8 +108,12 @@ */ protected void clonedQueryExecutionComplete(DatabaseQuery query, AbstractSession session) { if (shouldCacheQueryResults()) { - // Cached query results must exist on the original query rather than the cloned one - setQueryResults(((ReadQuery)query).getTemporaryCachedQueryResults(), query.getTranslationRow(), query.getSession()); + Object result = ((ReadQuery)query).getTemporaryCachedQueryResults(); + // If the temporary results were never set, then don't cache null. + if (result != null) { + // Cached query results must exist on the original query rather than the cloned one. + setQueryResults(result, query.getTranslationRow(), query.getSession()); + } } } @@ -216,10 +221,8 @@ */ protected Object getQueryResults(AbstractSession session, AbstractRecord row, boolean checkExpiry) { // Check for null translation row. - Vector arguments = null; - if (row == null) { - arguments = new NonSynchronizedVector(1); - } else { + List arguments = null; + if (row != null) { arguments = row.getValues(); } return session.getIdentityMapAccessorInstance().getQueryResult(this, arguments, checkExpiry); Index: foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/sessions/IdentityMapAccessor.java =================================================================== --- foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/sessions/IdentityMapAccessor.java (revision 6403) +++ foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/sessions/IdentityMapAccessor.java (working copy) @@ -273,7 +273,7 @@ /** * ADVANCED: * Returns the remaining life of the given Object. This method is associated with use of - * TopLink's cache invalidation feature and returns the difference between the next expiry + * cache invalidation feature and returns the difference between the next expiry * time of the Object and its read time. The method will return 0 for invalidated Objects. * @param object Object under consideration * @return long time in milliseconds Index: jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/Employee.java =================================================================== --- jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/Employee.java (revision 6403) +++ jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/models/jpa/advanced/Employee.java (working copy) @@ -115,14 +115,21 @@ query="SELECT e FROM Employee e", hints={ @QueryHint(name=QueryHints.QUERY_RESULTS_CACHE, value="true"), - @QueryHint(name=QueryHints.QUERY_RESULTS_CACHE_TYPE, value="SOFT"), - @QueryHint(name=QueryHints.QUERY_RESULTS_CACHE_IGNORE_NULL, value="true"), + @QueryHint(name=QueryHints.QUERY_RESULTS_CACHE_TYPE, value="FULL"), + @QueryHint(name=QueryHints.QUERY_RESULTS_CACHE_IGNORE_NULL, value="false"), @QueryHint(name=QueryHints.QUERY_RESULTS_CACHE_RANDOMIZE_EXPIRY, value="true"), @QueryHint(name=QueryHints.QUERY_RESULTS_CACHE_SIZE, value="200"), - @QueryHint(name=QueryHints.QUERY_RESULTS_CACHE_EXPIRY, value="5000") + @QueryHint(name=QueryHints.QUERY_RESULTS_CACHE_EXPIRY, value="50000") } ), @NamedQuery( + name="CachedNoEmployees", + query="SELECT e FROM Employee e where 1 <> 1", + hints={ + @QueryHint(name=QueryHints.QUERY_RESULTS_CACHE, value="true") + } +), +@NamedQuery( name="CachedTimeOfDayAllEmployees", query="SELECT e FROM Employee e", hints={ Index: jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/advanced/CacheImplJUnitTest.java =================================================================== --- jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/advanced/CacheImplJUnitTest.java (revision 6403) +++ jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/advanced/CacheImplJUnitTest.java (working copy) @@ -17,6 +17,7 @@ import junit.framework.TestSuite; import org.eclipse.persistence.testing.models.jpa.advanced.*; import org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl; +import org.eclipse.persistence.jpa.JpaCache; import org.eclipse.persistence.testing.framework.junit.JUnitTestCase; /** @@ -33,14 +34,7 @@ super(name); } - public static void setUpClass() throws Exception { - } - - public static void tearDownClass() throws Exception { - } - public void setUp() { - super.setUp(); clearCache(); } @@ -55,6 +49,7 @@ suite.addTest(new CacheImplJUnitTest("testEvictClass")); suite.addTest(new CacheImplJUnitTest("testEvictAll")); suite.addTest(new CacheImplJUnitTest("testEvictContains")); + suite.addTest(new CacheImplJUnitTest("testCacheAPI")); return suite; } @@ -79,13 +74,41 @@ em1.persist(e1); commitTransaction(em1); closeEntityManager(em1); - try { - boolean result = getEntityManagerFactory("default1").getCache().contains(Employee.class, 101); - assertTrue("Assertion Error",result); - } catch (Exception e) { - e.printStackTrace(); - } + boolean result = getEntityManagerFactory("default1").getCache().contains(Employee.class, 101); + assertTrue("Employee not found in cache", result); } + + /** + * Test cache API. + */ + public void testCacheAPI() { + EntityManager em = createEntityManager("default1"); + beginTransaction(em); + Employee employee = new Employee(); + employee.setFirstName("testCacheAPI"); + em.persist(employee); + commitTransaction(em); + closeEntityManager(em); + JpaCache cache = (JpaCache)getEntityManagerFactory("default1").getCache(); + assertTrue("Employee not valid in cache", cache.isValid(employee)); + assertTrue("Employee not valid in cache", cache.isValid(Employee.class, employee.getId())); + cache.timeToLive(employee); + assertTrue("Employee not found in cache", cache.getObject(Employee.class, employee.getId()) != null); + assertTrue("Employee not found in cache", cache.contains(employee)); + cache.evict(employee); + cache.putObject(employee); + cache.removeObject(employee); + cache.removeObject(Employee.class, employee.getId()); + cache.clear(); + cache.clear(Employee.class); + cache.clearQueryCache(); + cache.clearQueryCache("findAllEmployeesByIdAndFirstName"); + assertTrue("Employee id not correct", employee.getId().equals(cache.getId(employee))); + cache.print(); + cache.print(Employee.class); + cache.printLocks(); + cache.validate(); + } /** * Test of evict method, of class CacheImpl. @@ -111,8 +134,6 @@ Employee e3 = em4.find(Employee.class, 121); afterCache = e3.getFirstName(); assertNotSame("Assertion Error", beforeCache, afterCache); - } catch (Exception e) { - e.printStackTrace(); } finally { closeEntityManager(em3); closeEntityManager(em4); @@ -141,8 +162,6 @@ Employee e5 = em7.find(Employee.class, 131); String actual = e5.getFirstName(); assertNotSame("Assertion Error", expected, actual); - } catch (Exception e) { - e.printStackTrace(); } finally { closeEntityManager(em6); closeEntityManager(em7); @@ -180,8 +199,6 @@ String actualDept = d2.getName(); assertEquals("Assertion Error", expectedEmp, actualEmp); assertEquals("Assertion Error", expectedDept, actualDept); - } catch (Exception e) { - e.printStackTrace(); } finally { closeEntityManager(em9); } @@ -196,7 +213,7 @@ em.persist(emp); commitTransaction(em); - try{ + try { assertTrue(em.getEntityManagerFactory().getCache().contains(Employee.class, emp.getId())); em.clear(); @@ -206,7 +223,7 @@ em.getEntityManagerFactory().getCache().evict(Employee.class, emp.getId()); assertFalse(em.getEntityManagerFactory().getCache().contains(Employee.class, emp.getId())); } finally { - this.closeEntityManager(em); + closeEntityManager(em); } } Index: jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/jpql/AdvancedQueryTestSuite.java =================================================================== --- jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/jpql/AdvancedQueryTestSuite.java (revision 6403) +++ jpa/eclipselink.jpa.test/src/org/eclipse/persistence/testing/tests/jpa/jpql/AdvancedQueryTestSuite.java (working copy) @@ -26,7 +26,6 @@ import javax.persistence.EntityManager; import javax.persistence.RollbackException; -import junit.framework.Assert; import junit.framework.Test; import junit.framework.TestSuite; @@ -39,6 +38,7 @@ import org.eclipse.persistence.descriptors.invalidation.DailyCacheInvalidationPolicy; import org.eclipse.persistence.descriptors.invalidation.TimeToLiveCacheInvalidationPolicy; import org.eclipse.persistence.internal.sessions.AbstractSession; +import org.eclipse.persistence.jpa.JpaCache; import org.eclipse.persistence.jpa.JpaQuery; import org.eclipse.persistence.queries.Cursor; import org.eclipse.persistence.queries.ReadQuery; @@ -49,6 +49,7 @@ import org.eclipse.persistence.testing.framework.junit.JUnitTestCase; import org.eclipse.persistence.testing.framework.QuerySQLTracker; import org.eclipse.persistence.testing.models.jpa.advanced.Employee; +import org.eclipse.persistence.testing.models.jpa.advanced.Address; import org.eclipse.persistence.testing.models.jpa.advanced.EmployeePopulator; import org.eclipse.persistence.testing.models.jpa.advanced.AdvancedTableCreator; @@ -745,7 +746,7 @@ if (!(readQuery.getQueryResultsCachePolicy().getCacheInvalidationPolicy() instanceof TimeToLiveCacheInvalidationPolicy)) { fail("Query cache invalidation not set."); } - if (((TimeToLiveCacheInvalidationPolicy)readQuery.getQueryResultsCachePolicy().getCacheInvalidationPolicy()).getTimeToLive() != 5000) { + if (((TimeToLiveCacheInvalidationPolicy)readQuery.getQueryResultsCachePolicy().getCacheInvalidationPolicy()).getTimeToLive() != 50000) { fail("Query cache invalidation time not set."); } @@ -772,8 +773,37 @@ // Query by primary key. Query query = em.createNamedQuery("CachedAllEmployees"); if (result.size() != query.getResultList().size()) { + fail("List result size is not correct on 2nd cached query."); + } + if (counter.getSqlStatements().size() > 0) { + fail("Query cache was not used: " + counter.getSqlStatements()); + } + ((JpaCache)getEntityManagerFactory().getCache()).clearQueryCache(); + // Preload uow to test query cache in uow. + em.createQuery("Select e from Employee e").getResultList(); + query.getResultList(); + if (result.size() != query.getResultList().size()) { + fail("List result size is not correct on cached query in unit of work."); + } + ((JpaCache)getEntityManagerFactory().getCache()).clearQueryCache(); + // Also test query cache in early transaction. + em.persist(new Address()); + em.flush(); + query.getResultList(); + if (result.size() != query.getResultList().size()) { + fail("List result size is not correct on cached query in transaction."); + } + // Query by primary key. + query = em.createNamedQuery("CachedNoEmployees"); + if (!query.getResultList().isEmpty()) { fail("List result size is not correct."); } + // Also test empty query cache. + counter.remove(); + counter = new QuerySQLTracker(getServerSession()); + if (!query.getResultList().isEmpty()) { + fail("List result size is not correct."); + } if (counter.getSqlStatements().size() > 0) { fail("Query cache was not used: " + counter.getSqlStatements()); } @@ -1310,8 +1340,6 @@ } public void testLockWithSecondaryTable() { - ServerSession session = JUnitTestCase.getServerSession(); - // Cannot create parallel entity managers in the server. if (! isOnServer() && isSelectForUpateSupported()) { EntityManager em = createEntityManager(); @@ -1361,8 +1389,6 @@ } public void testVersionChangeWithReadLock() { - ServerSession session = JUnitTestCase.getServerSession(); - // It's a JPA2.0 feature. if (! isJPA10() && isSelectForUpateNoWaitSupported()){ Employee employee = null; @@ -1440,8 +1466,6 @@ } public void testVersionChangeWithWriteLock() { - ServerSession session = JUnitTestCase.getServerSession(); - // It's a JPA2.0 feature if (! isJPA10() && isSelectForUpateNoWaitSupported()) { Employee employee = null; Index: jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/CacheImpl.java =================================================================== --- jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/CacheImpl.java (revision 6406) +++ jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/CacheImpl.java (working copy) @@ -12,9 +12,9 @@ ******************************************************************************/ package org.eclipse.persistence.internal.jpa; -import javax.persistence.Cache; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.internal.identitymaps.CacheKey; +import org.eclipse.persistence.jpa.JpaCache; import org.eclipse.persistence.sessions.IdentityMapAccessor; import org.eclipse.persistence.sessions.server.ServerSession; @@ -22,7 +22,7 @@ * Implements the JPA Cache interface using the EclipseLink cache API through IdentityMapAccessor. * @author DaraniY */ -public class CacheImpl implements Cache { +public class CacheImpl implements JpaCache { private IdentityMapAccessor accessor; private EntityManagerFactoryImpl emf; @@ -34,34 +34,224 @@ this.serversession = emf.getServerSession(); } - public boolean contains(Class cls, Object primaryKey) { + /** + * Returns true if the cache contains an Object with the id and Class type, and is valid. + */ + public boolean contains(Class cls, Object id) { this.emf.verifyOpen(); - Object pk = createPrimaryKeyFromId(cls, primaryKey); + Object pk = createPrimaryKeyFromId(cls, id); ClassDescriptor descriptor = this.serversession.getDescriptor(cls); CacheKey key = ((org.eclipse.persistence.internal.sessions.IdentityMapAccessor)this.accessor).getCacheKeyForObject(pk, cls, descriptor); return (key != null) && (key.getObject() != null) && (!descriptor.getCacheInvalidationPolicy().isInvalidated(key)); } - public void evict(Class cls, Object primaryKey) { + /** + * Sets an Object with the id and Class type to be invalid in the cache. + */ + public void evict(Class cls, Object id) { this.emf.verifyOpen(); - this.accessor.invalidateObject(createPrimaryKeyFromId(cls, primaryKey), cls); + this.accessor.invalidateObject(createPrimaryKeyFromId(cls, id), cls); } + /** + * Sets all instances of the class to be invalid. + */ public void evict(Class cls) { this.emf.verifyOpen(); this.accessor.invalidateClass(cls); } + /** + * Sets all instances in the cache to be invalid. + */ public void evictAll() { this.emf.verifyOpen(); this.accessor.invalidateAll(); } - private Object createPrimaryKeyFromId(Class cls, Object primaryKey){ - ClassDescriptor cdesc = this.serversession.getDescriptor(cls); - CMP3Policy cmp = (CMP3Policy) (cdesc.getCMPPolicy()); - Object pk = cmp.createPrimaryKeyFromId(primaryKey, this.serversession); - return pk; + /** + * Return the EclipseLink cache key object from the JPA Id object. + */ + private Object createPrimaryKeyFromId(Class cls, Object id) { + CMP3Policy policy = (CMP3Policy)this.serversession.getDescriptor(cls).getCMPPolicy(); + Object primaryKey = policy.createPrimaryKeyFromId(id, this.serversession); + return primaryKey; } + + /** + * ADVANCED: + * Resets the entire Object cache, and the Query cache. + *

NOTE: Be careful using this method. This method blows away both this session's and its parent's caches. + * This includes the server cache or any other cache. This throws away any Objects that have been read in. + * Extreme caution should be used before doing this because Object identity will no longer + * be maintained for any Objects currently read in. This should only be called + * if the application knows that it no longer has references to Objects held in the cache. + */ + public void clear() { + this.emf.verifyOpen(); + this.accessor.initializeAllIdentityMaps(); + } + + /** + * ADVANCED: + * Resets the cache for only the instances of the given Class type. + * For inheritance the user must make sure that they only use the root class, + * clearing a subclass cache is not allowed (as they share their parents cache). + *

NOTE: Caution must be used in doing this to ensure that the Objects within the cache + * are not referenced from other Objects of other classes or from the application. + */ + public void clear(Class cls) { + this.emf.verifyOpen(); + this.accessor.initializeIdentityMap(cls); + } + + /** + * Clear all the query caches. + */ + public void clearQueryCache() { + this.emf.verifyOpen(); + this.accessor.clearQueryCache(); + } + + /** + * Clear the named query cache associated with the query name. + */ + public void clearQueryCache(String queryName) { + this.emf.verifyOpen(); + this.accessor.clearQueryCache(queryName); + } + + /** + * Returns the remaining life of the given Object (in milliseconds). This method is associated with use of + * cache invalidation feature and returns the difference between the next expiry + * time of the Object and its read time. The method will return 0 for invalidated Objects. + */ + public long timeToLive(Object object) { + this.emf.verifyOpen(); + return this.accessor.getRemainingValidTime(object); + } + + /** + * Returns true if the Object with the same id and Class type of the + * the given Object is valid in the cache. + */ + public boolean isValid(Object object) { + this.emf.verifyOpen(); + return this.accessor.isValid(object); + } + + /** + * Returns true if the Object with the id and Class type is valid in the cache. + */ + public boolean isValid(Class cls, Object id) { + this.emf.verifyOpen(); + return this.accessor.isValid(createPrimaryKeyFromId(cls, id), cls); + } + + /** + * Used to print all the Objects in the cache. + * The output of this method will be logged to this persistence unit's SessionLog at SEVERE level. + */ + public void print() { + this.emf.verifyOpen(); + this.accessor.printIdentityMaps(); + } + + /** + * Used to print all the Objects in the cache of the Class type. + * The output of this method will be logged to this persistence unit's SessionLog at SEVERE level. + */ + public void print(Class cls) { + this.emf.verifyOpen(); + this.accessor.printIdentityMap(cls); + } + + /** + * Used to print all the currently locked cache keys in the cache. + * The output of this method will be logged to this persistence unit's SessionLog at SEVERE level. + */ + public void printLocks() { + this.emf.verifyOpen(); + this.accessor.printIdentityMapLocks(); + } + + /** + * This can be used to help debugging an Object identity problem. + * An Object identity problem is when an Object in the cache references an + * Object that is not in the cache. This method will validate that all cached + * Objects are in a correct state. + */ + public void validate() { + this.emf.verifyOpen(); + this.accessor.validateCache(); + } + + /** + * Returns the Object from the cache map with the id + * and Class type. + */ + public Object getObject(Class cls, Object id) { + this.emf.verifyOpen(); + return this.accessor.getFromIdentityMap(createPrimaryKeyFromId(cls, id), cls); + } + + /** + * ADVANCED: + * Puts the given Object into the cache. + * This is a very advanced method, and caution should be used in adding objects to the cache + * as other objects may have relationships to previous object, or this object may have + * relationships to other objects. + */ + public Object putObject(Object object) { + this.emf.verifyOpen(); + return this.accessor.putInIdentityMap(object); + } + + /** + * ADVANCED: + * Removes the Object from the cache. + *

NOTE: Caution should be used when calling to avoid violating Object identity. + * The application should only call this if its known that no references to the Object exist. + */ + public Object removeObject(Object object) { + this.emf.verifyOpen(); + return this.accessor.removeFromIdentityMap(object); + } + + /** + * ADVANCED: + * Removes the Object with the id and Class type from the cache. + *

NOTE: Caution should be used when calling to avoid violating Object identity. + * The application should only call this if its known that no references to the Object exist. + */ + public Object removeObject(Class cls, Object id) { + this.emf.verifyOpen(); + return this.accessor.removeFromIdentityMap(createPrimaryKeyFromId(cls, id), cls); + } + + /** + * Returns true if the cache contains an Object with the same id and Class type of the given object. + */ + public boolean contains(Object object) { + return contains(object.getClass(), getId(object)); + } + + /** + * Sets the object to be invalid in the cache. + */ + public void evict(Object object) { + this.emf.verifyOpen(); + this.accessor.invalidateObject(object); + } + + /** + * Returns the object's Id. + */ + public Object getId(Object object) { + this.emf.verifyOpen(); + ClassDescriptor cdesc = this.serversession.getDescriptor(object.getClass()); + CMP3Policy policy = (CMP3Policy) (cdesc.getCMPPolicy()); + return policy.createPrimaryKeyInstance(object, this.serversession); + } } Index: jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/EntityManagerFactoryImpl.java =================================================================== --- jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/EntityManagerFactoryImpl.java (revision 6403) +++ jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/internal/jpa/EntityManagerFactoryImpl.java (working copy) @@ -52,586 +52,601 @@ * * @author gyorke * @since TopLink Essentials - JPA 1.0 - * - * 03/19/2009-2.0 Michael O'Brien - * - 266912: JPA 2.0 Metamodel API (part of the JSR-317 EJB 3.1 Criteria API) - */ + * + * 03/19/2009-2.0 Michael O'Brien - 266912: JPA 2.0 Metamodel API (part + * of the JSR-317 EJB 3.1 Criteria API) + */ public class EntityManagerFactoryImpl implements EntityManagerFactory, PersistenceUnitUtil { - /** Reference to Cache Interface. */ - protected Cache myCache; - /** Reference to the ServerSession for this deployment. */ - protected volatile ServerSession serverSession; - /** EntityManagerSetupImpl that deployed this factory. */ - protected EntityManagerSetupImpl setupImpl; - /** Stores if closed has been called. */ - protected boolean isOpen = true; - /** Persistence unit properties from create factory. */ - protected Map properties; + /** Reference to Cache Interface. */ + protected Cache myCache; + /** Reference to the ServerSession for this deployment. */ + protected volatile ServerSession serverSession; + /** EntityManagerSetupImpl that deployed this factory. */ + protected EntityManagerSetupImpl setupImpl; + /** Stores if closed has been called. */ + protected boolean isOpen = true; + /** Persistence unit properties from create factory. */ + protected Map properties; - /** - * INTERNAL: - * The following properties passed to createEMF cached and processed on the emf directly. - * None of these properties processed during predeploy or deploy. + /** + * INTERNAL: The following properties passed to createEMF cached and + * processed on the emf directly. None of these properties processed during + * predeploy or deploy. **/ - protected static final Set supportedNonServerSessionProperties = PersistenceUnitProperties.getSupportedNonServerSessionProperties(); - - /** - * Default join existing transaction property, allows reading through write - * connection. - */ - protected boolean beginEarlyTransaction; + protected static final Set supportedNonServerSessionProperties = PersistenceUnitProperties.getSupportedNonServerSessionProperties(); - /** Default property, allows flush before query to be avoided. */ - protected FlushModeType flushMode = FlushModeType.AUTO; + /** + * Default join existing transaction property, allows reading through write + * connection. + */ + protected boolean beginEarlyTransaction; - /** Default property, allows weak unit of work references. */ - protected ReferenceMode referenceMode = ReferenceMode.HARD; + /** Default property, allows flush before query to be avoided. */ + protected FlushModeType flushMode = FlushModeType.AUTO; - /** - * Default property to avoid resuming unit of work if going to be closed on - * commit anyway. - */ - protected boolean closeOnCommit; + /** Default property, allows weak unit of work references. */ + protected ReferenceMode referenceMode = ReferenceMode.HARD; - /** - * Default property to avoid discover new objects in unit of work if - * application always uses persist. - */ - protected boolean persistOnCommit = true; + /** + * Default property to avoid resuming unit of work if going to be closed on + * commit anyway. + */ + protected boolean closeOnCommit; - /** - * Default FlashClearCache mode to be used. Relevant only in case call to - * flush method followed by call to clear method. - * - * @see org.eclipse.persistence.config.FlushClearCache - */ - protected String flushClearCache = FlushClearCache.DEFAULT; + /** + * Default property to avoid discover new objects in unit of work if + * application always uses persist. + */ + protected boolean persistOnCommit = true; - /** Default to determine if does-exist should be performed on persist. */ - protected boolean shouldValidateExistence; - protected boolean commitWithoutPersistRules; + /** + * Default FlashClearCache mode to be used. Relevant only in case call to + * flush method followed by call to clear method. + * + * @see org.eclipse.persistence.config.FlushClearCache + */ + protected String flushClearCache = FlushClearCache.DEFAULT; - /** - * Will return an instance of the Factory. Should only be called by - * EclipseLink. - * - * @param serverSession - */ - public EntityManagerFactoryImpl(ServerSession serverSession) { - this.serverSession = serverSession; - processProperties(serverSession.getProperties()); - } + /** Default to determine if does-exist should be performed on persist. */ + protected boolean shouldValidateExistence; + protected boolean commitWithoutPersistRules; - public EntityManagerFactoryImpl(EntityManagerSetupImpl setupImpl, Map properties) { - this.setupImpl = setupImpl; - this.properties = properties; - } + /** + * Will return an instance of the Factory. Should only be called by + * EclipseLink. + * + * @param serverSession + */ + public EntityManagerFactoryImpl(ServerSession serverSession) { + this.serverSession = serverSession; + processProperties(serverSession.getProperties()); + } - /** - * INTERNAL: Returns the ServerSession that the Factory will be using and - * initializes it if it is not available. This method makes use of the - * partially constructed session stored in our setupImpl and completes its - * construction - */ - public ServerSession getServerSession() { - if (this.serverSession == null) { - // PERF: Avoid synchronization. - synchronized (this) { - // DCL ok as isLoggedIn is volatile boolean, set after login is - // complete. - if (this.serverSession == null) { - ClassLoader realLoader = setupImpl.getPersistenceUnitInfo().getClassLoader(); - // splitProperties[0] contains supportedNonServerSessionProperties; [1] - all the rest. - Map[] splitProperties = EntityManagerFactoryProvider.splitSpecifiedProperties(properties, supportedNonServerSessionProperties); - // keep only non server session properties - the rest will be either cached in the server session or ignored - properties = splitProperties[0]; - Map serverSessionProperties = splitProperties[1]; - // the call top setupImpl.deploy() finishes the session - // creation - ServerSession tempServerSession = setupImpl.deploy(realLoader, serverSessionProperties); - // discard all but non server session properties from server session properties. - Map tempProperties = EntityManagerFactoryProvider.keepSpecifiedProperties(tempServerSession.getProperties(), supportedNonServerSessionProperties); - // properties override server session properties - Map propertiesToProcess = EntityManagerFactoryProvider.mergeMaps(properties, tempProperties); - processProperties(propertiesToProcess); - this.serverSession = tempServerSession; - } - } - } - return this.serverSession; - } + public EntityManagerFactoryImpl(EntityManagerSetupImpl setupImpl, Map properties) { + this.setupImpl = setupImpl; + this.properties = properties; + } - /** - * Closes this factory, releasing any resources that might be held by this - * factory. After invoking this method, all methods on the instance will - * throw an {@link IllegalStateException}, except for {@link #isOpen}, which - * will return false. - */ - public synchronized void close() { - verifyOpen(); - isOpen = false; - // Do not invalidate the metaModel field + /** + * INTERNAL: Returns the ServerSession that the Factory will be using and + * initializes it if it is not available. This method makes use of the + * partially constructed session stored in our setupImpl and completes its + * construction + */ + public ServerSession getServerSession() { + if (this.serverSession == null) { + // PERF: Avoid synchronization. + synchronized (this) { + // DCL ok as isLoggedIn is volatile boolean, set after login is + // complete. + if (this.serverSession == null) { + ClassLoader realLoader = setupImpl.getPersistenceUnitInfo().getClassLoader(); + // splitProperties[0] contains + // supportedNonServerSessionProperties; [1] - all the rest. + Map[] splitProperties = EntityManagerFactoryProvider.splitSpecifiedProperties(properties, supportedNonServerSessionProperties); + // keep only non server session properties - the rest will + // be either cached in the server session or ignored + properties = splitProperties[0]; + Map serverSessionProperties = splitProperties[1]; + // the call top setupImpl.deploy() finishes the session + // creation + ServerSession tempServerSession = setupImpl.deploy(realLoader, serverSessionProperties); + // discard all but non server session properties from server + // session properties. + Map tempProperties = EntityManagerFactoryProvider.keepSpecifiedProperties(tempServerSession.getProperties(), supportedNonServerSessionProperties); + // properties override server session properties + Map propertiesToProcess = EntityManagerFactoryProvider.mergeMaps(properties, tempProperties); + processProperties(propertiesToProcess); + this.serverSession = tempServerSession; + } + } + } + return this.serverSession; + } + + /** + * Closes this factory, releasing any resources that might be held by this + * factory. After invoking this method, all methods on the instance will + * throw an {@link IllegalStateException}, except for {@link #isOpen}, which + * will return false. + */ + public synchronized void close() { + verifyOpen(); + isOpen = false; + // Do not invalidate the metaModel field // (a reopened emf will re-populate the same metaModel) // (a new persistence unit will generate a new metaModel) - if (setupImpl != null) { - // 260511 null check so that closing a EM - // created from the constructor no longer throws a NPE - setupImpl.undeploy(); - } - } + if (setupImpl != null) { + // 260511 null check so that closing a EM + // created from the constructor no longer throws a NPE + setupImpl.undeploy(); + } + } - /** - * Indicates whether or not this factory is open. Returns true - * until a call to {@link #close} is made. - */ - public boolean isOpen() { - return isOpen; - } + /** + * Indicates whether or not this factory is open. Returns true + * until a call to {@link #close} is made. + */ + public boolean isOpen() { + return isOpen; + } - /** - * PUBLIC: Returns an EntityManager for this deployment. - */ - public EntityManager createEntityManager() { - return createEntityManagerImpl(null); - } + /** + * PUBLIC: Returns an EntityManager for this deployment. + */ + public EntityManager createEntityManager() { + return createEntityManagerImpl(null); + } - /** - * PUBLIC: Returns an EntityManager for this deployment. - */ - public EntityManager createEntityManager(Map properties) { - return createEntityManagerImpl(properties); - } + /** + * PUBLIC: Returns an EntityManager for this deployment. + */ + public EntityManager createEntityManager(Map properties) { + return createEntityManagerImpl(properties); + } - protected EntityManagerImpl createEntityManagerImpl(Map properties) { - verifyOpen(); - ServerSession session = getServerSession(); - if (!session.isLoggedIn()) { - // PERF: Avoid synchronization. - synchronized (session) { - // DCL ok as isLoggedIn is volatile boolean, set after login is - // complete. - if (!session.isLoggedIn()) { - session.login(); - } - } - } - return new EntityManagerImpl(this, properties); - } + protected EntityManagerImpl createEntityManagerImpl(Map properties) { + verifyOpen(); + ServerSession session = getServerSession(); + if (!session.isLoggedIn()) { + // PERF: Avoid synchronization. + synchronized (session) { + // DCL ok as isLoggedIn is volatile boolean, set after login is + // complete. + if (!session.isLoggedIn()) { + session.login(); + } + } + } + return new EntityManagerImpl(this, properties); + } - protected void verifyOpen() { - if (!this.isOpen) { - throw new IllegalStateException(ExceptionLocalization.buildMessage("operation_on_closed_entity_manager_factory")); - } - } + protected void verifyOpen() { + if (!this.isOpen) { + throw new IllegalStateException(ExceptionLocalization.buildMessage("operation_on_closed_entity_manager_factory")); + } + } - protected void finalize() throws Throwable { - if (isOpen()) { - close(); - } - } + protected void finalize() throws Throwable { + if (isOpen()) { + close(); + } + } - /** - * The method return user defined property passed in from - * EntityManagerFactory. - */ - public Object getProperty(String name) { - if (name == null) { - return null; - } - if(properties != null) { - Object value = properties.get(name); - if(value != null) { - return value; - } - } - return getServerSession().getProperty(name); - } + /** + * The method return user defined property passed in from + * EntityManagerFactory. + */ + public Object getProperty(String name) { + if (name == null) { + return null; + } + if (properties != null) { + Object value = properties.get(name); + if (value != null) { + return value; + } + } + return getServerSession().getProperty(name); + } - /** - * Process all EntityManager properties. This allows all EntityManager - * properties specified in the persistence.xml, factory properties, or - * System properties to be preprocessed. This save the cost of processing - * these properties each time an EntityManager is created, which can add - * considerable overhead to both performance and concurrency as System - * properties are a Hashtable and synchronized. - * ATTENTION: - * If you add a new property to be processed in this method please also add - * the property's name to PersistenceUnitProperties.supportedNonServerSessionProperties - */ - protected void processProperties(Map properties) { - String beginEarlyTransactionProperty = PropertiesHandler.getPropertyValueLogDebug(EntityManagerProperties.JOIN_EXISTING_TRANSACTION, properties, this.serverSession, true); - if (beginEarlyTransactionProperty != null) { - this.beginEarlyTransaction = "true".equalsIgnoreCase(beginEarlyTransactionProperty); - } - String referenceMode = PropertiesHandler.getPropertyValueLogDebug(EntityManagerProperties.PERSISTENCE_CONTEXT_REFERENCE_MODE, properties, this.serverSession, true); - if (referenceMode != null) { - this.referenceMode = ReferenceMode.valueOf(referenceMode); - } - String flushMode = PropertiesHandler.getPropertyValueLogDebug(EntityManagerProperties.PERSISTENCE_CONTEXT_FLUSH_MODE, properties, this.serverSession, true); - if (flushMode != null) { - this.flushMode = FlushModeType.valueOf(flushMode); - } - String closeOnCommit = PropertiesHandler.getPropertyValueLogDebug(EntityManagerProperties.PERSISTENCE_CONTEXT_CLOSE_ON_COMMIT, properties, this.serverSession, true); - if (closeOnCommit != null) { - this.closeOnCommit = "true".equalsIgnoreCase(closeOnCommit); - } - String persistOnCommit = PropertiesHandler.getPropertyValueLogDebug(EntityManagerProperties.PERSISTENCE_CONTEXT_PERSIST_ON_COMMIT, properties, this.serverSession, true); - if (persistOnCommit != null) { - this.persistOnCommit = "true".equalsIgnoreCase(persistOnCommit); - } + /** + * Process all EntityManager properties. This allows all EntityManager + * properties specified in the persistence.xml, factory properties, or + * System properties to be preprocessed. This save the cost of processing + * these properties each time an EntityManager is created, which can add + * considerable overhead to both performance and concurrency as System + * properties are a Hashtable and synchronized. ATTENTION: If you add a new + * property to be processed in this method please also add the property's + * name to PersistenceUnitProperties.supportedNonServerSessionProperties + */ + protected void processProperties(Map properties) { + String beginEarlyTransactionProperty = PropertiesHandler.getPropertyValueLogDebug(EntityManagerProperties.JOIN_EXISTING_TRANSACTION, properties, this.serverSession, true); + if (beginEarlyTransactionProperty != null) { + this.beginEarlyTransaction = "true".equalsIgnoreCase(beginEarlyTransactionProperty); + } + String referenceMode = PropertiesHandler.getPropertyValueLogDebug(EntityManagerProperties.PERSISTENCE_CONTEXT_REFERENCE_MODE, properties, this.serverSession, true); + if (referenceMode != null) { + this.referenceMode = ReferenceMode.valueOf(referenceMode); + } + String flushMode = PropertiesHandler.getPropertyValueLogDebug(EntityManagerProperties.PERSISTENCE_CONTEXT_FLUSH_MODE, properties, this.serverSession, true); + if (flushMode != null) { + this.flushMode = FlushModeType.valueOf(flushMode); + } + String closeOnCommit = PropertiesHandler.getPropertyValueLogDebug(EntityManagerProperties.PERSISTENCE_CONTEXT_CLOSE_ON_COMMIT, properties, this.serverSession, true); + if (closeOnCommit != null) { + this.closeOnCommit = "true".equalsIgnoreCase(closeOnCommit); + } + String persistOnCommit = PropertiesHandler.getPropertyValueLogDebug(EntityManagerProperties.PERSISTENCE_CONTEXT_PERSIST_ON_COMMIT, properties, this.serverSession, true); + if (persistOnCommit != null) { + this.persistOnCommit = "true".equalsIgnoreCase(persistOnCommit); + } String commitWithoutPersist = PropertiesHandler.getPropertyValueLogDebug(EntityManagerProperties.PERSISTENCE_CONTEXT_COMMIT_WITHOUT_PERSIST_RULES, properties, this.serverSession, true); if (commitWithoutPersist != null) { this.commitWithoutPersistRules = "true".equalsIgnoreCase(commitWithoutPersist); } - String shouldValidateExistence = PropertiesHandler.getPropertyValueLogDebug(EntityManagerProperties.VALIDATE_EXISTENCE, properties, this.serverSession, true); - if (shouldValidateExistence != null) { - this.shouldValidateExistence = "true".equalsIgnoreCase(shouldValidateExistence); - } - String flushClearCache = PropertiesHandler.getPropertyValueLogDebug(EntityManagerProperties.FLUSH_CLEAR_CACHE, properties, this.serverSession, true); - if (flushClearCache != null) { - this.flushClearCache = flushClearCache; - } - } + String shouldValidateExistence = PropertiesHandler.getPropertyValueLogDebug(EntityManagerProperties.VALIDATE_EXISTENCE, properties, this.serverSession, true); + if (shouldValidateExistence != null) { + this.shouldValidateExistence = "true".equalsIgnoreCase(shouldValidateExistence); + } + String flushClearCache = PropertiesHandler.getPropertyValueLogDebug(EntityManagerProperties.FLUSH_CLEAR_CACHE, properties, this.serverSession, true); + if (flushClearCache != null) { + this.flushClearCache = flushClearCache; + } + } - /** - * Return default join existing transaction property, allows reading through - * write connection. - */ - public boolean getBeginEarlyTransaction() { - return beginEarlyTransaction; - } + /** + * Return default join existing transaction property, allows reading through + * write connection. + */ + public boolean getBeginEarlyTransaction() { + return beginEarlyTransaction; + } - /** - * Set default join existing transaction property, allows reading through - * write connection. - */ - public void setBeginEarlyTransaction(boolean beginEarlyTransaction) { - this.beginEarlyTransaction = beginEarlyTransaction; - } + /** + * Set default join existing transaction property, allows reading through + * write connection. + */ + public void setBeginEarlyTransaction(boolean beginEarlyTransaction) { + this.beginEarlyTransaction = beginEarlyTransaction; + } - /** - * Return default property, allows flush before query to be avoided. - */ - public FlushModeType getFlushMode() { - return flushMode; - } + /** + * Return default property, allows flush before query to be avoided. + */ + public FlushModeType getFlushMode() { + return flushMode; + } - /** - * Set default property, allows flush before query to be avoided. - */ - public void setFlushMode(FlushModeType flushMode) { - this.flushMode = flushMode; - } + /** + * Set default property, allows flush before query to be avoided. + */ + public void setFlushMode(FlushModeType flushMode) { + this.flushMode = flushMode; + } - /** - * Return default property, allows weak unit of work references. - */ - public ReferenceMode getReferenceMode() { - return referenceMode; - } + /** + * Return default property, allows weak unit of work references. + */ + public ReferenceMode getReferenceMode() { + return referenceMode; + } - /** - * Set default property, allows weak unit of work references. - */ - public void setReferenceMode(ReferenceMode referenceMode) { - this.referenceMode = referenceMode; - } + /** + * Set default property, allows weak unit of work references. + */ + public void setReferenceMode(ReferenceMode referenceMode) { + this.referenceMode = referenceMode; + } - /** - * Return default property to avoid resuming unit of work if going to be - * closed on commit anyway. - */ - public boolean getCloseOnCommit() { - return closeOnCommit; - } + /** + * Return default property to avoid resuming unit of work if going to be + * closed on commit anyway. + */ + public boolean getCloseOnCommit() { + return closeOnCommit; + } - /** - * Set default property to avoid resuming unit of work if going to be closed - * on commit anyway. - */ - public void setCloseOnCommit(boolean closeOnCommit) { - this.closeOnCommit = closeOnCommit; - } + /** + * Set default property to avoid resuming unit of work if going to be closed + * on commit anyway. + */ + public void setCloseOnCommit(boolean closeOnCommit) { + this.closeOnCommit = closeOnCommit; + } - /** - * Return default property to avoid discover new objects in unit of work if - * application always uses persist. - */ - public boolean getPersistOnCommit() { - return persistOnCommit; - } + /** + * Return default property to avoid discover new objects in unit of work if + * application always uses persist. + */ + public boolean getPersistOnCommit() { + return persistOnCommit; + } /** - * Return interface providing access to utility methods - * for the persistence unit. + * Return interface providing access to utility methods for the persistence + * unit. + * * @return PersistenceUnitUtil interface - * @throws IllegalStateException if the entity manager factory - * has been closed. + * @throws IllegalStateException + * if the entity manager factory has been closed. */ - public PersistenceUnitUtil getPersistenceUnitUtil(){ + public PersistenceUnitUtil getPersistenceUnitUtil() { return this; } /** - * Set default property to avoid discover new objects in unit of work if - * application always uses persist. - */ - public void setPersistOnCommit(boolean persistOnCommit) { - this.persistOnCommit = persistOnCommit; - } + * Set default property to avoid discover new objects in unit of work if + * application always uses persist. + */ + public void setPersistOnCommit(boolean persistOnCommit) { + this.persistOnCommit = persistOnCommit; + } /** - * Return default property to avoid discover new objects in unit of work if application always uses persist. + * Return default property to avoid discover new objects in unit of work if + * application always uses persist. */ public boolean getCommitWithoutPersistRules() { return commitWithoutPersistRules; } - + /** - * Set default property to avoid discover new objects in unit of work if application always uses persist. + * Set default property to avoid discover new objects in unit of work if + * application always uses persist. */ public void setCommitWithoutPersistRules(boolean commitWithoutPersistRules) { this.commitWithoutPersistRules = commitWithoutPersistRules; } + /** - * Return the default FlashClearCache mode to be used. - * Relevant only in case call to flush method followed by call to clear method. - * @see org.eclipse.persistence.config.FlushClearCache - */ - public String getFlushClearCache() { - return flushClearCache; - } + * Return the default FlashClearCache mode to be used. Relevant only in case + * call to flush method followed by call to clear method. + * + * @see org.eclipse.persistence.config.FlushClearCache + */ + public String getFlushClearCache() { + return flushClearCache; + } - /** - * Set the default FlashClearCache mode to be used. Relevant only in case - * call to flush method followed by call to clear method. - * - * @see org.eclipse.persistence.config.FlushClearCache - */ - public void setFlushClearCache(String flushClearCache) { - this.flushClearCache = flushClearCache; - } + /** + * Set the default FlashClearCache mode to be used. Relevant only in case + * call to flush method followed by call to clear method. + * + * @see org.eclipse.persistence.config.FlushClearCache + */ + public void setFlushClearCache(String flushClearCache) { + this.flushClearCache = flushClearCache; + } - /** - * Return the default to determine if does-exist should be performed on - * persist. - */ - public boolean shouldValidateExistence() { - return shouldValidateExistence; - } + /** + * Return the default to determine if does-exist should be performed on + * persist. + */ + public boolean shouldValidateExistence() { + return shouldValidateExistence; + } - /** - * Set the default to determine if does-exist should be performed on - * persist. - */ - public void setShouldValidateExistence(boolean shouldValidateExistence) { - this.shouldValidateExistence = shouldValidateExistence; - } + /** + * Set the default to determine if does-exist should be performed on + * persist. + */ + public void setShouldValidateExistence(boolean shouldValidateExistence) { + this.shouldValidateExistence = shouldValidateExistence; + } - public Cache getCache() { - verifyOpen(); - if (myCache == null) { - ServerSession session = this.getServerSession(); - myCache = new CacheImpl(this, session.getIdentityMapAccessor()); - } - return myCache; - } + public Cache getCache() { + verifyOpen(); + if (myCache == null) { + ServerSession session = this.getServerSession(); + myCache = new CacheImpl(this, session.getIdentityMapAccessor()); + } + return myCache; + } - /** - * @see javax.persistence.EntityManagerFactory#getProperties() - * @since Java Persistence API 2.0 - */ - public Map getProperties() { - if(!this.isOpen()) { - throw new IllegalStateException(ExceptionLocalization.buildMessage("operation_on_closed_entity_manager_factory")); - } - return Collections.unmodifiableMap(EntityManagerFactoryProvider.mergeMaps(properties, this.getServerSession().getProperties())); - } + /** + * @see javax.persistence.EntityManagerFactory#getProperties() + * @since Java Persistence API 2.0 + */ + public Map getProperties() { + if (!this.isOpen()) { + throw new IllegalStateException(ExceptionLocalization.buildMessage("operation_on_closed_entity_manager_factory")); + } + return Collections.unmodifiableMap(EntityManagerFactoryProvider.mergeMaps(properties, this.getServerSession().getProperties())); + } - /** - * @see javax.persistence.EntityManagerFactory#getCriteriaBuilder() - * @since Java Persistence 2.0 - */ - public CriteriaBuilder getCriteriaBuilder() { + /** + * @see javax.persistence.EntityManagerFactory#getCriteriaBuilder() + * @since Java Persistence 2.0 + */ + public CriteriaBuilder getCriteriaBuilder() { return new CriteriaBuilderImpl(this.getMetamodel()); - } + } /** - * Return an instance of Metamodel interface for access to the - * metamodel of the persistence unit. + * Return an instance of Metamodel interface for access to the metamodel of + * the persistence unit. + * * @return Metamodel instance - * @throws IllegalStateException if the entity manager factory has - * been closed. + * @throws IllegalStateException + * if the entity manager factory has been closed. * @see javax.persistence.EntityManagerFactory#getMetamodel() * @since Java Persistence 2.0 */ public Metamodel getMetamodel() { - if(!this.isOpen()) { + if (!this.isOpen()) { throw new IllegalStateException(ExceptionLocalization.buildMessage("operation_on_closed_entity_manager_factory")); } return this.setupImpl.getMetamodel(); } /** - * INTERNAL: - * Convenience function to allow us to reset the Metamodel - * in the possible case that we want to regenerate it. - * This function is outside of the JPA 2.0 specification. + * INTERNAL: Convenience function to allow us to reset the Metamodel in the + * possible case that we want to regenerate it. This function is outside of + * the JPA 2.0 specification. + * * @param aMetamodel - * @since Java Persistence 2.0 + * @since Java Persistence 2.0 */ public void setMetamodel(Metamodel aMetamodel) { - if(!this.isOpen()) { + if (!this.isOpen()) { throw new IllegalStateException(ExceptionLocalization.buildMessage("operation_on_closed_entity_manager_factory")); } this.setupImpl.setMetamodel(aMetamodel); } - + /** - * Determine the load state of a given persistent attribute - * of an entity belonging to the persistence unit. - * @param entity containing the attribute - * @param attributeName name of attribute whose load state is - * to be determined - * @return false if entity's state has not been loaded or - * if the attribute state has not been loaded, otherwise true + * Determine the load state of a given persistent attribute of an entity + * belonging to the persistence unit. + * + * @param entity + * containing the attribute + * @param attributeName + * name of attribute whose load state is to be determined + * @return false if entity's state has not been loaded or if the attribute + * state has not been loaded, otherwise true */ - public boolean isLoaded(Object entity, String attributeName){ - if (EntityManagerFactoryImpl.isLoaded(entity, attributeName, serverSession).equals(Boolean.valueOf(true))){ + public boolean isLoaded(Object entity, String attributeName) { + if (EntityManagerFactoryImpl.isLoaded(entity, attributeName, serverSession).equals(Boolean.valueOf(true))) { return true; } return false; } - + /** - * Determine the load state of an entity belonging to the - * persistence unit. - * This method can be used to determine the load state - * of an entity passed as a reference. An entity is - * considered loaded if all attributes for which FetchType - * EAGER has been specified have been loaded. - * The isLoaded(Object, String) method should be used to - * determine the load state of an attribute. - * Not doing so might lead to unintended loading of state. - * @param entity whose load state is to be determined + * Determine the load state of an entity belonging to the persistence unit. + * This method can be used to determine the load state of an entity passed + * as a reference. An entity is considered loaded if all attributes for + * which FetchType EAGER has been specified have been loaded. The + * isLoaded(Object, String) method should be used to determine the load + * state of an attribute. Not doing so might lead to unintended loading of + * state. + * + * @param entity + * whose load state is to be determined * @return false if the entity has not been loaded, else true. */ - public boolean isLoaded(Object entity){ - if (EntityManagerFactoryImpl.isLoaded(entity, serverSession).equals(Boolean.valueOf(true))){ + public boolean isLoaded(Object entity) { + if (EntityManagerFactoryImpl.isLoaded(entity, serverSession).equals(Boolean.valueOf(true))) { return true; } return false; } - + /** - * Returns the id of the entity. - * A generated id is not guaranteed to be available until after - * the database insert has occurred. - * Returns null if the entity does not yet have an id - * @param entity - * @return id of the entity - * @throws IllegalStateException if the entity is found not to be - * an entity. + * Returns the id of the entity. A generated id is not guaranteed to be + * available until after the database insert has occurred. Returns null if + * the entity does not yet have an id + * + * @param entity + * @return id of the entity + * @throws IllegalStateException + * if the entity is found not to be an entity. */ - public Object getIdentifier(Object entity){ + public Object getIdentifier(Object entity) { return EntityManagerFactoryImpl.getIdentifier(entity, serverSession); } - + /** - * Determine the load state of a given persistent attribute - * of an entity belonging to the persistence unit. - * @param entity containing the attribute - * @param attributeName name of attribute whose load state is - * to be determined - * @return false if entity's state has not been loaded or - * if the attribute state has not been loaded, otherwise true + * Determine the load state of a given persistent attribute of an entity + * belonging to the persistence unit. + * + * @param entity + * containing the attribute + * @param attributeName + * name of attribute whose load state is to be determined + * @return false if entity's state has not been loaded or if the attribute + * state has not been loaded, otherwise true */ - public static Boolean isLoaded(Object entity, String attributeName, AbstractSession session){ + public static Boolean isLoaded(Object entity, String attributeName, AbstractSession session) { ClassDescriptor descriptor = session.getDescriptor(entity); - if (descriptor == null){ + if (descriptor == null) { return null; } DatabaseMapping mapping = descriptor.getMappingForAttributeName(attributeName); - if (mapping == null){ + if (mapping == null) { return null; } return isLoaded(entity, attributeName, mapping); } - + /** - * Check whether a named attribute on a given entity with a given mapping has been loaded. + * Check whether a named attribute on a given entity with a given mapping + * has been loaded. * - * This method will check the valueholder or indirect collection for LAZY ForeignReferenceMappings - * to see if has been instantiated and otherwise check the fetch group. + * This method will check the valueholder or indirect collection for LAZY + * ForeignReferenceMappings to see if has been instantiated and otherwise + * check the fetch group. + * * @param entity * @param attributeName * @param mapping * @return */ - public static boolean isLoaded(Object entity, String attributeName, DatabaseMapping mapping){ - if (mapping.isForeignReferenceMapping()){ - if (((ForeignReferenceMapping)mapping).isLazy()){ + public static boolean isLoaded(Object entity, String attributeName, DatabaseMapping mapping) { + if (mapping.isForeignReferenceMapping()) { + if (((ForeignReferenceMapping) mapping).isLazy()) { Object value = mapping.getAttributeValueFromObject(entity); - IndirectionPolicy policy = ((ForeignReferenceMapping)mapping).getIndirectionPolicy(); + IndirectionPolicy policy = ((ForeignReferenceMapping) mapping).getIndirectionPolicy(); return policy.objectIsInstantiated(value); } } - if (entity instanceof FetchGroupTracker){ - return ((FetchGroupTracker)entity)._persistence_isAttributeFetched(attributeName); + if (entity instanceof FetchGroupTracker) { + return ((FetchGroupTracker) entity)._persistence_isAttributeFetched(attributeName); } else { return true; } } - + /** - * Determine the load state of an entity belonging to the - * persistence unit. - * This method can be used to determine the load state - * of an entity passed as a reference. An entity is - * considered loaded if all attributes for which FetchType - * EAGER has been specified have been loaded. - * The isLoaded(Object, String) method should be used to - * determine the load state of an attribute. - * Not doing so might lead to unintended loading of state. - * @param entity whose load state is to be determined + * Determine the load state of an entity belonging to the persistence unit. + * This method can be used to determine the load state of an entity passed + * as a reference. An entity is considered loaded if all attributes for + * which FetchType EAGER has been specified have been loaded. The + * isLoaded(Object, String) method should be used to determine the load + * state of an attribute. Not doing so might lead to unintended loading of + * state. + * + * @param entity + * whose load state is to be determined * @return false if the entity has not been loaded, else true. */ - public static Boolean isLoaded(Object entity, AbstractSession session){ + public static Boolean isLoaded(Object entity, AbstractSession session) { ClassDescriptor descriptor = session.getDescriptor(entity); - if (descriptor == null){ + if (descriptor == null) { return null; } List mappings = descriptor.getMappings(); Iterator i = mappings.iterator(); - while (i.hasNext()){ + while (i.hasNext()) { DatabaseMapping mapping = i.next(); - if (!mapping.isLazy() && !isLoaded(entity, mapping.getAttributeName(), mapping)){ + if (!mapping.isLazy() && !isLoaded(entity, mapping.getAttributeName(), mapping)) { return false; } } return true; } - + /** - * Returns the id of the entity. - * A generated id is not guaranteed to be available until after - * the database insert has occurred. - * Returns null if the entity does not yet have an id - * @param entity - * @return id of the entity - * @throws IllegalStateException if the entity is found not to be - * an entity. + * Returns the id of the entity. A generated id is not guaranteed to be + * available until after the database insert has occurred. Returns null if + * the entity does not yet have an id + * + * @param entity + * @return id of the entity + * @throws IllegalStateException + * if the entity is found not to be an entity. */ - public static Object getIdentifier(Object entity, AbstractSession session){ + public static Object getIdentifier(Object entity, AbstractSession session) { ClassDescriptor descriptor = session.getDescriptor(entity); - if (descriptor == null){ - throw new IllegalArgumentException(ExceptionLocalization.buildMessage("jpa_persistence_util_non_persistent_class ", new Object[]{entity})); + if (descriptor == null) { + throw new IllegalArgumentException(ExceptionLocalization.buildMessage("jpa_persistence_util_non_persistent_class ", new Object[] { entity })); } - if (descriptor.getCMPPolicy() != null){ + if (descriptor.getCMPPolicy() != null) { return descriptor.getCMPPolicy().createPrimaryKeyInstance(entity, session); } else { - throw new IllegalArgumentException(ExceptionLocalization.buildMessage("jpa_persistence_util_non_persistent_class ", new Object[]{entity})); + throw new IllegalArgumentException(ExceptionLocalization.buildMessage("jpa_persistence_util_non_persistent_class ", new Object[] { entity })); } } Index: jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/jpa/JpaCache.java =================================================================== --- jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/jpa/JpaCache.java (revision 0) +++ jpa/org.eclipse.persistence.jpa/src/org/eclipse/persistence/jpa/JpaCache.java (revision 0) @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright (c) 1998, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 + * which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * James Sutherland = 1.0 - Initial contribution + ******************************************************************************/ +package org.eclipse.persistence.jpa; + +import javax.persistence.Cache; + +/** + * Extends JPA Cache interface with additional EclipseLink API. + * @author James Sutherland + */ +public interface JpaCache extends Cache { + + /** + * ADVANCED: + * Resets the entire Object cache, and the Query cache. + *

NOTE: Be careful using this method. This method blows away both this session's and its parent's caches. + * This includes the server cache or any other cache. This throws away any Objects that have been read in. + * Extreme caution should be used before doing this because Object identity will no longer + * be maintained for any Objects currently read in. This should only be called + * if the application knows that it no longer has references to Objects held in the cache. + */ + void clear(); + + /** + * ADVANCED: + * Resets the cache for only the instances of the given Class type. + * For inheritance the user must make sure that they only use the root class, + * clearing a subclass cache is not allowed (as they share their parents cache). + *

NOTE: Caution must be used in doing this to ensure that the Objects within the cache + * are not referenced from other Objects of other classes or from the application. + */ + void clear(Class cls); + + /** + * Clear all the query caches. + */ + void clearQueryCache(); + + /** + * Clear the named query cache associated with the query name. + */ + void clearQueryCache(String queryName); + + /** + * Returns the remaining life of the given Object (in milliseconds). This method is associated with use of + * cache invalidation feature and returns the difference between the next expiry + * time of the Object and its read time. The method will return 0 for invalidated Objects. + */ + long timeToLive(Object object); + + /** + * Returns true if the Object with the same id and Class type of the + * the given Object is valid in the cache. + */ + boolean isValid(Object object); + + /** + * Returns true if the Object with the id and Class type is valid in the cache. + */ + boolean isValid(Class cls, Object id); + + /** + * Used to print all the Objects in the cache. + * The output of this method will be logged to this persistence unit's SessionLog at SEVERE level. + */ + void print(); + + /** + * Used to print all the Objects in the cache of the Class type. + * The output of this method will be logged to this persistence unit's SessionLog at SEVERE level. + */ + void print(Class cls); + + /** + * Used to print all the currently locked cache keys in the cache. + * The output of this method will be logged to this persistence unit's SessionLog at SEVERE level. + */ + void printLocks(); + + /** + * This can be used to help debugging an Object identity problem. + * An Object identity problem is when an Object in the cache references an + * Object that is not in the cache. This method will validate that all cached + * Objects are in a correct state. + */ + void validate(); + + /** + * Returns the Object from the cache map with the id + * and Class type. + */ + Object getObject(Class cls, Object id); + + /** + * ADVANCED: + * Puts the given Object into the cache. + * This is a very advanced method, and caution should be used in adding objects to the cache + * as other objects may have relationships to previous object, or this object may have + * relationships to other objects. + */ + Object putObject(Object object); + + /** + * ADVANCED: + * Removes the Object from the cache. + *

NOTE: Caution should be used when calling to avoid violating Object identity. + * The application should only call this if its known that no references to the Object exist. + */ + Object removeObject(Object object); + + /** + * ADVANCED: + * Removes the Object with the id and Class type from the cache. + *

NOTE: Caution should be used when calling to avoid violating Object identity. + * The application should only call this if its known that no references to the Object exist. + */ + Object removeObject(Class cls, Object id); + + /** + * Returns true if the cache contains an Object with the same id and Class type of the given object. + */ + boolean contains(Object object); + + /** + * Sets an Object to be invalid in the cache. + */ + void evict(Object object); + + /** + * Returns the object's Id. + */ + Object getId(Object object); + +}