diff --git a/Frameworks/Core/ERExtensions/Sources/er/extensions/eof/ERXCopyable.java b/Frameworks/Core/ERExtensions/Sources/er/extensions/eof/ERXCopyable.java new file mode 100644 index 00000000000..d47d7b6b904 --- /dev/null +++ b/Frameworks/Core/ERExtensions/Sources/er/extensions/eof/ERXCopyable.java @@ -0,0 +1,1493 @@ +package er.extensions.eof; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.webobjects.eoaccess.EOAttribute; +import com.webobjects.eoaccess.EOEntity; +import com.webobjects.eoaccess.EOModel; +import com.webobjects.eoaccess.EOProperty; +import com.webobjects.eoaccess.EORelationship; +import com.webobjects.eoaccess.EOUtilities; +import com.webobjects.eocontrol.EOEditingContext; +import com.webobjects.eocontrol.EOEnterpriseObject; +import com.webobjects.eocontrol.EOGlobalID; +import com.webobjects.foundation.NSArray; +import com.webobjects.foundation.NSDictionary; +import com.webobjects.foundation.NSMutableArray; +import com.webobjects.foundation.NSMutableDictionary; +import com.webobjects.foundation.NSMutableSet; +import com.webobjects.foundation.NSTimestamp; + +import er.extensions.foundation.ERXArrayUtilities; + +/** + * This class specifies an interface for flexible copying of + * {@code EOEnterpriseObject}s, a default implementation for doing the actual + * copying, and a Utility class that provides convenience methods to make + * implementing the interface easier. + *
+ * There are several ways to implement this interface: + *
+ * @Override + * public MyEntity copy() { + * MyEntity copy = copy(new NSMutableDictionary<EOGlobalID, ERXCopyable<?>>()); + * return copy; + * } + * + * @Override + * public MyEntity copy(NSMutableDictionary<EOGlobalID, ERXCopyable<?>> copiedObjects) { + * MyEntity copy = ERXCopyable.DefaultImplementation.copy(copiedObjects, (MyEntity) this); + * return copy; + * } + * + * @Override + * public MyEntity duplicate(NSMutableDictionary<EOGlobalID, ERXCopyable<?>> copiedObjects) { + * MyEntity duplicate = ERXCopyable.Utility.deepCopy(copiedObjects, (MyEntity) this); + * return duplicate; + * } + *+ * + *
+ * @Override + * public MyGenericRecord copy() { + * MyGenericRecord copy = copy(new NSMutableDictionary<EOGlobalID, ERXCopyable<?>>()); + * return copy; + * } + * + * @Override + * public MyGenericRecord copy(NSMutableDictionary<EOGlobalID, ERXCopyable<?>> copiedObjects) { + * MyGenericRecord copy = ERXCopyable.DefaultImplementation.copy(copiedObjects, this); + * return copy; + * } + * + * @Override + * public MyGenericRecord duplicate(NSMutableDictionary<EOGlobalID, ERXCopyable<?>> copiedObjects) { + * MyGenericRecord duplicate = ERXCopyable.Utility.deepCopy(copiedObjects, this); + * return duplicate; + * } + *+ * + *
+ * #if(${entity.userInfo.ERXCopyable}) implements ERXCopyable<${entity.classNameWithOptionalPackage}>#end + *+ * + *
+ * #if(${entity.userInfo.ERXCopyable} == 'Model' || ${entity.userInfo.ERXCopyable} == 'Default') + * + * + * public ${entity.classNameWithOptionalPackage} copy() { + * $entity.classNameWithOptionalPackage copy = copy(new NSMutableDictionary+ * + *>()); + * return copy; + * } + * + * public ${entity.classNameWithOptionalPackage} copy(NSMutableDictionary > copiedObjects) { + * ${entity.classNameWithOptionalPackage} copy = ERXCopyable.DefaultImplementation.copy(copiedObjects, (${entity.classNameWithOptionalPackage}) this); + * return copy; + * } + * + * public ${entity.classNameWithOptionalPackage} duplicate(NSMutableDictionary > copiedObjects) { + * #if(${entity.userInfo.ERXCopyable} == 'Model') + * ${entity.classNameWithOptionalPackage} duplicate = ERXCopyable.Utility.modelCopy(copiedObjects, (${entity.classNameWithOptionalPackage}) this); + * #elseif(${entity.userInfo.ERXCopyable} == 'Default') + * ${entity.classNameWithOptionalPackage} duplicate = ERXCopyable.Utility.deepCopy(copiedObjects, (${entity.classNameWithOptionalPackage}) this); + * #end + * return duplicate; + * } + * #end + * + *
+ * {@link Enum} that specifies the valid ways in which an {@link EOModel}'s + * {@link EOProperty}s can be copied. + *
+ *+ * The {@link CopyType} is specified for a given {@link EOProperty} using a + * String entry in the property's UserInfo dictionary with a key of + * {@code ERXCopyable.CopyType} and a value matching (case-insensitively) + * one of the elements of this enum. + *
+ * + * @author David Avendasora + */ + public enum CopyType { + + /** + * For attributes and relationships.Stored as " + * {@code ERXCopyable.CopyType = Nullify;}" in the property's UserInfo + * dictionary. This setting does not copy the {@code original}'s + * value. It sets the {@code copy}'s value tonull
.
+ */
+ NULLIFY("Nullify"),
+
+ /**
+ * For attributes and relationships. Stored as "
+ * {@code ERXCopyable.CopyType = Reference;}" in the {@link EOAttribute}
+ * 's and {@link EORelationship}'s UserInfo dictionary. For attributes
+ * this simply sets the same value on the destination as the source. For
+ * relationships, this sets the {@code copy}'s relationship to point to
+ * the same {@link ERXCopyable} object as the {@code original}'s
+ * relationship does. WARNING: if you use this on a
+ * non-flattening, to-many relationship, the destination objects will be
+ * moved from the {@code original} to the {@code copy}.
+ */
+ REFERENCE("Reference"),
+
+ /**
+ * For relationships only. Stored as "
+ * {@code ERXCopyable.CopyType = Shallow;}" in the
+ * {@link EORelationship}'s UserInfo dictionary. New instances of the
+ * destination {@link ERXCopyable} objects will be made and all of the
+ * original's attributes and relationships will be reference copied.
+ */
+ SHALLOW("Shallow"),
+
+ /**
+ * For relationships only. Stored as "
+ * {@code ERXCopyable.CopyType = Deep;}" in the {@link EORelationship}'s
+ * UserInfo dictionary. Duplicates each of the destination
+ * {@link ERXCopyable} objects using their implementation of the
+ * {@link #duplicate(NSMutableDictionary)} method.
+ */
+ DEEP("Deep"),
+
+ /**
+ * For attributes only. Stored as "
+ * {@code ERXCopyable.CopyType = CurrentTimestamp;}" in the
+ * {@link EOAttribute}'s UserInfo dictionary. This setting does
+ * not copy the {@code original}'s value. It sets the {@code copy}'s
+ * value to the current date and time using
+ * {@code new NSTimestamp()}
+ */
+ CURRENT_TIMESTAMP("CurrentTimestamp");
+
+ private final String _type;
+
+ CopyType(String type) {
+ _type = type;
+ }
+
+ public String type() {
+ return _type;
+ }
+
+ /**
+ * @param typeAsString
+ * a String to match (case-insensitive) to a {@link CopyType}
+ *
+ * @return the {@link CopyType} equivalent to the {@code typeAsString}
+ *
+ * @author David Avendasora
+ */
+ public static CopyType get(String typeAsString) {
+ CopyType copyType = null;
+ if (typeAsString != null) {
+ for (CopyType ct : CopyType.values()) {
+ if (typeAsString.equalsIgnoreCase(ct.type())) {
+ copyType = ct;
+ break;
+ }
+ }
+ }
+ return copyType;
+ }
+ }
+
+ /**
+ * + * This class provides a default implementation of ERXCopyable that handles + * the most common situations encountered copying {@link EOEnterpriseObject} + * s. + *
+ *+ * Notes + *
+ * er.extensions.eof.ERXCopyable}. + *+ * + *
+ * EOGlobalID globalID = editingContext().globalIDForObject(this); + * copiedObjects.setObjectForKey(copy, globalID); + *+ * + *
copiedObjects
dictionary, then that existing copy is
+ * returned instead of making a new copy. This allows complex graphs of
+ * objects, including those with cycles, to be copied without producing
+ * duplicate objects.
+ *
+ * @param
+ * Debugging information can be turned on with the DEBUG level of the log4j
+ * logger er.extensions.eof.ERXCopyable
.
+ *
return this;
on an {@code ERXCopyable}. This method of
+ * copying is suitable for lookup list items and other objects which
+ * should never be duplicated.
+ *
+ * @param + * Creates a new instance of the {@code source}'s Entity, then steps + * through all attributes and relationships, copying them as defined in + * each property's UserInfo dictionary in the EOModel. + *
+ * + *+ * To make use of this method of copying an EO, simply override the + * {@link ERXCopyable#duplicate(NSMutableDictionary) + * duplicate(NSMutableDictionary)} method in your EO with the following: + * + *
+ * public MyEO duplicate(NSMutableDictionary<EOGlobalID, ERXCopyable<?>> copiedObjects) { + * MyEO duplicate = ERXCopyable.Utility.modelCopy(copiedObjects, (MyEO) this); + * return duplicate; + * } + *+ * + * + * + * @param