/*
* 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.cms.lifecycle.Lifecycle;
import com.arsdigita.cms.lifecycle.LifecycleService;
import com.arsdigita.domain.DomainObject;
import com.arsdigita.kernel.ACSObject;
import com.arsdigita.persistence.metadata.Property;
import com.arsdigita.persistence.OID;
import com.arsdigita.util.Assert;
import org.apache.log4j.Logger;
import java.util.HashSet;
/**
* Extends
* ObjectCopier to create a live version for an item. Clones the
* item, making sure that live versions of all subitems point only to other live
* versions.
*
* @author Stanislav Freidin
* @version $Id: VersionCopier.java 2140 2011-01-16 12:04:20Z pboy $
*/
class VersionCopier extends ObjectCopier {
private static Logger s_log = Logger.getLogger(VersionCopier.class);
private final Lifecycle m_lifecycle;
private boolean m_once = false;
private long m_start = 0;
private final HashSet m_traversedComponents;
private OID m_topLevelSourceOID = null;
/**
* Creates a new
* VersionCopier with a given Lifecycle
*
* @param lifecycle The Lifecycle
*/
VersionCopier(final Lifecycle lifecycle) {
m_traversedComponents = new HashSet();
m_lifecycle = lifecycle;
}
/**
* Creates a new
* VersionCopier with no Lifecycle
*/
VersionCopier() {
m_traversedComponents = new HashSet();
m_lifecycle = null;
}
/**
* 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
*/
@Override
public ContentItem copyItem(final ContentItem item) {
m_trace.enter("copyItem", item);
if (s_log.isInfoEnabled()) {
s_log.info("Publishing " + item);
m_start = System.currentTimeMillis();
}
if (Assert.isEnabled()) {
//Assert.isFalse(item instanceof ContentBundle);
//Assert.isFalse(item instanceof Folder);
Assert.isFalse(m_once);
m_once = true;
}
m_topLevelSourceOID = item.getOID();
final ContentItem version = createVersion(item);
//Assert.isTrue(m_topLevelSourceOID == null,
// "CopyItem should be called only once for a given copier instance");
if (m_lifecycle != null) {
LifecycleService.setLifecycle(version, m_lifecycle);
}
m_trace.exit("copyItem", version);
if (Assert.isEnabled()) {
// Reset the reentrance detection.
m_once = false;
}
if (s_log.isInfoEnabled()) {
s_log.info("Done publishing " + item + " (" + (System.
currentTimeMillis()
- m_start)
+ " millis)");
}
return version;
}
/**
* This copier is used to create published copies of items
*/
@Override
public int getCopyType() {
return ItemCopier.VERSION_COPY;
}
/**
* Kicks off the copying process. Creates a copy by value of
* source and then traverses its associations and repeats the
* process.
*
* @param source the
* DomainObject from which to copy
*/
@Override
public DomainObject copy(final DomainObject object) {
if (object != null) {
m_traversedComponents.add(object);
}
return super.copy(object);
}
/**
* Copies properties. This method is called from {@link
* #copy(DomainObject)} for each property of the object being copied.
*
* Copying behavior depends on the following:
object instanceof ContentItem && prop.isComponent()object instanceof ContentItem &&
* !prop.isComponent() (and target is an already-traversed
* component of the top-level item )object instanceof ContentItem &&
* !prop.isComponent() && prop.isRequired (and target is not an already-traversed
* component of the top-level item )object instanceof ContentItem &&
* !prop.isComponent() && !prop.isRequired (and target is not an already-traversed
* component of the top-level item )!object instanceof ContentItem DomainObject being copied
* @param target the new copy
* @param prop the
* Property currently under consideration
*/
@Override
protected DomainObject copy(final DomainObject source,
final DomainObject target,
final DomainObject object,
final Property prop) {
m_trace.enter("copy", object, prop);
if (s_log.isDebugEnabled()) {
s_log.debug("Copying property " + prop + " of " + object);
}
Assert.exists(source, DomainObject.class);
Assert.exists(target, DomainObject.class);
Assert.exists(object, DomainObject.class);
Assert.exists(prop, Property.class);
if (object instanceof ContentItem) {
s_log.debug("The property is a content item");
final ContentItem item = (ContentItem) object;
if (Assert.isEnabled()) {
item.assertDraft();
}
if (prop.isComponent()) {
s_log.debug("The property is a component; creating a "
+ "live or pending version");
final ContentItem copy = createVersion(item);
m_trace.exit("copy", copy);
return copy;
} else if (m_traversedComponents.contains(object)) {
final DomainObject copy = copy(object);
m_trace.exit("copy", copy);
return copy;
} else if (prop.isRequired()) {
Assert.fail(
"1..1 associations to non-component top-level ContentItems are not allowed");
return null;
} else {
s_log.debug("The property is not a component; creating "
+ "PublishedLink for the item");
if (source instanceof ContentItem) {
PublishedLink.create(
(ContentItem) getCopy(m_topLevelSourceOID),
target,
prop.getName(),
item,
(ContentItem) source);
} else {
PublishedLink.create(
(ContentItem) getCopy(m_topLevelSourceOID),
target,
prop.getName(),
item,
null);
}
m_trace.exit("copy", null);
return null;
}
} else {
s_log.debug("The property is not a content item; using "
+ "domain object copier");
final DomainObject copy = super.copy(source, target, object, prop);
m_trace.exit("copy", copy);
return copy;
}
}
private ContentItem createVersion(final ContentItem item) {
m_trace.enter("createVersion", item);
if (Assert.isEnabled()) {
item.assertDraft();
}
final ContentItem version = (ContentItem) copy(item);
s_log.debug("The copy is pending; associating it with "
+ "the draft item");
version.setVersion(ContentItem.PENDING);
item.addPendingVersion(version);
version.copyServicesFrom(item);
m_trace.exit("createVersion", version);
return version;
}
}