189 lines
7.1 KiB
Java
Executable File
189 lines
7.1 KiB
Java
Executable File
/*
|
|
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public License
|
|
* as published by the Free Software Foundation; either version 2.1 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
package com.arsdigita.cms;
|
|
|
|
import com.arsdigita.domain.DomainObject;
|
|
import com.arsdigita.persistence.metadata.Property;
|
|
import org.apache.log4j.Logger;
|
|
|
|
/**
|
|
* Recursively copies a DataObject, and all of its composite sub-objects.
|
|
* This class implements <code>ItemCopier</code> by maintaining a Map of
|
|
* OID->DataObject of all objects copied so far. This ensures that no
|
|
* infinite recursion loops ever occur.
|
|
* <p>
|
|
* The {@link #copyItem(ContentItem)} method attempts to copy an item by
|
|
* using the following steps:
|
|
* <ol>
|
|
* <li>Copy the scalar attributes of the item</li>
|
|
* <li>Copy the 1..1 associations of the item</li>
|
|
* <li>Save the item</li>
|
|
* <li>Copy the 0..n associations of the item</li>
|
|
* <li>Save the item</li>
|
|
* <li>Transfer all services (such as categorization) from the original item to
|
|
* the copy</li>
|
|
* </ol>
|
|
* At each copying step, this class will call
|
|
* {@link ContentItem#copyProperty(ContentItem, String, ItemCopier)}
|
|
* in order to give the item a chance to override the default copying behavior.
|
|
* This class will pass itself as the third argument.
|
|
* <p>
|
|
* <code>ObjectCopier</code> has package-scope since it will only be accessed from
|
|
* {@link ContentItem}, as part of the internal implementation of the
|
|
* {@link ContentItem#copy()} method. Classes outside the package should not
|
|
* attempt to call methods on this class directly, since the results may
|
|
* prove dangerous.
|
|
* <p>
|
|
*
|
|
* @author <a href="mailto:sfreidin@arsdigita.com">Stanislav Freidin</a>
|
|
* @version $Id: ObjectCopier.java 754 2005-09-02 13:26:17Z sskracic $
|
|
* @see ContentItem
|
|
* @see ContentItem#copyProperty(ContentItem, String, ItemCopier)
|
|
*/
|
|
class ObjectCopier extends DomainCopier implements ItemCopier {
|
|
public static final String versionId =
|
|
"$Id: ObjectCopier.java 754 2005-09-02 13:26:17Z sskracic $" +
|
|
"$Author: sskracic $" +
|
|
"$DateTime: 2004/08/17 23:15:09 $";
|
|
|
|
private static Logger s_log = Logger.getLogger(ObjectCopier.class);
|
|
|
|
/**
|
|
* This copier is used to create plain copies for items
|
|
*/
|
|
public int getCopyType() {
|
|
return ItemCopier.PLAIN_COPY;
|
|
}
|
|
|
|
/**
|
|
* Copy a {@link ContentItem}, along with all of its component
|
|
* sub-objects, and return the copy. Note that the categories to
|
|
* which the source item belongs are not automatically transferred
|
|
* to the copy; the user must call {@link #copyServices(ContentItem,
|
|
* ContentItem)} in order to transfer the categories and other
|
|
* services.
|
|
*
|
|
* @param item the item to be copied
|
|
* @return a copy of the item
|
|
*/
|
|
public ContentItem copyItem(ContentItem item) {
|
|
final ContentItem copy = (ContentItem) copy(item);
|
|
return copy;
|
|
}
|
|
|
|
/**
|
|
* Copies properties. This method is called from {@link
|
|
* #copy(DomainObject)} for each property of the object being
|
|
* copied.
|
|
*
|
|
* This implementation calls {@link CustomCopy#copyProperty(CustomCopy,
|
|
* Property, itemCopier)} if <code>source</code> and
|
|
* <code>target</code> implement <code>CustomCopy</code>, and only
|
|
* call <code>super.copyProperty</code> if the above returns false.
|
|
*
|
|
*
|
|
* @param source the <code>DomainObject</code> being copied
|
|
* @param target the new copy
|
|
* @param prop the <code>Property</code> currently under
|
|
* consideration
|
|
*/
|
|
protected void copyProperty(final DomainObject source,
|
|
final DomainObject target,
|
|
final Property prop) {
|
|
m_trace.enter("copyProperty", source, target, prop);
|
|
|
|
if (target instanceof CustomCopy) {
|
|
|
|
final CustomCopy sitem = (CustomCopy) source;
|
|
final CustomCopy titem = (CustomCopy) target;
|
|
|
|
if (titem.copyProperty(sitem, prop, this)) {
|
|
s_log.debug("The target item overrides the default " +
|
|
"behavior to propogate the property; " +
|
|
"skipping it");
|
|
|
|
m_trace.exit("copyProperty");
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
super.copyProperty(source, target, prop);
|
|
|
|
m_trace.exit("copyProperty");
|
|
}
|
|
|
|
/**
|
|
* Creates a copy, by reference or by value, of the property
|
|
* represented in <code>object</code>.
|
|
*
|
|
* This implementation returns the result of {@link
|
|
* #copy(DomainObject)} if the property is a component and simply
|
|
* returns <code>object</code> if it is not.
|
|
*
|
|
* @param source the <code>CustomCopy</code> source (original)
|
|
* object to which this property belongs
|
|
* @param target the new <code>CustomCopy</code> copy to which
|
|
* the return value of this method will be attached
|
|
* @param object the <code>DomainObject</code> property being
|
|
* copied
|
|
* @param prop a <code>Property</code> representing
|
|
* <code>object</code>
|
|
* @return <code>object</code> if <code>prop</code> is not a
|
|
* component or a copy of <code>object</code> it is a component
|
|
* @throws UnsupportedOperationException if either source or
|
|
* target are not <code>DomainObjects</code>
|
|
*/
|
|
public DomainObject copy(final CustomCopy source,
|
|
final CustomCopy target,
|
|
final DomainObject object,
|
|
final Property prop) {
|
|
if ((source instanceof DomainObject) &&
|
|
(target instanceof DomainObject)) {
|
|
return copy((DomainObject) source, (DomainObject) target,
|
|
object, prop);
|
|
} else {
|
|
throw new UnsupportedOperationException
|
|
("CustomCopy implementations should be DomainObjects");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Transfer services from one {@link ContentItem} to another. For
|
|
* example, this method will be called to transfer the categories
|
|
* from the draft version of the item to the live version of the
|
|
* item.
|
|
*
|
|
* Note that the target item must have a valid item ID before this
|
|
* method is called. If the target item is new, it should be saved
|
|
* prior to calling <code>copyServices</code>.
|
|
*
|
|
* @param target the target item
|
|
* @param source the source item
|
|
*/
|
|
public static void copyServices(ContentItem target, ContentItem source) {
|
|
if (target.copyServices(source)) {
|
|
s_log.debug("The target item has opted to do its own " +
|
|
"service propogation");
|
|
} else {
|
|
// What goes here?
|
|
}
|
|
}
|
|
}
|