/* * 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 ItemCopier by maintaining a Map of * OID->DataObject of all objects copied so far. This ensures that no * infinite recursion loops ever occur. *

* The {@link #copyItem(ContentItem)} method attempts to copy an item by * using the following steps: *

    *
  1. Copy the scalar attributes of the item
  2. *
  3. Copy the 1..1 associations of the item
  4. *
  5. Save the item
  6. *
  7. Copy the 0..n associations of the item
  8. *
  9. Save the item
  10. *
  11. Transfer all services (such as categorization) from the original item to * the copy
  12. *
* 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. *

* ObjectCopier 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. *

* * @author Stanislav Freidin * @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 source and * target implement CustomCopy, and only * call super.copyProperty if the above returns false. * * * @param source the DomainObject being copied * @param target the new copy * @param prop the Property 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 object. * * This implementation returns the result of {@link * #copy(DomainObject)} if the property is a component and simply * returns object if it is not. * * @param source the CustomCopy source (original) * object to which this property belongs * @param target the new CustomCopy copy to which * the return value of this method will be attached * @param object the DomainObject property being * copied * @param prop a Property representing * object * @return object if prop is not a * component or a copy of object it is a component * @throws UnsupportedOperationException if either source or * target are not DomainObjects */ 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 copyServices. * * @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? } } }