blob: 0a6aa2d2d97bc9bfcf91ebd7a505c77108fc693c [file] [log] [blame]
/*
* Copyright (c) 2011, 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:
// ailitchev - Bug 244124 - Added to handle copying using AttributeGroup
// Functionality copied from ObjectCopyPolicy
// 09 Jan 2013-2.5 Gordon Yorke
// - 397772: JPA 2.1 Entity Graph Support
package org.eclipse.persistence.sessions;
import java.util.*;
import org.eclipse.persistence.core.queries.CoreAttributeGroup;
import org.eclipse.persistence.internal.localization.*;
import org.eclipse.persistence.queries.AttributeGroup;
/**
* <b>Purpose</b>: Define how an object is to be copied.<p>
* <b>Description</b>: This is for usage with the object copying feature, not the unit of work.
* This is useful for copying an entire object graph as part of the
* host application's logic.<p>
* <b>Responsibilities</b>:<ul>
* <li> Indicate through CASCADE levels the depth relationships will copied.
* <li> Indicate if PK attributes should be copied with existing value or should be reset.
* <li> Copies only the attributes found in the group.
* </ul>
* @see Session#copy(Object, AttributeGroup)
*/
public class CopyGroup extends AttributeGroup {
protected boolean shouldResetPrimaryKey;
protected boolean shouldResetVersion;
protected transient org.eclipse.persistence.internal.sessions.AbstractSession session;
protected Map copies;
/** Policy depth that determines how the copy will cascade to the object's
related parts */
protected int depth;
/** Depth level indicating that NO relationships should be included in the copy.
Relationships that are not copied will include the default value of the object's
instantiation policy */
public static final int NO_CASCADE = 1;
/** Depth level indicating that only relationships with mapping indicated privately-
owned should be copied */
public static final int CASCADE_PRIVATE_PARTS = 2;
/** Depth level indicating that all relationships with mappings should be used when
building the copied object graph */
public static final int CASCADE_ALL_PARTS = 3;
/** Depth level indicating that only the attributes found in the attribute group should be copied */
public static final int CASCADE_TREE = 4;
/**
* PUBLIC:
* By default only copy the attributes found in the attribute group and don't null primary keys.
*/
public CopyGroup() {
super();
// 2612538 - the default size of Map (32) is appropriate
this.copies = new IdentityHashMap();
this.depth = CASCADE_PRIVATE_PARTS;
}
/**
* PUBLIC:
* By default only copy the attributes found in the attribute group and don't null primary keys.
*/
public CopyGroup(String name) {
super(name);
// 2612538 - the default size of Map (32) is appropriate
this.copies = new IdentityHashMap();
this.depth = CASCADE_PRIVATE_PARTS;
}
/**
* PUBLIC:
* Set if the copy should cascade all relationships when copying the object(s).
*/
public void cascadeAllParts() {
setDepth(CASCADE_ALL_PARTS);
}
/**
* PUBLIC:
* Set if the copy should cascade only those relationships that are configured
* as privately-owned.
*/
public void cascadePrivateParts() {
setDepth(CASCADE_PRIVATE_PARTS);
}
/**
* PUBLIC:
* Set if the copy should cascade only those attributes that are found in the group.
*/
public void cascadeTree() {
setDepth(CASCADE_TREE);
}
/**
* PUBLIC:
* Set if the copy should not cascade relationships when copying the object(s)
*/
public void dontCascade() {
setDepth(NO_CASCADE);
}
/**
* INTERNAL: Get the session.
*/
public Map getCopies() {
return copies;
}
/**
* INTERNAL: Return the cascade depth.
*/
public int getDepth() {
return depth;
}
/**
* INTERNAL: Return the session.
*/
public org.eclipse.persistence.internal.sessions.AbstractSession getSession() {
return session;
}
/**
* INTERNAL: Set the copies.
*/
public void setCopies(Map newCopies) {
copies = newCopies;
}
/**
* INTERNAL: Set the cascade depth.
*/
public void setDepth(int newDepth) {
depth = newDepth;
}
/**
* INTERNAL: Set the session.
*/
public void setSession(org.eclipse.persistence.internal.sessions.AbstractSession newSession) {
session = newSession;
}
/**
* PUBLIC:
* Set if the primary key should be reset to null.
*/
public void setShouldResetPrimaryKey(boolean newShouldResetPrimaryKey) {
shouldResetPrimaryKey = newShouldResetPrimaryKey;
}
/**
* PUBLIC:
* Set if the version should be reset to null.
*/
public void setShouldResetVersion(boolean newShouldResetVersion) {
shouldResetVersion = newShouldResetVersion;
}
/**
* PUBLIC:
* Return true if has been configured to CASCADE_ALL_PARTS or CASCADE_PRIVATE_PARTS.
*/
public boolean shouldCascade() {
return getDepth() != NO_CASCADE;
}
/**
* PUBLIC:
* Return true if should CASCADE_ALL_PARTS
*/
public boolean shouldCascadeAllParts() {
return getDepth() == CASCADE_ALL_PARTS;
}
/**
* PUBLIC:
* Return true if should CASCADE_PRIVATE_PARTS
*/
public boolean shouldCascadePrivateParts() {
return getDepth() == CASCADE_PRIVATE_PARTS;
}
/**
* PUBLIC:
* Return true if should CASCADE_TREE
*/
public boolean shouldCascadeTree() {
return getDepth() == CASCADE_TREE;
}
/**
* PUBLIC:
* Return if the primary key should be reset to null.
*/
public boolean shouldResetPrimaryKey() {
return shouldResetPrimaryKey;
}
/**
* PUBLIC:
* Return if the version should be reset to null.
*/
public boolean shouldResetVersion() {
return shouldResetVersion;
}
/**
* INTERNAL:
*/
@Override
protected String toStringAdditionalInfo() {
String depthString = "";
if (shouldCascadeAllParts()) {
depthString = "CASCADE_ALL_PARTS";
} else if (shouldCascadePrivateParts()) {
depthString = "CASCADE_PRIVATE_PARTS";
} else if (shouldCascadeTree()) {
depthString = "CASCADE_TREE";
} else {
depthString = "NO_CASCADE";
}
Object[] args = { depthString, shouldResetPrimaryKey(), shouldResetVersion()};
return ToStringLocalization.buildMessage("depth_reset_key", args);
}
@Override
public void addAttribute(String attributeNameOrPath, CoreAttributeGroup group) {
cascadeTree();
if(group == null) {
super.addAttribute(attributeNameOrPath, (AttributeGroup)null);
} else {
addAttribute(attributeNameOrPath, ((AttributeGroup)group).toCopyGroup());
}
}
public void addAttribute(String attributeNameOrPath, CopyGroup group) {
cascadeTree();
if(group != null) {
group.setCopies(getCopies());
group.cascadeTree();
}
super.addAttribute(attributeNameOrPath, group);
}
@Override
public boolean isCopyGroup() {
return true;
}
@Override
public CopyGroup clone() {
CopyGroup clone = (CopyGroup)super.clone();
clone.copies = new IdentityHashMap();
return clone;
}
/**
* Returns CopyGroup corresponding to the passed (possibly nested) attribute.
*/
@Override
public CopyGroup getGroup(String attributeNameOrPath) {
return (CopyGroup)super.getGroup(attributeNameOrPath);
}
@Override
protected CopyGroup newGroup(String name, CoreAttributeGroup parent) {
CopyGroup copyGroup = new CopyGroup(name);
copyGroup.cascadeTree();
if(parent != null) {
copyGroup.setShouldResetPrimaryKey(((CopyGroup)parent).shouldResetPrimaryKey());
copyGroup.setShouldResetVersion(((CopyGroup)parent).shouldResetVersion());
copyGroup.setCopies(((CopyGroup)parent).getCopies());
}
return copyGroup;
}
}