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, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020 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
// 05/14/2012-2.4 Guy Pelletier
// - 376603: Provide for table per tenant support for multitenant applications
// 02/11/2013-2.5 Guy Pelletier
// - 365931: @JoinColumn(name="FK_DEPT",insertable = false, updatable = true) causes INSERT statement to include this data value that it is associated with
package org.eclipse.persistence.mappings;
import java.util.*;
import org.eclipse.persistence.annotations.CacheKeyType;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.exceptions.*;
import org.eclipse.persistence.expressions.*;
import org.eclipse.persistence.internal.helper.*;
import org.eclipse.persistence.internal.identitymaps.*;
import org.eclipse.persistence.internal.indirection.ProxyIndirectionPolicy;
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.sessions.DatabaseRecord;
import org.eclipse.persistence.queries.*;
import org.eclipse.persistence.internal.descriptors.CascadeLockingPolicy;
import org.eclipse.persistence.internal.descriptors.DescriptorIterator;
import org.eclipse.persistence.internal.descriptors.ObjectBuilder;
import org.eclipse.persistence.internal.expressions.ConstantExpression;
import org.eclipse.persistence.internal.expressions.ObjectExpression;
import org.eclipse.persistence.internal.expressions.FieldExpression;
import org.eclipse.persistence.internal.expressions.ParameterExpression;
import org.eclipse.persistence.internal.expressions.QueryKeyExpression;
import org.eclipse.persistence.internal.expressions.SQLSelectStatement;
import org.eclipse.persistence.mappings.foundation.MapKeyMapping;
import org.eclipse.persistence.mappings.querykeys.OneToOneQueryKey;
import org.eclipse.persistence.mappings.querykeys.QueryKey;
/**
*
Purpose: One to one mappings are used to represent a pointer references
* between two java objects. This mappings is usually represented by a single pointer
* (stored in an instance variable) between the source and target objects. In the relational
* database tables, these mappings are normally implemented using foreign keys.
*
* @author Sati
* @since TOPLink/Java 1.0
*/
public class OneToOneMapping extends ObjectReferenceMapping implements RelationalMapping, MapKeyMapping {
/** Maps the source foreign/primary key fields to the target primary/foreign key fields. */
protected Map sourceToTargetKeyFields;
/** Maps the target primary/foreign key fields to the source foreign/primary key fields. */
protected Map targetToSourceKeyFields;
/** Keeps track of which fields are foreign keys on a per field basis (can have mixed foreign key relationships). */
/** These are used for non-unit of work modification to check if the value of the 1-1 was changed and a deletion is required. */
protected boolean shouldVerifyDelete;
protected transient Expression privateOwnedCriteria;
public DatabaseTable keyTableForMapKey = null;
protected static final String setObject = "setObject";
/** Mechanism holds relationTable and all fields and queries associated with it. */
protected RelationTableMechanism mechanism;
/**
* Define if this mapping is really for a OneToOne relationship.
* This is a backward compatibility issue, in that before the ManyToOneMapping
* was created OneToOneMapping was used for both.
*/
protected boolean isOneToOneRelationship = false;
/**
* Defines if this mapping was built using primary key join columns.
*/
protected boolean isOneToOnePrimaryKeyRelationship = false;
/**
* Keep track of which fields are insertable and updatable.
*/
protected HashSet insertableFields = new HashSet();
protected HashSet updatableFields = new HashSet();
/**
* Keep a reference to the source and target expressions to post initialize
* when building a selection criteria early.
*/
protected transient List sourceExpressionsToPostInitialize;
protected transient List targetExpressionsToPostInitialize;
/**
* Mode for writeFromObjectIntoRowInternal method
*/
protected static enum ShallowMode {
Insert,
UpdateAfterInsert,
UpdateBeforeDelete
}
/**
* PUBLIC:
* Default constructor.
*/
public OneToOneMapping() {
this.selectionQuery = new ReadObjectQuery();
this.sourceToTargetKeyFields = new HashMap(2);
this.targetToSourceKeyFields = new HashMap(2);
this.foreignKeyFields = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
this.sourceExpressionsToPostInitialize = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
this.targetExpressionsToPostInitialize = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
this.isForeignKeyRelationship = false;
this.shouldVerifyDelete = true;
}
/**
* INTERNAL:
*/
@Override
public boolean isRelationalMapping() {
return true;
}
/**
* 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.
*/
public void addAdditionalFieldsToQuery(ReadQuery selectionQuery, Expression baseExpression){
for (DatabaseField field : getForeignKeyFields()) {
if (selectionQuery.isObjectLevelReadQuery()){
((ObjectLevelReadQuery)selectionQuery).addAdditionalField(baseExpression.getField(field));
} else if (selectionQuery.isDataReadQuery()){
((SQLSelectStatement)((DataReadQuery)selectionQuery).getSQLStatement()).addField(field);
}
}
}
/**
* 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
*/
public void addFieldsForMapKey(AbstractRecord joinRow){
Iterator i = getForeignKeyFields().iterator();
while (i.hasNext()){
joinRow.put((DatabaseField)i.next(), null);
}
}
/**
* PUBLIC:
* Define the foreign key relationship in the 1-1 mapping.
* This method is used for composite foreign key relationships,
* that is the source object's table has multiple foreign key fields to
* the target object's primary key fields.
* Both the source foreign key field and the target foreign key field must
* be specified.
* When a foreign key is specified TopLink will automatically populate the
* value for that field from the target object when the object is written to
* the database. If the foreign key is also mapped through a direct-to-field
* then the direct-to-field must be set read-only.
*/
@Override
public void addForeignKeyField(DatabaseField sourceForeignKeyField, DatabaseField targetPrimaryKeyField) {
setIsForeignKeyRelationship(true);
getForeignKeyFields().addElement(sourceForeignKeyField);
getSourceToTargetKeyFields().put(sourceForeignKeyField, targetPrimaryKeyField);
getTargetToSourceKeyFields().put(targetPrimaryKeyField, sourceForeignKeyField);
}
/**
* PUBLIC:
* Define the foreign key relationship in the 1-1 mapping.
* This method is used for composite foreign key relationships,
* that is the source object's table has multiple foreign key fields to
* the target object's primary key fields.
* Both the source foreign key field name and the target foreign key field
* name must be specified.
* When a foreign key is specified TopLink will automatically populate the
* value for that field from the target object when the object is written to
* the database. If the foreign key is also mapped through a direct-to-field
* then the direct-to-field must be set read-only.
*/
public void addForeignKeyFieldName(String sourceForeignKeyFieldName, String targetPrimaryKeyFieldName) {
addForeignKeyField(new DatabaseField(sourceForeignKeyFieldName), new DatabaseField(targetPrimaryKeyFieldName));
}
/**
* PUBLIC:
* Define the target foreign key relationship in the 1-1 mapping.
* This method is used for composite target foreign key relationships,
* that is the target object's table has multiple foreign key fields to
* the source object's primary key fields.
* Both the target foreign key field and the source primary key field must
* be specified.
* The distinction between a foreign key and target foreign key is that the
* 1-1 mapping will not populate the target foreign key value when written
* (because it is in the target table). Normally 1-1's are through foreign
* keys but in bi-directional 1-1's the back reference will be a target
* foreign key. In obscure composite legacy data models a 1-1 may consist of
* a foreign key part and a target foreign key part, in this case both
* method will be called with the correct parts.
*/
@Override
public void addTargetForeignKeyField(DatabaseField targetForeignKeyField, DatabaseField sourcePrimaryKeyField) {
getSourceToTargetKeyFields().put(sourcePrimaryKeyField, targetForeignKeyField);
getTargetToSourceKeyFields().put(targetForeignKeyField, sourcePrimaryKeyField);
}
/**
* PUBLIC:
* Define the target foreign key relationship in the 1-1 mapping.
* This method is used for composite target foreign key relationships,
* that is the target object's table has multiple foreign key fields to
* the source object's primary key fields.
* Both the target foreign key field name and the source primary key field
* name must be specified.
* The distinction between a foreign key and target foreign key is that the
* 1-1 mapping will not populate the target foreign key value when written
* (because it is in the target table). Normally 1-1's are through foreign
* keys but in bi-directional 1-1's the back reference will be a target
* foreign key. In obscure composite legacy data models a 1-1 may consist of
* a foreign key part and a target foreign key part, in this case both
* method will be called with the correct parts.
*/
public void addTargetForeignKeyFieldName(String targetForeignKeyFieldName, String sourcePrimaryKeyFieldName) {
addTargetForeignKeyField(new DatabaseField(targetForeignKeyFieldName), new DatabaseField(sourcePrimaryKeyFieldName));
}
/**
* 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.
*/
public void addKeyToDeletedObjectsList(Object object, Map deletedObjects){
deletedObjects.put(object, object);
}
/**
* Build a clone of the given element in a unitOfWork.
*/
public Object buildElementClone(Object attributeValue, Object parent, CacheKey cacheKey, Integer refreshCascade, AbstractSession cloningSession, boolean isExisting, boolean isFromSharedCache){
return buildCloneForPartObject(attributeValue, null, cacheKey, parent, cloningSession, refreshCascade, isExisting, isFromSharedCache);
}
/**
* INTERNAL:
* Used to allow object level comparisons.
*/
public Expression buildObjectJoinExpression(Expression expression, Object value, AbstractSession session) {
Expression base = ((ObjectExpression)expression).getBaseExpression();
Expression foreignKeyJoin = null;
if(this.mechanism == null) {
// Allow for equal null.
if (value == null) {
if (!isForeignKeyRelationship()) {
// ELBug#331352
// Need to do a join and compare target foreign key to null.
for (DatabaseField field : getSourceToTargetKeyFields().values()) {
Expression join = null;
join = expression.getField(field).equal(null);
if (foreignKeyJoin == null) {
foreignKeyJoin = join;
} else {
foreignKeyJoin = foreignKeyJoin.and(join);
}
}
} else {
for (DatabaseField field : getSourceToTargetKeyFields().keySet()) {
Expression join = null;
join = base.getField(field).equal(null);
if (foreignKeyJoin == null) {
foreignKeyJoin = join;
} else {
foreignKeyJoin = foreignKeyJoin.and(join);
}
}
}
} else {
if (!getReferenceDescriptor().getJavaClass().isInstance(value)) {
// Bug 3894351 - ensure any proxys are triggered so we can do a proper class comparison
value = ProxyIndirectionPolicy.getValueFromProxy(value);
if (!getReferenceDescriptor().getJavaClass().isInstance(value)) {
throw QueryException.incorrectClassForObjectComparison(base, value, this);
}
}
Iterator keyIterator = Arrays.asList(((CacheId)extractKeyFromReferenceObject(value, session)).getPrimaryKey()).iterator();
for (DatabaseField field : getSourceToTargetKeyFields().keySet()) {
Expression join = null;
join = base.getField(field).equal(keyIterator.next());
if (foreignKeyJoin == null) {
foreignKeyJoin = join;
} else {
foreignKeyJoin = foreignKeyJoin.and(join);
}
}
}
} else {
int size = this.mechanism.sourceKeyFields.size();
Object key = null;
if (value != null) {
if (!getReferenceDescriptor().getJavaClass().isInstance(value)) {
// Bug 3894351 - ensure any proxys are triggered so we can do a proper class comparison
value = ProxyIndirectionPolicy.getValueFromProxy(value);
if (!getReferenceDescriptor().getJavaClass().isInstance(value)) {
throw QueryException.incorrectClassForObjectComparison(base, value, this);
}
}
key = extractKeyFromReferenceObject(value, session);
boolean allNulls = true;
for (int i=0; i < size; i++) {
if (((CacheId)key).getPrimaryKey()[i] != null) {
allNulls = false;
break;
}
}
// the same case
if (allNulls) {
value = null;
}
}
if (value != null) {
for(int i=0; i < size; i++) {
DatabaseField field = this.mechanism.sourceKeyFields.get(i);
Expression join = null;
join = base.getField(field).equal(((CacheId)key).getPrimaryKey()[i]);
if (foreignKeyJoin == null) {
foreignKeyJoin = join;
} else {
foreignKeyJoin = foreignKeyJoin.and(join);
}
}
} else {
ReportQuery subQuery = new ReportQuery(this.descriptor.getJavaClass(), new ExpressionBuilder());
Expression relationTableExp = subQuery.getExpressionBuilder().getTable(this.mechanism.relationTable);
Expression subSelectExp = null;
for(int i=0; i < size; i++) {
subSelectExp = relationTableExp.getField(this.mechanism.sourceRelationKeyFields.get(i)).equal(base.getField(this.mechanism.sourceKeyFields.get(i))).and(subSelectExp);
}
subQuery.setSelectionCriteria(subSelectExp);
subQuery.dontRetrievePrimaryKeys();
subQuery.addAttribute("", subQuery.getExpressionBuilder().getField(this.mechanism.sourceKeyFields.get(0)));
foreignKeyJoin = base.notExists(subQuery);
}
}
return foreignKeyJoin;
}
/**
* INTERNAL:
* Used to allow object level comparisons.
*/
public Expression buildObjectJoinExpression(Expression expression, Expression argument, AbstractSession session) {
Expression base = ((org.eclipse.persistence.internal.expressions.ObjectExpression)expression).getBaseExpression();
Expression foreignKeyJoin = null;
if(this.mechanism == null) {
if (expression==argument){
for (Iterator sourceFieldsEnum = getSourceToTargetKeyFields().keySet().iterator();
sourceFieldsEnum.hasNext();) {
DatabaseField field = (DatabaseField)sourceFieldsEnum.next();
Expression join = base.getField(field);
join = join.equal(join);
if (foreignKeyJoin == null) {
foreignKeyJoin = join;
} else {
foreignKeyJoin = foreignKeyJoin.and(join);
}
}
}else{
Iterator targetFieldsEnum = getSourceToTargetKeyFields().values().iterator();
for (Iterator sourceFieldsEnum = getSourceToTargetKeyFields().keySet().iterator();
sourceFieldsEnum.hasNext();) {
DatabaseField sourceField = (DatabaseField)sourceFieldsEnum.next();
DatabaseField targetField = (DatabaseField)targetFieldsEnum.next();
Expression join = null;
join = base.getField(sourceField).equal(argument.getField(targetField));
if (foreignKeyJoin == null) {
foreignKeyJoin = join;
} else {
foreignKeyJoin = foreignKeyJoin.and(join);
}
}
}
} else {
if (expression==argument){
foreignKeyJoin = (new ConstantExpression(0, base)).equal(new ConstantExpression(0, base));
}else{
int size = this.mechanism.sourceKeyFields.size();
Expression relTable = base.getTable(this.mechanism.getRelationTable());
for(int i=0; i < size; i++) {
Expression source = base.getField(this.mechanism.sourceKeyFields.get(i));
Expression sourceRel = relTable.getField(this.mechanism.sourceRelationKeyFields.get(i));
Expression targetRel = relTable.getField(this.mechanism.targetRelationKeyFields.get(i));
Expression target = argument.getField(this.mechanism.targetKeyFields.get(i));
foreignKeyJoin = source.equal(sourceRel).and(targetRel.equal(target)).and(foreignKeyJoin);
}
}
}
return foreignKeyJoin;
}
/**
* INTERNAL:
* Certain key mappings favor different types of selection query. Return the appropriate
* type of selectionQuery
* @return
*/
public ReadQuery buildSelectionQueryForDirectCollectionKeyMapping(ContainerPolicy containerPolicy){
DataReadQuery query = new DataReadQuery();
query.setSQLStatement(new SQLSelectStatement());
query.setContainerPolicy(containerPolicy);
return query;
}
/**
* INTERNAL:
* This methods clones all the fields and ensures that each collection refers to
* the same clones.
*/
@Override
public Object clone() {
OneToOneMapping clone = (OneToOneMapping)super.clone();
if(this.mechanism == null) {
clone.setForeignKeyFields(org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(getForeignKeyFields().size()));
clone.setSourceToTargetKeyFields(new HashMap(getSourceToTargetKeyFields().size()));
clone.setTargetToSourceKeyFields(new HashMap(getTargetToSourceKeyFields().size()));
// DatabaseField overrides equals, so we need to use an IdentifyHashMap for this implementation
// to make sure we are using the object references to lookup clone references
AbstractMap fieldToCloneMap = new IdentityHashMap(getTargetToSourceKeyFields().size());
//clone foreign keys and save the clones in a lookup table
for (Enumeration enumtr = getForeignKeyFields().elements(); enumtr.hasMoreElements();) {
DatabaseField field = enumtr.nextElement();
DatabaseField fieldClone = field.clone();
fieldToCloneMap.put(field, fieldClone);
clone.getForeignKeyFields().addElement(fieldClone);
}
// lookup references in the map to get the associated clone reference. If it doesn't exist, create a new one.
for (Iterator sourceEnum = getSourceToTargetKeyFields().keySet().iterator();
sourceEnum.hasNext();) {
DatabaseField sourceField = sourceEnum.next();
DatabaseField targetField = getSourceToTargetKeyFields().get(sourceField);
DatabaseField targetClone;
DatabaseField sourceClone;
targetClone = fieldToCloneMap.get(targetField);
if (targetClone == null) {
targetClone = targetField.clone();
fieldToCloneMap.put(targetField, targetClone);
}
sourceClone = fieldToCloneMap.get(sourceField);
if (sourceClone == null) {
sourceClone = sourceField.clone();
fieldToCloneMap.put(sourceField, sourceClone);
}
clone.getSourceToTargetKeyFields().put(sourceClone, targetClone);
}
// lookup references in the map to get the associated clone reference. If it doesn't exist, create a new one.
for (Iterator targetEnum = getTargetToSourceKeyFields().keySet().iterator();
targetEnum.hasNext();) {
DatabaseField targetField = targetEnum.next();
DatabaseField sourceField = getTargetToSourceKeyFields().get(targetField);
DatabaseField targetClone;
DatabaseField sourceClone;
targetClone = fieldToCloneMap.get(targetField);
if (targetClone == null) {
targetClone = targetField.clone();
fieldToCloneMap.put(targetField, targetClone);
}
sourceClone = fieldToCloneMap.get(sourceField);
if (sourceClone == null) {
sourceClone = sourceField.clone();
fieldToCloneMap.put(sourceField, sourceClone);
}
clone.getTargetToSourceKeyFields().put(targetClone, sourceClone);
}
} else {
clone.mechanism = (RelationTableMechanism)this.mechanism.clone();
}
return clone;
}
@Override
public void collectQueryParameters(Set cacheFields){
for (DatabaseField field : sourceToTargetKeyFields.keySet()) {
cacheFields.add(field);
}
}
/**
* INTERNAL
* Called when a DatabaseMapping is used to map the key in a collection. Returns the key.
*/
public Object createMapComponentFromRow(AbstractRecord dbRow, ObjectBuildingQuery query, CacheKey parentCacheKey, AbstractSession session, boolean isTargetProtected){
return session.executeQuery(getSelectionQuery(), dbRow);
}
/**
* INTERNAL:
* Creates the Array of simple types used to recreate this map.
*/
public Object createSerializableMapKeyInfo(Object key, AbstractSession session){
return referenceDescriptor.getObjectBuilder().extractPrimaryKeyFromObject(key, session);
}
/**
* 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.
*/
public List