| /* |
| * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation from Oracle TopLink |
| // 11/10/2011-2.4 Guy Pelletier |
| // - 357474: Address primaryKey option from tenant discriminator column |
| // 30/05/2012-2.4 Guy Pelletier |
| // - 354678: Temp classloader is still being used during metadata processing |
| // 06/03/2013-2.5.1 Guy Pelletier |
| // - 402380: 3 jpa21/advanced tests failed on server with |
| // "java.lang.NoClassDefFoundError: org/eclipse/persistence/testing/models/jpa21/advanced/enums/Gender" |
| package org.eclipse.persistence.mappings; |
| |
| import java.beans.PropertyChangeListener; |
| import java.io.Serializable; |
| import java.security.AccessController; |
| import java.security.PrivilegedActionException; |
| import java.sql.ResultSet; |
| import java.sql.ResultSetMetaData; |
| import java.sql.SQLException; |
| import java.util.ArrayList; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.Vector; |
| |
| import org.eclipse.persistence.core.mappings.CoreMapping; |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| import org.eclipse.persistence.exceptions.DatabaseException; |
| import org.eclipse.persistence.exceptions.DescriptorException; |
| import org.eclipse.persistence.exceptions.QueryException; |
| import org.eclipse.persistence.exceptions.ValidationException; |
| import org.eclipse.persistence.expressions.Expression; |
| import org.eclipse.persistence.expressions.ExpressionBuilder; |
| import org.eclipse.persistence.indirection.ValueHolderInterface; |
| import org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor; |
| import org.eclipse.persistence.internal.databaseaccess.DatabasePlatform; |
| import org.eclipse.persistence.internal.descriptors.ClassNameConversionRequired; |
| import org.eclipse.persistence.internal.descriptors.DescriptorIterator; |
| import org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor; |
| import org.eclipse.persistence.internal.descriptors.MethodAttributeAccessor; |
| import org.eclipse.persistence.internal.expressions.ObjectExpression; |
| import org.eclipse.persistence.internal.expressions.QueryKeyExpression; |
| import org.eclipse.persistence.internal.helper.ConversionManager; |
| import org.eclipse.persistence.internal.helper.DatabaseField; |
| import org.eclipse.persistence.internal.helper.DatabaseTable; |
| import org.eclipse.persistence.internal.helper.IdentityHashSet; |
| import org.eclipse.persistence.internal.helper.NonSynchronizedVector; |
| import org.eclipse.persistence.internal.identitymaps.CacheKey; |
| import org.eclipse.persistence.internal.indirection.DatabaseValueHolder; |
| import org.eclipse.persistence.internal.queries.AttributeItem; |
| import org.eclipse.persistence.internal.queries.ContainerPolicy; |
| import org.eclipse.persistence.internal.queries.JoinedAttributeManager; |
| import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; |
| import org.eclipse.persistence.internal.security.PrivilegedClassForName; |
| import org.eclipse.persistence.internal.sessions.AbstractRecord; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.internal.sessions.ChangeRecord; |
| import org.eclipse.persistence.internal.sessions.MergeManager; |
| import org.eclipse.persistence.internal.sessions.ObjectChangeSet; |
| import org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet; |
| import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl; |
| import org.eclipse.persistence.internal.sessions.remote.RemoteSessionController; |
| import org.eclipse.persistence.internal.sessions.remote.RemoteValueHolder; |
| import org.eclipse.persistence.mappings.converters.Converter; |
| import org.eclipse.persistence.queries.DeleteObjectQuery; |
| import org.eclipse.persistence.queries.ObjectBuildingQuery; |
| import org.eclipse.persistence.queries.ObjectLevelModifyQuery; |
| import org.eclipse.persistence.queries.ObjectLevelReadQuery; |
| import org.eclipse.persistence.queries.QueryByExamplePolicy; |
| import org.eclipse.persistence.queries.WriteObjectQuery; |
| import org.eclipse.persistence.sessions.CopyGroup; |
| import org.eclipse.persistence.sessions.Project; |
| import org.eclipse.persistence.sessions.remote.DistributedSession; |
| |
| /** |
| * <p><b>Purpose</b>: Defines how an attribute of an object maps to and from the database |
| * |
| * <p><b>Responsibilities</b>:<ul> |
| * <li> Define type of relationship (1:1/1:M/M:M/etc.) |
| * <li> Define instance variable name and fields names required |
| * <li> Define any additional properties (ownership, indirection, read only, etc.) |
| * <li> Control building the value for the instance variable from the database row |
| * <li> Control building the database fields from the object |
| * <li> Control any pre/post updating/inserting/deleting required to maintain the relationship |
| * <li> Merges object changes for unit of work. |
| * <li> Clones objects for unit of work. |
| * <li> cache computed information to optimize performance |
| * </ul> |
| * |
| * @author Sati |
| * @since TOPLink/Java 1.0 |
| */ |
| public abstract class DatabaseMapping extends CoreMapping<AttributeAccessor, AbstractSession, ContainerPolicy, ClassDescriptor, DatabaseField> implements Cloneable, Serializable { |
| public enum WriteType { INSERT, UPDATE, UNDEFINED } |
| |
| /** Used to reduce memory for mappings with no fields. */ |
| protected static final Vector NO_FIELDS = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(0); |
| |
| /** Used to share integer instance to reduce memory. */ |
| protected static final Integer NO_WEIGHT = Integer.MAX_VALUE; |
| protected static final Integer WEIGHT_DIRECT = 1; |
| protected static final Integer WEIGHT_TRANSFORM = 100; |
| protected static final Integer WEIGHT_AGGREGATE = 200; |
| protected static final Integer WEIGHT_TO_ONE = 400; |
| |
| /** ClassDescriptor to which this mapping belongs to */ |
| protected ClassDescriptor descriptor; |
| |
| /** Wrapper to store the reference objects. */ |
| protected AttributeAccessor attributeAccessor; |
| |
| /** Makes this mapping read only. No write are performed on it. Default is false */ |
| protected boolean isReadOnly; |
| |
| /** Specifies whether this mapping is optional (i.e. field may be null). Used for DDL generation. */ |
| protected boolean isOptional; |
| |
| /** Specifies whether this mapping is lazy, this means not included in the default fetch group. */ |
| protected Boolean isLazy; |
| |
| /** Fields associated with the mappings are cached */ |
| protected Vector<DatabaseField> fields; |
| |
| /** It is needed only in remote initialization and mapping is in parent descriptor */ |
| protected boolean isRemotelyInitialized; |
| |
| /** This is a TopLink defined attribute that allows us to sort the mappings */ |
| protected Integer weight = NO_WEIGHT; |
| |
| /** Allow user defined properties. */ |
| protected Map properties; |
| /** Allow the user to defined un-converted properties which will be initialized at runtime. */ |
| protected Map<String, List<String>> unconvertedProperties; |
| |
| /** |
| * Used by the CMP3Policy to see if this mapping should be used in |
| * processing pk classes for find methods |
| */ |
| protected boolean derivesId; |
| |
| /** |
| * |
| */ |
| protected boolean isJPAId = false; |
| |
| /** |
| * A mapsId value. |
| */ |
| protected String mapsIdValue; |
| |
| /** |
| * The id mapping this mapping derives. Used by the CMP3Policy to see if |
| * this mapping should be used in processing pk classes for find methods. |
| */ |
| protected DatabaseMapping derivedIdMapping; |
| |
| /** |
| * PERF: Used as a quick check to see if this mapping is a primary key mapping, |
| * set by the object builder during initialization. |
| */ |
| protected boolean isPrimaryKeyMapping = false; |
| |
| /** |
| * PERF: Cache the mappings attribute name. |
| */ |
| protected String attributeName; |
| |
| /** |
| * Records if this mapping is being used as a MapKeyMapping. This is important for recording main mappings |
| */ |
| protected boolean isMapKeyMapping = false; |
| |
| //used by the object build/merge code to control building/merging into the |
| //shared cache. |
| protected boolean isCacheable = true; |
| |
| /** |
| * Irrelevant (and not set) unless descriptor has SerializedObjectPolicy (SOP). |
| * If descriptor has SOP, then ObjectLevelReadQuery (with shouldUseSerializedObjectPolicy flag set to true) |
| * reads in row that contain both field/value pairs and sopObject. |
| * This flag indicates whether the data for this mapping is contained in the row's sopObject or in fields/values. |
| * Boolean.TRUE - sopObject (in sopObject) |
| * Boolean.FALSE - fields/values (out sopObject); |
| * null - both sopObject and fields/values (both in and out sopObject). |
| * While writing to the data base the mapping will be used for writing into sopObject unless this flag is set to Boolean.FALSE; |
| */ |
| protected Boolean isInSopObject; |
| |
| /** |
| * PUBLIC: |
| * Default constructor. |
| */ |
| protected DatabaseMapping() { |
| this.isOptional = true; |
| this.isReadOnly = false; |
| this.attributeAccessor = new InstanceVariableAttributeAccessor(); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add an unconverted property (to be initialiazed at runtime) |
| * |
| * @param propertyName TODO |
| * @param propertyValue TODO |
| * @param propertyType TODO |
| */ |
| public void addUnconvertedProperty(String propertyName, String propertyValue, String propertyType) { |
| List<String> valuePair = new ArrayList<>(2); |
| valuePair.add(propertyValue); |
| valuePair.add(propertyType); |
| getUnconvertedProperties().put(propertyName, valuePair); |
| } |
| |
| /** |
| * INTERNAL: |
| * Clone the attribute from the clone and assign it to the backup. |
| * |
| * @param clone TODO |
| * @param backup TODO |
| * @param unitOfWork TODO |
| */ |
| public abstract void buildBackupClone(Object clone, Object backup, UnitOfWorkImpl unitOfWork); |
| |
| /** |
| * INTERNAL: |
| * Require for cloning, the part must be cloned. |
| * |
| * @param attributeValue TODO |
| * @param clone TODO |
| * @param backup TODO |
| * @param unitOfWork TODO |
| * @return TODO |
| */ |
| public Object buildBackupCloneForPartObject(Object attributeValue, Object clone, Object backup, UnitOfWorkImpl unitOfWork) { |
| throw DescriptorException.invalidMappingOperation(this, "buildBackupCloneForPartObject"); |
| } |
| |
| /** |
| * INTERNAL: |
| * Clone the attribute from the original and assign it to the clone. |
| * |
| * @param original TODO |
| * @param cacheKey TODO |
| * @param clone TODO |
| * @param refreshCascade TODO |
| * @param cloningSession TODO |
| */ |
| public abstract void buildClone(Object original, CacheKey cacheKey, Object clone, Integer refreshCascade, AbstractSession cloningSession); |
| |
| /** |
| * INTERNAL: |
| * A combination of readFromRowIntoObject and buildClone. |
| * <p> |
| * buildClone assumes the attribute value exists on the original and can |
| * simply be copied. |
| * <p> |
| * readFromRowIntoObject assumes that one is building an original. |
| * <p> |
| * Both of the above assumptions are false in this method, and actually |
| * attempts to do both at the same time. |
| * <p> |
| * Extract value from the row and set the attribute to this value in the |
| * working copy clone. |
| * In order to bypass the shared cache when in transaction a UnitOfWork must |
| * be able to populate working copies directly from the row. |
| * |
| * @param databaseRow TODO |
| * @param joinManager TODO |
| * @param clone TODO |
| * @param sharedCacheKey TODO |
| * @param sourceQuery TODO |
| * @param unitOfWork TODO |
| * @param executionSession TODO |
| */ |
| public abstract void buildCloneFromRow(AbstractRecord databaseRow, JoinedAttributeManager joinManager, Object clone, CacheKey sharedCacheKey, ObjectBuildingQuery sourceQuery, UnitOfWorkImpl unitOfWork, AbstractSession executionSession); |
| |
| /** |
| * INTERNAL: |
| * Builds a shallow original object. Only direct attributes and primary |
| * keys are populated. In this way the minimum original required for |
| * instantiating a working copy clone can be built without placing it in |
| * the shared cache (no concern over cycles). |
| * |
| * @param databaseRow TODO |
| * @param original TODO |
| * @param joinManager TODO |
| * @param query TODO |
| * @param executionSession TODO |
| */ |
| public void buildShallowOriginalFromRow(AbstractRecord databaseRow, Object original, JoinedAttributeManager joinManager, ObjectBuildingQuery query, AbstractSession executionSession) { |
| return; |
| } |
| |
| /** |
| * INTERNAL: |
| * Require for cloning, the part must be cloned. |
| * @param attributeValue TODO |
| * @param original TODO |
| * @param cacheKey TODO |
| * @param clone TODO |
| * @param cloningSession TODO |
| * @param refreshCascade TODO |
| * @param isExisting TODO |
| * @param isFromSharedCache TODO |
| * @return TODO |
| */ |
| public Object buildCloneForPartObject(Object attributeValue, Object original, CacheKey cacheKey, Object clone, AbstractSession cloningSession, Integer refreshCascade, boolean isExisting, boolean isFromSharedCache) { |
| throw DescriptorException.invalidMappingOperation(this, "buildCloneForPartObject"); |
| } |
| |
| /** |
| * INTERNAL: |
| * Performs a first level clone of the attribute. This generally means on the container will be cloned. |
| * |
| * @param attributeValue TODO |
| * @param cloningSession TODO |
| * @return TODO |
| */ |
| public Object buildContainerClone(Object attributeValue, AbstractSession cloningSession){ |
| return attributeValue; |
| } |
| |
| /** |
| * INTERNAL: |
| * Copy of the attribute of the object. |
| * This is NOT used for unit of work but for templatizing an object. |
| * |
| * @param copy TODO |
| * @param original TODO |
| * @param group TODO |
| */ |
| public void buildCopy(Object copy, Object original, CopyGroup group) { |
| } |
| |
| /** |
| * INTERNAL: |
| * In case Query By Example is used, this method builds and returns an expression that |
| * corresponds to a single attribue and it's value. |
| * |
| * @param queryObject TODO |
| * @param policy TODO |
| * @param expressionBuilder TODO |
| * @param processedObjects TODO |
| * @param session TODO |
| * @return TODO |
| */ |
| public Expression buildExpression(Object queryObject, QueryByExamplePolicy policy, Expression expressionBuilder, Map processedObjects, AbstractSession session) { |
| if (policy.shouldValidateExample()){ |
| throw QueryException.unsupportedMappingQueryByExample(queryObject.getClass().getName(), this); |
| } |
| return null; |
| } |
| |
| /** |
| * INTERNAL: |
| * Used to allow object level comparisons. |
| * |
| * @param base TODO |
| * @param value TODO |
| * @param session TODO |
| * @return TODO |
| */ |
| public Expression buildObjectJoinExpression(Expression base, Object value, AbstractSession session) { |
| throw QueryException.unsupportedMappingForObjectComparison(this, base); |
| } |
| |
| /** |
| * INTERNAL: |
| * Used to allow object level comparisons. |
| * |
| * @param base TODO |
| * @param argument TODO |
| * @param session TODO |
| * @return TODO |
| */ |
| public Expression buildObjectJoinExpression(Expression base, Expression argument, AbstractSession session) { |
| throw QueryException.unsupportedMappingForObjectComparison(this, base); |
| } |
| |
| /** |
| * INTERNAL: |
| * Cascade registerNew for Create through mappings that require the cascade |
| * |
| * @param object TODO |
| * @param uow TODO |
| * @param visitedObjects TODO |
| */ |
| abstract public void cascadePerformRemoveIfRequired(Object object, UnitOfWorkImpl uow, Map visitedObjects); |
| |
| /** |
| * INTERNAL: |
| * Cascade removal of orphaned private owned objects from the UnitOfWorkChangeSet |
| * |
| * @param object TODO |
| * @param uow TODO |
| * @param visitedObjects TODO |
| */ |
| public void cascadePerformRemovePrivateOwnedObjectFromChangeSetIfRequired(Object object, UnitOfWorkImpl uow, Map visitedObjects) { |
| // no-op by default |
| } |
| |
| /** |
| * INTERNAL: |
| * Cascade registerNew for Create through mappings that require the cascade |
| * |
| * @param object TODO |
| * @param uow TODO |
| * @param visitedObjects TODO |
| */ |
| abstract public void cascadeRegisterNewIfRequired(Object object, UnitOfWorkImpl uow, Map visitedObjects); |
| |
| /** |
| * INTERNAL: |
| * Cascade discover and persist new objects during commit. |
| * |
| * @param object TODO |
| * @param newObjects TODO |
| * @param unregisteredExistingObjects TODO |
| * @param visitedObjects TODO |
| * @param uow TODO |
| * @param cascadeErrors TODO |
| */ |
| public void cascadeDiscoverAndPersistUnregisteredNewObjects(Object object, Map newObjects, Map unregisteredExistingObjects, Map visitedObjects, UnitOfWorkImpl uow, Set cascadeErrors) { |
| // Do nothing by default, (direct and xml mappings do not require anything). |
| } |
| |
| /** |
| * INTERNAL: |
| * Used by AttributeLevelChangeTracking to update a changeRecord with calculated changes |
| * as apposed to detected changes. If an attribute can not be change tracked it's |
| * changes can be detected through this process. |
| * |
| * @param changeRecord TODO |
| * @param session TODO |
| */ |
| public void calculateDeferredChanges(ChangeRecord changeRecord, AbstractSession session){ |
| throw DescriptorException.invalidMappingOperation(this, "calculatedDeferredChanges"); |
| } |
| |
| /** |
| * INTERNAL: |
| * Clones itself. |
| * |
| * @return new instance of itself |
| */ |
| @Override |
| public Object clone() { |
| // Bug 3037701 - clone the AttributeAccessor |
| DatabaseMapping mapping = null; |
| try { |
| mapping = (DatabaseMapping)super.clone(); |
| } catch (CloneNotSupportedException e) { |
| throw new InternalError(); |
| } |
| mapping.setAttributeAccessor((AttributeAccessor)attributeAccessor.clone()); |
| return mapping; |
| } |
| |
| /** |
| * INTERNAL: |
| * Helper method to clone vector of fields (used in aggregate initialization cloning). |
| * |
| * @param fields TODO |
| * @return TODO |
| */ |
| protected Vector cloneFields(Vector fields) { |
| Vector clonedFields = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(); |
| for (Enumeration fieldsEnum = fields.elements(); fieldsEnum.hasMoreElements();) { |
| clonedFields.addElement(((DatabaseField)fieldsEnum.nextElement()).clone()); |
| } |
| |
| return clonedFields; |
| } |
| |
| /** |
| * This method must be overwritten in the subclasses to return a vector of all the |
| * fields this mapping represents. |
| * |
| * @return TODO |
| */ |
| protected Vector<DatabaseField> collectFields() { |
| return NO_FIELDS; |
| } |
| |
| /** |
| * INTERNAL: |
| * This method is used to store the FK fields that can be cached that correspond to noncacheable mappings |
| * the FK field values will be used to re-issue the query when cloning the shared cache entity |
| * |
| * @param record TODO |
| */ |
| public void collectQueryParameters(Set<DatabaseField> record){ |
| //no-op for mappings that do not support PROTECTED cache isolation |
| } |
| |
| /** |
| * INTERNAL: |
| * Mapping callback for post-initialization of source and target expression fields |
| * created when a mapping's selectionCriteria is created early with uninitialized fields. |
| * @see OneToOneMapping#postInitializeSourceAndTargetExpressions() |
| * @see OneToManyMapping#postInitializeSourceAndTargetExpressions() |
| */ |
| public void postInitializeSourceAndTargetExpressions() { |
| // no-op by default |
| // EL Bug 426500 |
| } |
| |
| /** |
| * INTERNAL: |
| * This method was created in VisualAge. |
| * |
| * @param clone TODO |
| * @param backup TODO |
| * @param owner TODO |
| * @param session TODO |
| * @return prototype.changeset.ChangeRecord TODO |
| */ |
| abstract public ChangeRecord compareForChange(Object clone, Object backup, ObjectChangeSet owner, AbstractSession session); |
| |
| /** |
| * INTERNAL: |
| * Compare the attributes belonging to this mapping for the objects. |
| * |
| * @param firstObject TODO |
| * @param secondObject TODO |
| * @param session TODO |
| * @return TODO |
| */ |
| public abstract boolean compareObjects(Object firstObject, Object secondObject, AbstractSession session); |
| |
| /** |
| * INTERNAL: |
| * Convert all the class-name-based settings in this mapping to actual class-based |
| * settings |
| * This method is implemented by subclasses as necessary. |
| * |
| * @param classLoader TODO |
| */ |
| public void convertClassNamesToClasses(ClassLoader classLoader) { |
| if (hasUnconvertedProperties()) { |
| for (String propertyName : getUnconvertedProperties().keySet()) { |
| List<String> valuePair = getUnconvertedProperties().get(propertyName); |
| String value = valuePair.get(0); |
| String valueTypeName = valuePair.get(1); |
| Class valueType = null; |
| |
| // Have to initialize the valueType now |
| try { |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) { |
| try { |
| valueType = AccessController.doPrivileged(new PrivilegedClassForName<>(valueTypeName, true, classLoader)); |
| } catch (PrivilegedActionException exception) { |
| throw ValidationException.classNotFoundWhileConvertingClassNames(valueTypeName, exception.getException()); |
| } |
| } else { |
| valueType = PrivilegedAccessHelper.getClassForName(valueTypeName, true, classLoader); |
| } |
| } catch (Exception exception) { |
| throw ValidationException.classNotFoundWhileConvertingClassNames(valueTypeName, exception); |
| } |
| |
| // Add the converted property. If the value type is the same |
| // as the source (value) type, no conversion is made. |
| getProperties().put(propertyName, ConversionManager.getDefaultManager().convertObject(value, valueType)); |
| } |
| } |
| } |
| |
| /** |
| * Convenience method to ensure converters have an opportunity to convert |
| * any class names to classes during project setup. |
| * |
| * @param converter TODO |
| * @param classLoader TODO |
| */ |
| protected void convertConverterClassNamesToClasses(Converter converter, ClassLoader classLoader) { |
| if (converter != null && converter instanceof ClassNameConversionRequired) { |
| ((ClassNameConversionRequired)converter).convertClassNamesToClasses(classLoader); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Builder the unit of work value holder. |
| * |
| * @param attributeValue TODO |
| * @param original TODO |
| * @param clone TODO |
| * @param row TODO |
| * @param cloningSession TODO |
| * @param buildDirectlyFromRow indicates that we are building the clone directly |
| * from a row as opposed to building the original from the row, putting it in |
| * the shared cache, and then cloning the original. |
| * @return TODO |
| */ |
| public DatabaseValueHolder createCloneValueHolder(ValueHolderInterface attributeValue, Object original, Object clone, AbstractRecord row, AbstractSession cloningSession, boolean buildDirectlyFromRow) { |
| throw DescriptorException.invalidMappingOperation(this, "createUnitOfWorkValueHolder"); |
| } |
| |
| /** |
| * ADVANCED: |
| * Returns true if the mapping references a JPA ID attribute for the CMP3Policy and JPA ID classes. |
| * |
| * @return TODO |
| */ |
| public boolean derivesId() { |
| return derivesId; |
| } |
| |
| /** |
| * INTERNAL: |
| * This method is called to update collection tables prior to commit. |
| * |
| * @param query TODO |
| * @param object TODO |
| */ |
| public void earlyPreDelete(DeleteObjectQuery query, Object object) { |
| } |
| |
| /** |
| * INTERNAL: |
| * Extract the nested attribute expressions that apply to this mapping. |
| * This is used for partial objects, and batch fetching. |
| * |
| * @param expressions TODO |
| * @param newRoot TODO |
| * @return TODO |
| */ |
| protected List<Expression> extractNestedExpressions(List<Expression> expressions, ExpressionBuilder newRoot) { |
| List<Expression> nestedExpressions = new ArrayList(expressions.size()); |
| |
| /* |
| * If the expression closest to to the Builder is for this mapping, that expression is rebuilt using |
| * newRoot and added to the nestedExpressions list. |
| */ |
| for (Expression next : expressions) { |
| // The expressionBuilder can be one of the locked expressions in |
| // the ForUpdateOfClause. |
| if (!next.isQueryKeyExpression()) { |
| continue; |
| } |
| QueryKeyExpression expression = (QueryKeyExpression)next; |
| ObjectExpression base = expression; |
| boolean afterBase = false; |
| |
| while (!base.getBaseExpression().isExpressionBuilder()) { |
| base = (ObjectExpression)base.getBaseExpression(); |
| afterBase = true; |
| } |
| if (base.getName().equals(getAttributeName())) { |
| // Only add the nested expressions for the mapping (not the mapping itself). |
| if (afterBase) { |
| nestedExpressions.add(expression.rebuildOn(base, newRoot)); |
| } |
| } |
| } |
| return nestedExpressions; |
| } |
| |
| /** |
| * INTERNAL: |
| * Extract the nested attribute expressions that apply to this mapping. |
| * This is used for joining, and locking. |
| * For aggregates return the nested foreign reference mapping, not the aggregate, as the aggregates are not joined, |
| * and share their parent's query. |
| * |
| * @param expressions TODO |
| * @param newRoot TODO |
| * @param rootExpressionsAllowed true if newRoot itself can be one of the |
| * expressions returned (used for locking) |
| * @return TODO |
| */ |
| protected List<Expression> extractNestedNonAggregateExpressions(List<Expression> expressions, ExpressionBuilder newRoot, boolean rootExpressionsAllowed) { |
| List<Expression> nestedExpressions = new ArrayList(expressions.size()); |
| |
| /* |
| * need to work on all expressions with at least 2 nestings off the base expression builder, excluding |
| * aggregateObjectMapping expressions from the count (only ForeignReferenceMapping expressions count). For those |
| * expressions, If the expression closest to to the Builder is for this mapping, that expression is rebuilt using |
| * newRoot and added to the nestedExpressions list. |
| */ |
| for (Expression next : expressions) { |
| // The expressionBuilder can be one of the locked expressions in |
| // the ForUpdateOfClause. |
| if (!next.isQueryKeyExpression()) { |
| continue; |
| } |
| QueryKeyExpression expression = (QueryKeyExpression)next; |
| ObjectExpression base = expression; |
| boolean afterBase = false; |
| boolean done = false; |
| |
| ObjectExpression prevExpression = base; |
| while (!base.getBaseExpression().isExpressionBuilder()&& !done) { |
| base = (ObjectExpression)base.getBaseExpression(); |
| while (!base.isExpressionBuilder() && (base.getMapping() != null && base.getMapping().isAggregateObjectMapping())) { |
| base = (ObjectExpression)base.getBaseExpression(); |
| } |
| if (base.isExpressionBuilder()){ |
| done = true; |
| //use the one closest to the expression builder that wasn't an aggregate |
| base = prevExpression; |
| } else { |
| prevExpression = base; |
| afterBase = true; |
| } |
| } |
| if (afterBase && base.getName().equals(getAttributeName())) { |
| nestedExpressions.add(expression.rebuildOn(base, newRoot)); |
| } else if (rootExpressionsAllowed && expression.getBaseExpression().isExpressionBuilder() && expression.getName().equals(getAttributeName())) { |
| nestedExpressions.add(newRoot); |
| } |
| } |
| return nestedExpressions; |
| } |
| |
| /** |
| * INTERNAL: |
| * If there is root expression in the list then indicates whether it shouldUseOuterJoin, |
| * otherwise return false. |
| * |
| * @param expressions TODO |
| * @return TODO |
| */ |
| protected boolean hasRootExpressionThatShouldUseOuterJoin(List expressions) { |
| for (Iterator expressionsEnum = expressions.iterator(); |
| expressionsEnum.hasNext();) { |
| Expression next = (Expression)expressionsEnum.next(); |
| |
| // The expressionBuilder can be one of the locked expressions in |
| // the ForUpdateOfClause. |
| if (!next.isQueryKeyExpression()) { |
| continue; |
| } |
| QueryKeyExpression expression = (QueryKeyExpression)next; |
| if (expression.getBaseExpression().isExpressionBuilder() && expression.getName().equals(getAttributeName())) { |
| return expression.shouldUseOuterJoin(); |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Used to store un-converted properties, which are subsequenctly converted |
| * at runtime (through the convertClassNamesToClasses method. |
| * |
| * @return TODO |
| */ |
| public boolean hasUnconvertedProperties() { |
| return unconvertedProperties != null; |
| } |
| |
| /** |
| * INTERNAL: |
| * An object has been serialized from the server to the client. |
| * Replace the transient attributes of the remote value holders |
| * with client-side objects. |
| * |
| * @param object TODO |
| * @param objectDescriptors TODO |
| * @param processedObjects TODO |
| * @param query TODO |
| * @param session TODO |
| */ |
| public abstract void fixObjectReferences(Object object, Map objectDescriptors, Map processedObjects, ObjectLevelReadQuery query, DistributedSession session); |
| |
| /** |
| * INTERNAL: |
| * At this point, we realize we don't have indirection; |
| * so we need to replace the reference object(s) with |
| * the corresponding object(s) from the remote session. |
| * The default is to do nothing. |
| * |
| * @param object TODO |
| * @param objectInformation TODO |
| * @param processedObjects TODO |
| * @param query TODO |
| * @param session TODO |
| */ |
| public void fixRealObjectReferences(Object object, Map objectInformation, Map processedObjects, ObjectLevelReadQuery query, DistributedSession session) { |
| // do nothing |
| } |
| |
| /** |
| * ADVANCED: |
| * Return the attributeAccessor. |
| * The attribute accessor is responsible for setting and retrieving the attribute value |
| * from the object for this mapping. |
| * |
| * @return TODO |
| */ |
| @Override |
| public AttributeAccessor getAttributeAccessor() { |
| return attributeAccessor; |
| } |
| |
| /** |
| * PUBLIC: |
| * The classification type for the attribute this mapping represents |
| * |
| * @return TODO |
| */ |
| @Override |
| public Class getAttributeClassification() { |
| return null; |
| } |
| |
| /** |
| * PUBLIC: |
| * Return the name of the attribute set in the mapping. |
| * |
| * @return TODO |
| */ |
| @Override |
| public String getAttributeName() { |
| // The attribute name on the attributeAccessor will always override any attribute already set |
| // Use the attributeAccessor attribute over the current attribute name |
| if (attributeName == null) { |
| attributeName = getAttributeAccessor().getAttributeName(); |
| } |
| return attributeName; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the value of an attribute which this mapping represents for an object. |
| */ |
| @Override |
| public Object getAttributeValueFromObject(Object object) throws DescriptorException { |
| try { |
| // PERF: direct-access. |
| return this.attributeAccessor.getAttributeValueFromObject(object); |
| } catch (DescriptorException exception) { |
| exception.setMapping(this); |
| throw exception; |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the mapping's containerPolicy. |
| * |
| * @return TODO |
| */ |
| @Override |
| public ContainerPolicy getContainerPolicy() { |
| throw DescriptorException.invalidMappingOperation(this, "getContainerPolicy"); |
| } |
| |
| /** |
| * ADVANCED: |
| * Set the maps id value |
| * |
| * @return TODO |
| */ |
| public DatabaseMapping getDerivedIdMapping() { |
| return derivedIdMapping; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the descriptor to which this mapping belongs |
| * |
| * @return TODO |
| */ |
| @Override |
| public ClassDescriptor getDescriptor() { |
| return descriptor; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the field associated with this mapping if there is exactly one. |
| * This is required for object relational mapping to print them, but because |
| * they are defined in in an Enterprise context they cannot be cast to. |
| * Mappings that have a field include direct mappings and object relational mappings. |
| * |
| * @return TODO |
| */ |
| @Override |
| public DatabaseField getField() { |
| return null; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the classification for the field contained in the mapping. |
| * This is used to convert the row value to a consistent java value. |
| * By default this is unknown. |
| */ |
| public Class getFieldClassification(DatabaseField fieldToClassify) { |
| return null; |
| } |
| |
| /** |
| * INTERNAL: |
| * Returns the set of fields that should be selected to build this mapping's value(s). |
| * This is used by expressions to determine which fields to include in the select clause for non-object expressions. |
| * |
| * @return TODO |
| */ |
| public Vector getSelectFields() { |
| return getFields(); |
| } |
| |
| /** |
| * INTERNAL: |
| * Returns the table(s) that should be selected to build this mapping's value(s). |
| * This is used by expressions to determine which tables to include in the from clause for non-object expressions. |
| * |
| * @return TODO |
| */ |
| public Vector getSelectTables() { |
| return new NonSynchronizedVector(0); |
| } |
| |
| /** |
| * INTERNAL: |
| * Returns a vector of all the fields this mapping represents. |
| * |
| * @return TODO |
| */ |
| @Override |
| public Vector<DatabaseField> getFields() { |
| return this.fields; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the list of fields that should be used if this mapping is used in an order by. |
| * null means this mapping does not need to normalize it fields (it is a field). |
| */ |
| public List<Expression> getOrderByNormalizedExpressions(Expression base) { |
| return null; |
| } |
| |
| /** |
| * PUBLIC: |
| * This method is invoked reflectively on the reference object to return the value of the |
| * attribute in the object. This method returns the name of the getMethodName or null if not using method access. |
| * |
| * @return TODO |
| */ |
| public String getGetMethodName() { |
| if (!getAttributeAccessor().isMethodAttributeAccessor()) { |
| return null; |
| } |
| return ((MethodAttributeAccessor)getAttributeAccessor()).getGetMethodName(); |
| } |
| |
| /** |
| * ADVANCED: |
| * Set the mapped by id value |
| * |
| * @return TODO |
| */ |
| public boolean hasMapsIdValue() { |
| return mapsIdValue != null; |
| } |
| |
| /** |
| * ADVANCED: |
| * Set the mapped by id value |
| * |
| * @return TODO |
| */ |
| public String getMapsIdValue() { |
| return mapsIdValue; |
| } |
| |
| /** |
| * INTERNAL: |
| * return the object on the client corresponding to the specified object. |
| * The default is to simply return the object itself, without worrying about |
| * maintaining object identity. |
| * |
| * @param object TODO |
| * @param session TODO |
| * @param objectDescriptors TODO |
| * @param processedObjects TODO |
| * @param query TODO |
| * @return TODO |
| */ |
| public Object getObjectCorrespondingTo(Object object, DistributedSession session, Map objectDescriptors, Map processedObjects, ObjectLevelReadQuery query) { |
| return object; |
| } |
| |
| /** |
| * INTERNAL: |
| * used as a temporary store for custom SDK usage |
| * |
| * @return TODO |
| */ |
| public Map getProperties() { |
| if (properties == null) {//Lazy initialize to conserve space and allocation time. |
| properties = new HashMap(5); |
| } |
| return properties; |
| } |
| |
| /** |
| * ADVANCED: |
| * Allow user defined properties. |
| * |
| * @param property TODO |
| * @return TODO |
| */ |
| public Object getProperty(Object property) { |
| if (properties == null) { |
| return null; |
| } |
| |
| return getProperties().get(property); |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the value of an attribute unwrapping value holders if required. |
| */ |
| public Object getRealAttributeValueFromObject(Object object, AbstractSession session) throws DescriptorException { |
| return getRealAttributeValueFromAttribute(getAttributeValueFromObject(object), object, session); |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the value of an attribute unwrapping value holders if required. |
| */ |
| public Object getRealAttributeValueFromAttribute(Object attributeValue, Object object, AbstractSession session) throws DescriptorException { |
| return attributeValue; |
| } |
| |
| /** |
| * INTERNAL: |
| * Trigger the instantiation of the attribute if lazy. |
| */ |
| public void instantiateAttribute(Object object, AbstractSession session) { |
| // Not lazy by default. |
| } |
| |
| /** |
| * INTERNAL: |
| * Return whether the specified object is instantiated. |
| */ |
| public boolean isAttributeValueFromObjectInstantiated(Object object) { |
| return true; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the value of an attribute, unwrapping value holders if necessary. |
| * If the value is null, build a new container. |
| */ |
| public Object getRealCollectionAttributeValueFromObject(Object object, AbstractSession session) throws DescriptorException { |
| throw DescriptorException.invalidMappingOperation(this, "getRealCollectionAttributeValueFromObject"); |
| } |
| |
| /** |
| * PUBLIC: |
| * Return the referenceDescriptor. This is a descriptor which is associated with |
| * the reference class. |
| */ |
| @Override |
| public ClassDescriptor getReferenceDescriptor() { |
| return null; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the relationshipPartner mapping for this bi-directional mapping. If the relationshipPartner is null then |
| * this is a uni-directional mapping. |
| */ |
| public DatabaseMapping getRelationshipPartner() { |
| return null; |
| } |
| |
| /** |
| * PUBLIC: |
| * This method is invoked reflectively on the reference object to set the value of the |
| * attribute in the object. This method returns the name of the setMethodName or null if not using method access. |
| */ |
| public String getSetMethodName() { |
| if (!getAttributeAccessor().isMethodAttributeAccessor()) { |
| return null; |
| } |
| return ((MethodAttributeAccessor)getAttributeAccessor()).getSetMethodName(); |
| } |
| |
| /** |
| * INTERNAL: |
| * Used to store un-converted properties, which are subsequenctly converted |
| * at runtime (through the convertClassNamesToClasses method. |
| */ |
| public Map<String, List<String>> getUnconvertedProperties() { |
| if (unconvertedProperties == null) { |
| unconvertedProperties = new HashMap<>(5); |
| } |
| |
| return unconvertedProperties; |
| } |
| |
| /** |
| * INTERNAL: |
| * extract and return the appropriate value from the |
| * specified remote value holder |
| */ |
| public Object getValueFromRemoteValueHolder(RemoteValueHolder remoteValueHolder) { |
| throw DescriptorException.invalidMappingOperation(this, "getValueFromRemoteValueHolder"); |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the weight of the mapping, used to sort mappings to ensure that |
| * DirectToField Mappings get merged first |
| */ |
| public Integer getWeight() { |
| return this.weight; |
| } |
| |
| /** |
| * INTERNAL: |
| * The returns if the mapping has any constraint dependencies, such as foreign keys and join tables. |
| */ |
| public boolean hasConstraintDependency() { |
| return false; |
| } |
| |
| /** |
| * PUBLIC: |
| * Return if method access is used. |
| */ |
| public boolean isUsingMethodAccess() { |
| return getAttributeAccessor().isMethodAttributeAccessor(); |
| } |
| |
| /** |
| * INTERNAL: |
| * Return if the mapping has any ownership or other dependency over its target object(s). |
| */ |
| public boolean hasDependency() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * The returns if the mapping has any inverse constraint dependencies, such as foreign keys and join tables. |
| */ |
| public boolean hasInverseConstraintDependency() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Allow for initialization of properties and validation. |
| */ |
| public void initialize(AbstractSession session) throws DescriptorException { |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isAggregateCollectionMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isAggregateMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isAggregateObjectMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| @Override |
| public boolean isCollectionMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public boolean isDatabaseMapping() { |
| return true; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isDirectCollectionMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isDirectMapMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| @Override |
| public boolean isDirectToFieldMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isElementCollectionMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isForeignReferenceMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return whether this mapping should be traversed when we are locking |
| */ |
| public boolean isLockableMapping(){ |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isManyToManyMapping() { |
| return false; |
| } |
| |
| /** |
| * @return the isMapKeyMapping |
| */ |
| public boolean isMapKeyMapping() { |
| return isMapKeyMapping; |
| } |
| |
| /** |
| * INTERNAL |
| */ |
| public boolean isMultitenantPrimaryKeyMapping() { |
| return false; |
| } |
| |
| /** |
| * @param isMapKeyMapping the isMapKeyMapping to set |
| */ |
| public void setIsMapKeyMapping(boolean isMapKeyMapping) { |
| this.isMapKeyMapping = isMapKeyMapping; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isNestedTableMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isObjectReferenceMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isOneToManyMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isOneToOneMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isManyToOneMapping() { |
| return false; |
| } |
| |
| /** |
| * Return whether the value of this mapping is optional (that is, can be |
| * null). This is a hint and is used when generating DDL. |
| */ |
| public boolean isOptional() { |
| return isOptional; |
| } |
| |
| /** |
| * Returns true if this mapping is owned by the parent descriptor. This is generally based on mapping type |
| */ |
| public boolean isOwned(){ |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Flags that this mapping is part of a JPA id mapping. It should be |
| * temporary though, as the CMP3Policy should be able to figure things |
| * out on its own. The problem being that the JPA mapped superclass |
| * descriptors are not initialized and do not have a CMP3Policy set by |
| * default. |
| */ |
| public boolean isJPAId() { |
| return isJPAId; |
| } |
| |
| /** |
| * Return if this mapping is lazy. |
| * Lazy has different meaning for different mappings. |
| * For basic/direct mappings, this can be used exclude it from the descriptor's |
| * default fetch group. This means that queries will not include the field(s) required |
| * by this mapping by default. |
| * This can only be used if the descriptor has a FetchGroupManager and class implements |
| * the FetchGroupTracker interface (or is weaved). |
| * <p> |
| * For relationship mappings this should normally be the same value as indirection, |
| * however for eager relationships this can be used with indirection to allow |
| * indirection locking and change tracking, but still always force instantiation. |
| */ |
| public boolean isLazy() { |
| if (isLazy == null) { |
| // False by default for mappings without indirection. |
| isLazy = Boolean.FALSE; |
| } |
| return isLazy; |
| } |
| |
| /** |
| * INTERNAL: |
| * Flags that this mapping is part of a JPA id mapping. It should be |
| * temporary though, as the CMP3Policy should be able to figure things |
| * out on its own. The problem being that the JPA mapped superclass |
| * descriptors are not initialized and do not have a CMP3Policy set by |
| * default. |
| */ |
| public void setIsJPAId() { |
| this.isJPAId = true; |
| } |
| |
| /** |
| * Set if this mapping is lazy. |
| * This can be used for any mapping type to exclude it from the descriptor's |
| * default fetch group. This means that queries will not include the field(s) required |
| * by this mapping by default. |
| * This can only be used if the descriptor has a FetchGroupManager and class implements |
| * the FetchGroupTracker interface (or is weaved). |
| * This is not the same as indirection on relationships (lazy relationships), |
| * as it defers the loading of the source object fields, not the relationship. |
| */ |
| public void setIsLazy(boolean isLazy) { |
| this.isLazy = isLazy; |
| } |
| |
| /** |
| * INTERNAL: |
| * All EIS mappings should implement this method to return true. |
| */ |
| public boolean isEISMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * All relational mappings should implement this method to return true. |
| */ |
| public boolean isRelationalMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * All relational mappings should implement this method to return true. |
| */ |
| public boolean isXMLMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| @Override |
| public boolean isAbstractDirectMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public boolean isAbstractColumnMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| @Override |
| public boolean isAbstractCompositeDirectCollectionMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| @Override |
| public boolean isAbstractCompositeObjectMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| @Override |
| public boolean isAbstractCompositeCollectionMapping() { |
| return false; |
| } |
| /** |
| * INTERNAL: |
| * Return if this mapping support joining. |
| */ |
| public boolean isJoiningSupported() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return if this mapping requires its attribute value to be cloned. |
| */ |
| public boolean isCloningRequired() { |
| return true; |
| } |
| |
| /** |
| * INTERNAL: |
| * Set by the Object builder during initialization returns true if this mapping |
| * is used as a primary key mapping. |
| */ |
| public boolean isPrimaryKeyMapping() { |
| return this.isPrimaryKeyMapping; |
| } |
| |
| /** |
| * INTERNAL: |
| * Returns true if the mapping should be added to the UnitOfWork's list of private owned |
| * objects for private owned orphan removal. |
| */ |
| public boolean isCandidateForPrivateOwnedRemoval() { |
| return isPrivateOwned(); |
| } |
| |
| /** |
| * INTERNAL: |
| * Used when determining if a mapping supports cascaded version optimistic |
| * locking. |
| */ |
| public boolean isCascadedLockingSupported() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return if this mapping supports change tracking. |
| */ |
| public boolean isChangeTrackingSupported(Project project) { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return if the mapping has ownership over its target object(s). |
| */ |
| public boolean isPrivateOwned() { |
| return false; |
| } |
| |
| /** |
| * Used to signal that this mapping references a protected/isolated entity and requires |
| * special merge/object building behaviour. |
| * |
| */ |
| public boolean isCacheable() { |
| return this.isCacheable; |
| } |
| /** |
| * Used to signal that this mapping references a protected/isolated entity and requires |
| * special merge/object building behaviour. |
| */ |
| public void setIsCacheable(boolean cacheable) { |
| if (!cacheable) { |
| throw ValidationException.operationNotSupported("setIsCacheable"); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Returns true if mapping is read only else false. |
| */ |
| @Override |
| public boolean isReadOnly() { |
| return isReadOnly; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| @Override |
| public boolean isReferenceMapping() { |
| return false; |
| } |
| |
| protected boolean isRemotelyInitialized() { |
| return isRemotelyInitialized; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isStructureMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| @Override |
| public boolean isTransformationMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public boolean isUnidirectionalOneToManyMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isVariableOneToOneMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Related mapping should implement this method to return true. |
| */ |
| public boolean isDirectToXMLTypeMapping() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Some mappings support no attribute (transformation and multitenant primary key). |
| */ |
| @Override |
| public boolean isWriteOnly() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Iterate on the appropriate attribute value. |
| */ |
| public abstract void iterate(DescriptorIterator iterator); |
| |
| /** |
| * INTERNAL: |
| * Iterate on the attribute value. |
| * The value holder has already been processed. |
| */ |
| public void iterateOnRealAttributeValue(DescriptorIterator iterator, Object realAttributeValue) { |
| throw DescriptorException.invalidMappingOperation(this, "iterateOnRealAttributeValue"); |
| } |
| |
| /** |
| * Force instantiation of the load group. |
| */ |
| public void load(final Object object, AttributeItem item, final AbstractSession session, final boolean fromFetchGroup) { |
| // Do nothing by default. |
| } |
| |
| /** |
| * Force instantiation of all indirections. |
| */ |
| public void loadAll(Object object, AbstractSession session, IdentityHashSet loaded) { |
| // Do nothing by default. |
| } |
| |
| /** |
| * INTERNAL: |
| * Merge changes from the source to the target object. |
| */ |
| public abstract void mergeChangesIntoObject(Object target, ChangeRecord changeRecord, Object source, MergeManager mergeManager, AbstractSession targetSession); |
| |
| /** |
| * INTERNAL: |
| * Merge changes from the source to the target object. |
| */ |
| public abstract void mergeIntoObject(Object target, boolean isTargetUninitialized, Object source, MergeManager mergeManager, AbstractSession targetSession); |
| |
| /** |
| * INTERNAL: |
| * Perform the commit event. |
| * This is used in the uow to delay data modifications. |
| */ |
| public void performDataModificationEvent(Object[] event, AbstractSession session) throws DatabaseException, DescriptorException { |
| throw DescriptorException.invalidDataModificationEvent(this); |
| } |
| |
| /** |
| * INTERNAL: |
| * A subclass should implement this method if it wants different behavior. |
| * Recurse thru the parts to delete the reference objects after the actual object is deleted. |
| */ |
| public void postDelete(DeleteObjectQuery query) throws DatabaseException { |
| return; |
| } |
| |
| /** |
| * INTERNAL: |
| * Allow for initialization of properties and validation that have dependecies no the descriptor |
| * being initialized. |
| */ |
| public void postInitialize(AbstractSession session) throws DescriptorException { |
| // Nothing by default. |
| } |
| |
| /** |
| * INTERNAL: |
| * A subclass should implement this method if it wants different behavior. |
| * Recurse thru the parts to insert the reference objects after the actual object is inserted. |
| */ |
| public void postInsert(WriteObjectQuery query) throws DatabaseException { |
| return; |
| } |
| |
| /** |
| * INTERNAL: |
| * A subclass should implement this method if it wants different behavior. |
| * Recurse thru the parts to update the reference objects after the actual object is updated. |
| */ |
| public void postUpdate(WriteObjectQuery query) throws DatabaseException { |
| return; |
| } |
| |
| /** |
| * INTERNAL: |
| * A subclass should implement this method if it wants different behavior. |
| * Recurse thru the parts to delete the reference objects before the actual object is deleted. |
| */ |
| public void preDelete(DeleteObjectQuery query) throws DatabaseException { |
| return; |
| } |
| |
| /** |
| * INTERNAL: |
| * Allow for initialization of properties and validation. |
| */ |
| public void preInitialize(AbstractSession session) throws DescriptorException { |
| try { |
| getAttributeAccessor().initializeAttributes(getDescriptor().getJavaClass()); |
| } catch (DescriptorException exception) { |
| exception.setMapping(this); |
| session.getIntegrityChecker().handleError(exception); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * A subclass should implement this method if it wants different behavior. |
| * Recurse thru the parts to insert the reference objects before the actual object is inserted. |
| */ |
| public void preInsert(WriteObjectQuery query) throws DatabaseException { |
| return; |
| } |
| |
| /** |
| * INTERNAL: |
| * A subclass that supports cascade version optimistic locking should |
| * implement this method to properly prepare the locking policy for their |
| * mapping type. |
| */ |
| public void prepareCascadeLockingPolicy() { |
| return; |
| } |
| |
| /** |
| * INTERNAL: |
| * A subclass should implement this method if it wants different behavior. |
| * Recurse thru the parts to update the reference objects before the actual object is updated. |
| */ |
| public void preUpdate(WriteObjectQuery query) throws DatabaseException { |
| return; |
| } |
| |
| /** |
| * INTERNAL: |
| * Extract value from the row and set the attribute to this value in the object. |
| * return value as this value will have been converted to the appropriate type for |
| * the object. |
| */ |
| public Object readFromRowIntoObject(AbstractRecord databaseRow, JoinedAttributeManager joinManager, Object targetObject, CacheKey parentCacheKey, ObjectBuildingQuery sourceQuery, AbstractSession executionSession, boolean isTargetProtected) throws DatabaseException { |
| Object attributeValue = valueFromRow(databaseRow, joinManager, sourceQuery, parentCacheKey, executionSession, isTargetProtected, null); |
| setAttributeValueInObject(targetObject, attributeValue); |
| return attributeValue; |
| } |
| |
| /** |
| * INTERNAL: |
| * Extract values directly from the result-set. |
| * PERF: This is used for optimized object building directly from the result-set. |
| */ |
| public Object readFromResultSetIntoObject(ResultSet resultSet, Object targetObject, ObjectBuildingQuery query, AbstractSession session, DatabaseAccessor accessor, ResultSetMetaData metaData, int columnNumber, DatabasePlatform platform) throws SQLException { |
| Object attributeValue = valueFromResultSet(resultSet, query, session, accessor, metaData, columnNumber, platform); |
| setAttributeValueInObject(targetObject, attributeValue); |
| return attributeValue; |
| } |
| |
| /** |
| * PUBLIC: |
| * To make mapping read only. |
| * Read-only mappings can be used if two attributes map to the same field. |
| * Read-only mappings cannot be used for the primary key or other required fields. |
| */ |
| public void readOnly() { |
| setIsReadOnly(true); |
| } |
| |
| /** |
| * PUBLIC: |
| * The mapping can be dynamically made either readOnly or readWriteOnly. This makes mapping go back to |
| * default mode. |
| */ |
| public void readWrite() { |
| setIsReadOnly(false); |
| } |
| |
| /** |
| * INTERNAL: |
| * Rehash any hashtables based on fields. |
| * This is used to clone descriptors for aggregates, which hammer field names, |
| * it is probably better not to hammer the field name and this should be refactored. |
| */ |
| public void rehashFieldDependancies(AbstractSession session) { |
| // Should be overwritten by any mapping with fields. |
| } |
| |
| /** |
| * INTERNAL: |
| * Once descriptors are serialized to the remote session. All its mappings and reference descriptors are traversed. Usually |
| * mappings are initilaized and serialized reference descriptors are replaced with local descriptors if they already exist on the |
| * remote session. |
| */ |
| public void remoteInitialization(DistributedSession session) { |
| // Remote mappings is initilaized here again because while serializing only the uninitialized data is passed |
| // as the initialized data is not serializable. |
| if (!isRemotelyInitialized()) { |
| getAttributeAccessor().initializeAttributes(getDescriptor().getJavaClass()); |
| remotelyInitialized(); |
| } |
| } |
| |
| /** |
| * Set the mapping to be initialized for the remote session. |
| */ |
| protected void remotelyInitialized() { |
| isRemotelyInitialized = true; |
| } |
| |
| /** |
| * INTERNAL: |
| * replace the value holders in the specified reference object(s) |
| */ |
| public Map replaceValueHoldersIn(Object object, RemoteSessionController controller) { |
| // by default, do nothing |
| return null; |
| } |
| |
| /** |
| * ADVANCED: |
| * Set the attributeAccessor. |
| * The attribute accessor is responsible for setting and retrieving the attribute value |
| * from the object for this mapping. |
| * This can be set to an implementor of AttributeAccessor if the attribute |
| * requires advanced conversion of the mapping value, or a real attribute does not exist. |
| */ |
| @Override |
| public void setAttributeAccessor(AttributeAccessor attributeAccessor) { |
| String attributeName = getAttributeName(); |
| this.attributeAccessor = attributeAccessor; |
| if (attributeAccessor.getAttributeName() == null) { |
| attributeAccessor.setAttributeName(attributeName); |
| } |
| this.attributeName = null; |
| } |
| |
| /** |
| * PUBLIC: |
| * Sets the name of the attribute in the mapping. |
| */ |
| @Override |
| public void setAttributeName(String attributeName) { |
| getAttributeAccessor().setAttributeName(attributeName); |
| // Clear the mapping attribute name until a getAttributeName() call copies the accessor attributeName |
| this.attributeName = null; |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the value of the attribute mapped by this mapping. |
| */ |
| @Override |
| public void setAttributeValueInObject(Object object, Object value) throws DescriptorException { |
| // PERF: Direct variable access. |
| try { |
| this.attributeAccessor.setAttributeValueInObject(object, value); |
| } catch (DescriptorException exception) { |
| exception.setMapping(this); |
| throw exception; |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the value of the attribute mapped by this mapping, |
| * placing it inside a value holder if necessary. |
| */ |
| public void setRealAttributeValueInObject(Object object, Object value) throws DescriptorException { |
| try { |
| this.setAttributeValueInObject(object, value); |
| } catch (DescriptorException exception) { |
| exception.setMapping(this); |
| throw exception; |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the descriptor to which this mapping belongs |
| */ |
| @Override |
| public void setDescriptor(ClassDescriptor descriptor) { |
| this.descriptor = descriptor; |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the mapping's field collection. |
| */ |
| @Override |
| protected void setFields(Vector<DatabaseField> fields) { |
| this.fields = fields; |
| } |
| |
| /** |
| * PUBLIC: |
| * This method is invoked reflectively on the reference object to return the value of the |
| * attribute in the object. This method sets the name of the getMethodName. |
| */ |
| public void setGetMethodName(String methodName) { |
| if (methodName == null) { |
| return; |
| } |
| |
| // This is done because setting attribute name by defaults create InstanceVariableAttributeAccessor |
| if (getAttributeAccessor() instanceof InstanceVariableAttributeAccessor) { |
| String attributeName = this.attributeAccessor.getAttributeName(); |
| setAttributeAccessor(new MethodAttributeAccessor()); |
| getAttributeAccessor().setAttributeName(attributeName); |
| } |
| |
| ((MethodAttributeAccessor)getAttributeAccessor()).setGetMethodName(methodName); |
| } |
| |
| /** |
| * Used to specify whether the value of this mapping may be null. |
| * This is used when generating DDL. |
| */ |
| public void setIsOptional(boolean isOptional) { |
| this.isOptional = isOptional; |
| } |
| |
| /** |
| * INTERNAL: |
| * Set by the Object builder during initialization returns true if this mapping |
| * is used as a primary key mapping. |
| */ |
| public void setIsPrimaryKeyMapping(boolean isPrimaryKeyMapping) { |
| this.isPrimaryKeyMapping = isPrimaryKeyMapping; |
| } |
| |
| /** |
| * PUBLIC: |
| * Set this mapping to be read only. |
| * Read-only mappings can be used if two attributes map to the same field. |
| * Read-only mappings cannot be used for the primary key or other required fields. |
| */ |
| public void setIsReadOnly(boolean aBoolean) { |
| isReadOnly = aBoolean; |
| } |
| |
| /** |
| * ADVANCED: |
| * Set the maps id value |
| */ |
| public void setMapsIdValue(String mapsIdValue) { |
| this.mapsIdValue = mapsIdValue; |
| } |
| |
| /** |
| * INTERNAL: |
| * Allow user defined properties. |
| */ |
| public void setProperties(Map properties) { |
| this.properties = properties; |
| } |
| |
| /** |
| * ADVANCED: |
| * Allow user defined properties. |
| */ |
| public void setProperty(Object property, Object value) { |
| getProperties().put(property, value); |
| } |
| |
| /** |
| * PUBLIC: |
| * Set the methodName used to set the value for the mapping's attribute into the object. |
| */ |
| public void setSetMethodName(String methodName) { |
| if (methodName == null) { |
| return; |
| } |
| |
| // This is done because setting attribute name by defaults create InstanceVariableAttributeAccessor |
| if (!getAttributeAccessor().isMethodAttributeAccessor()) { |
| String attributeName = this.attributeAccessor.getAttributeName(); |
| setAttributeAccessor(new MethodAttributeAccessor()); |
| getAttributeAccessor().setAttributeName(attributeName); |
| } |
| |
| ((MethodAttributeAccessor)getAttributeAccessor()).setSetMethodName(methodName); |
| } |
| |
| /** |
| * ADVANCED: |
| * Set the weight of the mapping, used to sort mappings |
| * DirectToField Mappings have a default weight of 1 while all other Mappings have a |
| * default weight of MAXINT. Ordering of Mappings can be achieved by setting the weight of |
| * a particular mapping to a value within the above mentioned limits. By ordering mappings |
| * the user can control what order relationships are processed by TopLink. |
| */ |
| |
| // CR 4097 |
| public void setWeight(Integer newWeight) { |
| this.weight = newWeight; |
| } |
| |
| /** |
| * ADVANCED: |
| * This method is used to add an object to a collection once the changeSet is applied. |
| * The referenceKey parameter should only be used for direct Maps. |
| */ |
| public void simpleAddToCollectionChangeRecord(Object referenceKey, Object changeSetToAdd, ObjectChangeSet changeSet, AbstractSession session) throws DescriptorException { |
| throw DescriptorException.invalidMappingOperation(this, "simpleAddToCollectionChangeRecord"); |
| } |
| |
| /** |
| * ADVANCED: |
| * This method is used to remove an object from a collection once the changeSet is applied. |
| * The referenceKey parameter should only be used for direct Maps. |
| */ |
| public void simpleRemoveFromCollectionChangeRecord(Object referenceKey, Object changeSetToAdd, ObjectChangeSet changeSet, AbstractSession session) throws DescriptorException { |
| throw DescriptorException.invalidMappingOperation(this, "simpleRemoveFromCollectionChangeRecord"); |
| } |
| |
| /** |
| * INTERNAL: |
| * Print the mapping attribute name, this is used in error messages. |
| */ |
| @Override |
| public String toString() { |
| return getClass().getName() + "[" + getAttributeName() + "]"; |
| } |
| |
| /** |
| * INTERNAL: |
| * Allow for subclasses to perform validation. |
| */ |
| public void validateAfterInitialization(AbstractSession session) throws DescriptorException { |
| } |
| |
| /** |
| * INTERNAL: |
| * Allow for subclasses to perform validation. |
| */ |
| public void validateBeforeInitialization(AbstractSession session) throws DescriptorException { |
| } |
| |
| /** |
| * INTERNAL: |
| * A subclass should extract the value from the object for the field, if it does not map the field then |
| * it should return null. |
| * Return the Value from the object. |
| */ |
| @Override |
| public Object valueFromObject(Object anObject, DatabaseField field, AbstractSession session) { |
| return null; |
| } |
| |
| /** |
| * INTERNAL: |
| * A subclass should implement this method if it wants different behavior. |
| * Returns the value for the mapping from the database row. |
| */ |
| public Object valueFromRow(AbstractRecord row, JoinedAttributeManager joinManager, ObjectBuildingQuery query, boolean isTargetProtected) throws DatabaseException { |
| return valueFromRow(row, joinManager, query, null, query.getExecutionSession(), isTargetProtected, null); |
| } |
| |
| /** |
| * INTERNAL: |
| * A subclass should implement this method if it wants different behavior. |
| * Returns the value for the mapping from the database row. |
| * The execution session is the session the query was executed on, |
| * and its platform should be used for data conversion. |
| */ |
| public Object valueFromRow(AbstractRecord row, JoinedAttributeManager joinManager, ObjectBuildingQuery query, CacheKey cacheKey, AbstractSession session, boolean isTargetProtected, Boolean[] wasCacheUsed) throws DatabaseException { |
| return null; |
| } |
| |
| /** |
| * INTERNAL: |
| * Indicates whether the mapping is in SerializedObjectPolicy's sopObject. |
| */ |
| public boolean isInSopObject() { |
| return this.isInSopObject == null || this.isInSopObject; |
| } |
| |
| /** |
| * INTERNAL: |
| * Indicates whether the mapping is in SerializedObjectPolicy's sopObject and not out of it. |
| */ |
| public boolean isInOnlySopObject() { |
| return this.isInSopObject != null && this.isInSopObject; |
| } |
| |
| /** |
| * INTERNAL: |
| * Indicates whether the mapping is out of SerializedObjectPolicy's sopObject. |
| */ |
| public boolean isOutSopObject() { |
| return this.isInSopObject == null || !this.isInSopObject; |
| } |
| |
| /** |
| * INTERNAL: |
| * Indicates whether the mapping is out of SerializedObjectPolicy's sopObject and not in it. |
| */ |
| public boolean isOutOnlySopObject() { |
| return this.isInSopObject != null && !this.isInSopObject; |
| } |
| |
| /** |
| * INTERNAL: |
| * Indicates whether the mapping is both in and out of SerializedObjectPolicy's sopObject. |
| */ |
| public boolean isInAndOutSopObject() { |
| return this.isInSopObject == null; |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the mapping is in SerializedObjectPolicy's sopObject. |
| */ |
| public void setIsInSopObject() { |
| this.isInSopObject = Boolean.TRUE; |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the mapping is out of SerializedObjectPolicy's sopObject. |
| */ |
| public void setIsOutSopObject() { |
| this.isInSopObject = Boolean.FALSE; |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the mapping is both in and out of SerializedObjectPolicy's sopObject |
| */ |
| public void setIsInAndOutSopObject() { |
| this.isInSopObject = null; |
| } |
| |
| /** |
| * INTERNAL: |
| * Indicates whether the mapping (or at least one of its nested mappings, at any nested depth) |
| * references an entity. |
| * To return true the mapping (or nested mapping) should be ForeignReferenceMapping with non-null and non-aggregate reference descriptor. |
| */ |
| public boolean hasNestedIdentityReference() { |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Returns the value for the mapping directly from the result-set. |
| * PERF: Used for optimized object building. |
| */ |
| public Object valueFromResultSet(ResultSet resultSet, ObjectBuildingQuery query, AbstractSession session, DatabaseAccessor accessor, ResultSetMetaData metaData, int columnNumber, DatabasePlatform platform) throws SQLException { |
| throw DescriptorException.invalidMappingOperation(this, "valueFromResultSet"); |
| } |
| |
| /** |
| * INTERNAL: |
| * To verify if the specified object has been deleted or not. |
| */ |
| public boolean verifyDelete(Object object, AbstractSession session) throws DatabaseException { |
| return true; |
| } |
| |
| /** |
| * INTERNAL: |
| * A subclass should implement this method if it wants different behavior. |
| * Write the foreign key values from the attribute to the row. |
| */ |
| |
| public void writeFromAttributeIntoRow(Object attribute, AbstractRecord row, AbstractSession session) |
| { |
| // Do nothing by default. |
| } |
| |
| /** |
| * INTERNAL: |
| * A subclass should implement this method if it wants different behavior. |
| * Write the attribute value from the object to the row. |
| */ |
| public void writeFromObjectIntoRow(Object object, AbstractRecord row, AbstractSession session, WriteType writeType) { |
| // Do nothing by default. |
| } |
| |
| /** |
| * INTERNAL: |
| * This row is built for shallow insert which happens in case of bidirectional inserts. |
| * If mapping overrides this method it must override writeFromObjectIntoRowForUpdateAfterShallowInsert method, too. |
| */ |
| public void writeFromObjectIntoRowForShallowInsert(Object object, AbstractRecord row, AbstractSession session) { |
| writeFromObjectIntoRow(object, row, session, WriteType.INSERT); |
| } |
| |
| /** |
| * INTERNAL: |
| * This row is built for update after shallow insert which happens in case of bidirectional inserts. |
| * It contains the foreign keys with non null values that were set to null for shallow insert. |
| * If mapping overrides writeFromObjectIntoRowForShallowInsert method it must override this one, too. |
| */ |
| public void writeFromObjectIntoRowForUpdateAfterShallowInsert(Object object, AbstractRecord databaseRow, AbstractSession session, DatabaseTable table) { |
| // Do nothing by default. |
| } |
| |
| /** |
| * INTERNAL: |
| * This row is built for update before shallow delete which happens in case of bidirectional inserts. |
| * It contains the same fields as the row built by writeFromObjectIntoRowForUpdateAfterShallowInsert, but all the values are null. |
| */ |
| public void writeFromObjectIntoRowForUpdateBeforeShallowDelete(Object object, AbstractRecord databaseRow, AbstractSession session, DatabaseTable table) { |
| // Do nothing by default. |
| } |
| |
| /** |
| * INTERNAL: |
| * A subclass should implement this method if it wants different behavior. |
| * Write the attribute value from the object to the row. |
| */ |
| public void writeFromObjectIntoRowWithChangeRecord(ChangeRecord changeRecord, AbstractRecord row, AbstractSession session, WriteType writeType) { |
| // Do nothing by default. |
| } |
| |
| /** |
| * INTERNAL: |
| * This row is built for shallow insert which happens in case of bidirectional inserts. |
| */ |
| public void writeFromObjectIntoRowForShallowInsertWithChangeRecord(ChangeRecord changeRecord, AbstractRecord row, AbstractSession session) { |
| writeFromObjectIntoRowWithChangeRecord(changeRecord, row, session, WriteType.INSERT); |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public void writeFromObjectIntoRowForUpdate(WriteObjectQuery query, AbstractRecord row) { |
| writeFromObjectIntoRow(query.getObject(), row, query.getSession(), WriteType.UPDATE); |
| } |
| |
| /** |
| * INTERNAL: |
| * A subclass should implement this method if it wants different behavior. |
| * Write the attribute value from the object to the row. |
| */ |
| public void writeFromObjectIntoRowForWhereClause(ObjectLevelModifyQuery query, AbstractRecord row) { |
| Object object; |
| if (query.isDeleteObjectQuery()) { |
| object = query.getObject(); |
| } else { |
| object = query.getBackupClone(); |
| } |
| writeFromObjectIntoRow(object, row, query.getSession(), WriteType.UNDEFINED); |
| } |
| |
| /** |
| * INTERNAL: |
| * Write fields needed for insert into the template for with null values. |
| */ |
| public void writeInsertFieldsIntoRow(AbstractRecord databaseRow, AbstractSession session) { |
| // Do nothing by default. |
| } |
| |
| /** |
| * INTERNAL: |
| * Write fields needed for update into the template for with null values. |
| * By default inserted fields are used. |
| */ |
| public void writeUpdateFieldsIntoRow(AbstractRecord databaseRow, AbstractSession session) { |
| writeInsertFieldsIntoRow(databaseRow, session); |
| } |
| |
| /** |
| * INTERNAL: |
| * Either create a new change record or update the change record with the new value. |
| * This is used by attribute change tracking. |
| */ |
| public void updateChangeRecord(Object clone, Object newValue, Object oldValue, ObjectChangeSet objectChangeSet, UnitOfWorkImpl uow) throws DescriptorException { |
| throw DescriptorException.invalidMappingOperation(this, "updateChangeRecord"); |
| } |
| |
| /** |
| * INTERNAL: |
| * Add or removes a new value and its change set to the collection change record based on the event passed in. This is used by |
| * attribute change tracking. |
| */ |
| public void updateCollectionChangeRecord(org.eclipse.persistence.descriptors.changetracking.CollectionChangeEvent event, ObjectChangeSet objectChangeSet, UnitOfWorkImpl uow) throws DescriptorException { |
| throw DescriptorException.invalidMappingOperation(this, "updateCollectionChangeRecord"); |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the change listener if required. |
| * This is required for collections and aggregates or other change tracked mutable objects. |
| * This is used for resuming or flushing units of work. |
| */ |
| public void setChangeListener(Object clone, PropertyChangeListener listener, UnitOfWorkImpl uow) { |
| // Nothing by default. |
| } |
| |
| /** |
| * ADVANCED: |
| * Used to indicate the mapping references a JPA ID or MapsId attribute |
| * for the CMP3Policy and JPA Id classes (as well as Embeddable Id classes). |
| * This is different from isPrimaryKeyMapping, as an ID mapping is user |
| * specified and can be read only, as long as another writable mapping for |
| * the field exists. |
| */ |
| public void setDerivesId(boolean derivesId) { |
| this.derivesId = derivesId; |
| } |
| |
| /** |
| * ADVANCED: |
| * Used to indicate the mapping references a JPA ID or MapsId attribute |
| * for the CMP3Policy and JPA Id classes (as well as Embeddable Id classes). |
| * This is different from isPrimaryKeyMapping, as an ID mapping is user |
| * specified and can be read only, as long as another writable mapping for |
| * the field exists. |
| */ |
| public void setDerivedIdMapping(DatabaseMapping derivedIdMapping) { |
| this.derivedIdMapping = derivedIdMapping; |
| } |
| |
| /** |
| * INTERNAL: |
| * Directly build a change record without comparison |
| */ |
| public ChangeRecord buildChangeRecord(Object newValue, ObjectChangeSet owner, AbstractSession session) throws DescriptorException { |
| throw DescriptorException.invalidMappingOperation(this, "buildChangeRecord"); |
| } |
| |
| /** |
| * INTERNAL: |
| * Overridden by mappings that require additional processing of the change record after the record has been calculated. |
| */ |
| public void postCalculateChanges(org.eclipse.persistence.sessions.changesets.ChangeRecord changeRecord, UnitOfWorkImpl uow) { |
| } |
| /** |
| * INTERNAL: |
| * Overridden by mappings that require objects to be deleted contribute to change set creation. |
| */ |
| public void postCalculateChangesOnDeleted(Object deletedObject, UnitOfWorkChangeSet uowChangeSet, UnitOfWorkImpl uow) { |
| } |
| |
| /** |
| * INTERNAL: |
| * Overridden by mappings that require objects to be deleted contribute to change set creation. |
| */ |
| public void recordPrivateOwnedRemovals(Object object, UnitOfWorkImpl uow) { |
| } |
| } |