Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2021 IBM Corporation. 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/13/2009-2.0 mobrien - 294765: MapKey keyType DirectToField processing
// should return attributeClassification class in getMapKeyTargetType when
// accessor.attributeField is null in the absence of a MapKey annotation
// 02/19/2015 - Rick Curtis
// - 458877 : Add national character support
package org.eclipse.persistence.mappings.foundation;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.util.*;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.exceptions.*;
import org.eclipse.persistence.expressions.*;
import org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor;
import org.eclipse.persistence.internal.databaseaccess.DatabasePlatform;
import org.eclipse.persistence.internal.descriptors.*;
import org.eclipse.persistence.internal.expressions.SQLSelectStatement;
import org.eclipse.persistence.internal.helper.*;
import org.eclipse.persistence.internal.identitymaps.CacheKey;
import org.eclipse.persistence.internal.queries.ContainerPolicy;
import org.eclipse.persistence.internal.queries.JoinedAttributeManager;
import org.eclipse.persistence.internal.queries.MappedKeyMapContainerPolicy;
import org.eclipse.persistence.internal.sessions.*;
import org.eclipse.persistence.mappings.converters.*;
import org.eclipse.persistence.mappings.querykeys.DirectQueryKey;
import org.eclipse.persistence.mappings.querykeys.QueryKey;
import org.eclipse.persistence.queries.*;
import org.eclipse.persistence.sessions.remote.*;
import org.eclipse.persistence.sessions.CopyGroup;
import org.eclipse.persistence.sessions.Project;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedClassForName;
/**
* Purpose: Maps an attribute to the corresponding database field type.
* The list of field types that are supported by EclipseLink's direct to field mapping
* is dependent on the relational database being used.
* A converter can be used to convert between the object and data type if they do not match.
*
* @see Converter
* @see ObjectTypeConverter
* @see TypeConversionConverter
* @see SerializedObjectConverter
* @see ClassInstanceConverter
*
* @author Sati
* @since TopLink/Java 1.0
*/
public abstract class AbstractDirectMapping extends AbstractColumnMapping implements MapKeyMapping {
/** To specify the conversion type */
protected transient Class> attributeClassification;
protected String attributeClassificationName;
/** PERF: Also store object class of attribute in case of primitive. */
protected transient Class> attributeObjectClassification;
/** Support specification of the value to use for null. */
protected transient Object nullValue;
protected DatabaseTable keyTableForMapKey = null;
protected String fieldClassificationClassName = null;
/** PERF: Avoid default null value conversion check if not default null value set in conversion manager. */
protected boolean bypassDefaultNullValueCheck;
/**
* PERF: Indicates if this mapping's attribute is a simple atomic value and cannot be modified, only replaced.
* This is a tri-state to allow user to set to true or false, as default is false but
* some data-types such as Calendar or byte[] or converter types may be desired to be used as mutable.
*/
protected Boolean isMutable;
/**
* Default constructor.
*/
protected AbstractDirectMapping() {
super();
}
/**
* INTERNAL:
* Used when initializing queries for mappings that use a Map.
* Called when the selection query is being initialized to add the fields for the map key to the query.
*/
@Override
public void addAdditionalFieldsToQuery(ReadQuery selectionQuery, Expression baseExpression){
if (selectionQuery.isObjectLevelReadQuery()){
((ObjectLevelReadQuery)selectionQuery).addAdditionalField(baseExpression.getField(getField()));
} else if (selectionQuery.isDataReadQuery()){
((SQLSelectStatement) selectionQuery.getSQLStatement()).addField(baseExpression.getField(getField()));
}
}
/**
* INTERNAL:
* Used when initializing queries for mappings that use a Map
* Called when the insert query is being initialized to ensure the fields for the map key are in the insert query.
*/
@Override
public void addFieldsForMapKey(AbstractRecord joinRow) {
if (!isReadOnly()){
if (isUpdatable()){
joinRow.put(getField(), null);
}
}
}
/**
* INTERNAL:
* For mappings used as MapKeys in MappedKeyContainerPolicy. Add the target of this mapping to the deleted
* objects list if necessary
*
* This method is used for removal of private owned relationships
* DirectMappings are dealt with in their parent delete, so this is a no-op.
*/
@Override
public void addKeyToDeletedObjectsList(Object object, Map deletedObjects) {
}
/**
* PUBLIC:
* Return true if the attribute for this mapping is a simple atomic value that cannot be modified,
* only replaced.
* This is false by default unless a mutable converter is used such as the SerializedObjectConverter.
* This can be set to false in this case, or if a Calendar or byte[] is desired to be used as a mutable value it can be set to true.
*/
public boolean isMutable() {
if (isMutable == null) {
return false;
}
return isMutable;
}
/**
* PUBLIC:
* Return true if the attribute for this mapping is a simple atomic value that cannot be modified,
* only replaced.
* This is false by default unless a mutable converter is used such as the SerializedObjectConverter.
* This can be set to false in this case, or if a Calendar or byte[] is desired to be used as a mutable value it can be set to true.
*/
public void setIsMutable(boolean isMutable) {
if (isMutable == true) {
this.isMutable = Boolean.TRUE;
} else {
this.isMutable = Boolean.FALSE;
}
}
/**
* INTERNAL:
* Clone the attribute from the clone and assign it to the backup.
*/
@Override
public void buildBackupClone(Object clone, Object backup, UnitOfWorkImpl unitOfWork) {
buildClone(clone, null, backup, null, unitOfWork);
}
/**
* INTERNAL:
* Directly build a change record without comparison
*/
@Override
public ChangeRecord buildChangeRecord(Object clone, ObjectChangeSet owner, AbstractSession session) {
return internalBuildChangeRecord(getAttributeValueFromObject(clone), null, owner);
}
/**
* INTERNAL:
* Clone the attribute from the original and assign it to the clone.
*/
@Override
public void buildClone(Object original, CacheKey cacheKey, Object clone, Integer refreshCascade, AbstractSession cloningSession) {
buildCloneValue(original, clone, cloningSession);
}
/**
* INTERNAL:
* 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.
*/
@Override
public void buildCloneFromRow(AbstractRecord databaseRow, JoinedAttributeManager joinManager, Object clone, CacheKey sharedCacheKey, ObjectBuildingQuery sourceQuery, UnitOfWorkImpl unitOfWork, AbstractSession executionSession) {
// Even though the correct value may exist on the original, we can't
// make that assumption. It is easy to just build it again from the
// row even if copy policy already copied it.
// That optimization is lost.
Object attributeValue = valueFromRow(databaseRow, joinManager, sourceQuery, sharedCacheKey, executionSession, true, null);
setAttributeValueInObject(clone, attributeValue);
}
/**
* INTERNAL:
* Clone the attribute from the original and assign it to the clone.
* If mutability is configured to be true, clone the attribute if it is an instance of
* byte[], java.util.Calendar or java.util.Date (or their subclasses).
*/
public void buildCloneValue(Object original, Object clone, AbstractSession session) {
Object attributeValue = getAttributeValueFromObject(original);
attributeValue = buildCloneValue(attributeValue, session);
setAttributeValueInObject(clone, attributeValue);
}
/**
* INTERNAL:
* Clone the actual value represented by this mapping. Do set the cloned value into the object.
*/
protected Object buildCloneValue(Object attributeValue, AbstractSession session) {
Object newAttributeValue = attributeValue;
if (isMutable() && attributeValue != null) {
// EL Bug 252047 - Mutable attributes are not cloned when isMutable is enabled on a Direct Mapping
if (attributeValue instanceof byte[]) {
int length = ((byte[]) attributeValue).length;
byte[] arrayCopy = new byte[length];
System.arraycopy(attributeValue, 0, arrayCopy, 0, length);
newAttributeValue = arrayCopy;
} else if (attributeValue instanceof Byte[]) {
int length = ((Byte[]) attributeValue).length;
Byte[] arrayCopy = new Byte[length];
System.arraycopy(attributeValue, 0, arrayCopy, 0, length);
newAttributeValue = arrayCopy;
} else if (attributeValue instanceof char[]) {
int length = ((char[]) attributeValue).length;
char[] arrayCopy = new char[length];
System.arraycopy(attributeValue, 0, arrayCopy, 0, length);
newAttributeValue = arrayCopy;
} else if (attributeValue instanceof Character[]) {
int length = ((Character[]) attributeValue).length;
Character[] arrayCopy = new Character[length];
System.arraycopy(attributeValue, 0, arrayCopy, 0, length);
newAttributeValue = arrayCopy;
} else if (attributeValue instanceof Date) {
newAttributeValue = ((Date)attributeValue).clone();
} else if (attributeValue instanceof Calendar) {
newAttributeValue = ((Calendar)attributeValue).clone();
} else {
newAttributeValue = getObjectValue(getFieldValue(attributeValue, session), session);
}
}
return newAttributeValue;
}
/**
* INTERNAL:
* Copy of the attribute of the object.
* This is NOT used for unit of work but for templatizing an object.
*/
@Override
public void buildCopy(Object copy, Object original, CopyGroup group) {
buildCloneValue(original, copy, group.getSession());
}
/**
* Build a clone of the given element in a unitOfWork.
*/
@Override
public Object buildElementClone(Object attributeValue, Object parent, CacheKey cacheKey, Integer refreshCascade, AbstractSession cloningSession, boolean isExisting, boolean isFromSharedCache){
return buildCloneValue(attributeValue, cloningSession);
}
/**
* INTERNAL:
* In case Query By Example is used, this method builds and returns an expression that
* corresponds to a single attribute and it's value for a directToField mapping.
*/
@Override
public Expression buildExpression(Object queryObject, QueryByExamplePolicy policy, Expression expressionBuilder, Map processedObjects, AbstractSession session) {
String attributeName = this.getAttributeName();
Object attributeValue = this.getAttributeValueFromObject(queryObject);
if (!policy.shouldIncludeInQuery(queryObject.getClass(), attributeName, attributeValue)) {
//the attribute name and value pair is not to be included in the query.
return null;
}
Expression expression = expressionBuilder.get(attributeName);
if (attributeValue == null) {
expression = policy.completeExpressionForNull(expression);
} else {
expression = policy.completeExpression(expression, attributeValue, attributeValue.getClass());
}
return expression;
}
/**
* INTERNAL:
* Certain key mappings favor different types of selection query. Return the appropriate
* type of selectionQuery.
*/
@Override
public ReadQuery buildSelectionQueryForDirectCollectionKeyMapping(ContainerPolicy containerPolicy){
DataReadQuery query = new DataReadQuery();
query.setSQLStatement(new SQLSelectStatement());
query.setContainerPolicy(containerPolicy);
return query;
}
/**
* INTERNAL:
* Cascade discover and persist new objects during commit to the map key.
*/
@Override
public void cascadeDiscoverAndPersistUnregisteredNewObjects(Object object, Map newObjects, Map unregisteredExistingObjects, Map visitedObjects, UnitOfWorkImpl uow, boolean getAttributeValueFromObject, Set cascadeErrors){
//objects referenced by this mapping are not registered as they have
// no identity, this is a no-op.
}
/**
* INTERNAL:
* Cascade perform delete through mappings that require the cascade.
*/
@Override
public void cascadePerformRemoveIfRequired(Object object, UnitOfWorkImpl uow, Map visitedObjects, boolean getAttributeValueFromObject) {
//objects referenced by this mapping are not registered as they have
// no identity, this is a no-op.
}
/**
* INTERNAL:
* Cascade perform delete through mappings that require the cascade.
*/
@Override
public void cascadePerformRemoveIfRequired(Object object, UnitOfWorkImpl uow, Map visitedObjects) {
//objects referenced by this mapping are not registered as they have
// no identity, this is a no-op.
}
/**
* INTERNAL:
* Cascade registerNew for Create through mappings that require the cascade.
*/
@Override
public void cascadeRegisterNewIfRequired(Object object, UnitOfWorkImpl uow, Map visitedObjects, boolean getAttributeValueFromObject) {
//objects referenced by this mapping are not registered as they have
// no identity, this is a no-op.
}
/**
* INTERNAL:
* Cascade registerNew for Create through mappings that require the cascade.
*/
@Override
public void cascadeRegisterNewIfRequired(Object object, UnitOfWorkImpl uow, Map visitedObjects) {
//objects referenced by this mapping are not registered as they have
// no identity, this is a no-op.
}
/**
* INTERNAL:
* Compare the clone and backup clone values and return a change record if the value changed.
*/
@Override
public ChangeRecord compareForChange(Object clone, Object backUp, ObjectChangeSet owner, AbstractSession session) {
// same code as write from object into row for update
if (owner.isNew()) {
return internalBuildChangeRecord(getAttributeValueFromObject(clone), null, owner);
} else if (!compareObjects(backUp, clone, session)) {
Object oldValue = null;
if (backUp != null && clone != backUp) {
oldValue = getAttributeValueFromObject(backUp);
}
return internalBuildChangeRecord(getAttributeValueFromObject(clone), oldValue, owner);
}
return null;
}
/**
* INTERNAL:
* For mappings used as MapKeys in MappedKeyContainerPolicy, Delete the passed object if necessary.
*
* This method is used for removal of private owned relationships
* DirectMappings are dealt with in their parent delete, so this is a no-op.
*/
@Override
public void deleteMapKey(Object objectDeleted, AbstractSession session){
}
/**
* INTERNAL:
* Compare the attributes belonging to this mapping for the objects.
*/
@Override
public boolean compareObjects(Object firstObject, Object secondObject, AbstractSession session) {
Object firstValue = getAttributeValueFromObject(firstObject);
Object secondValue = getAttributeValueFromObject(secondObject);
return compareObjectValues(firstValue, secondValue, session);
}
/**
* INTERNAL:
* Compare the attribute values.
*/
protected boolean compareObjectValues(Object firstValue, Object secondValue, AbstractSession session) {
// PERF: Check identity before conversion.
if (firstValue == secondValue) {
return true;
}
if ((firstValue != null) && (secondValue != null)) {
// PERF: Check equals first, as normally no change.
// Also for serialization objects bytes may not be consistent, but equals may work (HashMap).
if (firstValue.equals(secondValue)) {
return true;
}
}
// CR2114 - following two lines modified; getFieldValue() needs class as an argument
firstValue = getFieldValue(firstValue, session);
secondValue = getFieldValue(secondValue, session);
// PERF: Check identity/nulls before special type comparison.
if (firstValue == secondValue) {
return true;
}
if ((firstValue == null) || (secondValue == null)) {
return false;
}
// PERF: Check equals first, as normally no change.
if (firstValue.equals(secondValue)) {
return true;
}
return Helper.comparePotentialArrays(firstValue, secondValue);
}
/**
* INTERNAL:
* Convert all the class-name-based settings in this mapping to actual class-based settings
* This method is implemented by subclasses as necessary.
*/
@Override
public void convertClassNamesToClasses(ClassLoader classLoader){
super.convertClassNamesToClasses(classLoader);
if (getAttributeClassificationName() != null) {
Class> attributeClass = null;
try{
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
try {
attributeClass = AccessController.doPrivileged(new PrivilegedClassForName<>(getAttributeClassificationName(), true, classLoader));
} catch (PrivilegedActionException exception) {
throw ValidationException.classNotFoundWhileConvertingClassNames(getAttributeClassificationName(), exception.getException());
}
} else {
attributeClass = PrivilegedAccessHelper.getClassForName(getAttributeClassificationName(), true, classLoader);
}
} catch (ClassNotFoundException exc){
throw ValidationException.classNotFoundWhileConvertingClassNames(getAttributeClassificationName(), exc);
}
setAttributeClassification(attributeClass);
}
if (fieldClassificationClassName != null){
Class> fieldClassification = null;
try {
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
try {
fieldClassification = AccessController.doPrivileged(new PrivilegedClassForName<>(fieldClassificationClassName, true, classLoader));
} catch (PrivilegedActionException exception) {
throw ValidationException.classNotFoundWhileConvertingClassNames(fieldClassificationClassName, exception.getException());
}
} else {
fieldClassification = PrivilegedAccessHelper.getClassForName(fieldClassificationClassName, true, classLoader);
}
} catch (ClassNotFoundException exc) {
throw ValidationException.classNotFoundWhileConvertingClassNames(fieldClassificationClassName, exc);
} catch (Exception e) {
// Catches IllegalAccessException and InstantiationException
throw ValidationException.classNotFoundWhileConvertingClassNames(fieldClassificationClassName, e);
}
setFieldClassification(fieldClassification);
}
}
/**
* INTERNAL:
* Creates the Array of simple types used to recreate this map.
*/
@Override
public Object createSerializableMapKeyInfo(Object key, AbstractSession session){
return key; // DirectToFields are already simple types.
}
/**
* INTERNAL:
* Create an instance of the Key object from the key information extracted from the map.
* This may return the value directly in case of a simple key or will be used as the FK to load a related entity.
*/
@Override
public List