275 lines
9.4 KiB
Java
Executable File
275 lines
9.4 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.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
|
|
* <code>ObjectCopier</code> 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 <a href="mailto:sfreidin@arsdigita.com">Stanislav Freidin</a>
|
|
* @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
|
|
* <code>VersionCopier</code> with a given Lifecycle
|
|
*
|
|
* @param lifecycle The Lifecycle
|
|
*/
|
|
VersionCopier(final Lifecycle lifecycle) {
|
|
m_traversedComponents = new HashSet();
|
|
m_lifecycle = lifecycle;
|
|
}
|
|
|
|
/**
|
|
* Creates a new
|
|
* <code>VersionCopier</code> 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
|
|
* <code>source</code> and then traverses its associations and repeats the
|
|
* process.
|
|
*
|
|
* @param source the
|
|
* <code>DomainObject</code> 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: <dl> <dt>
|
|
* <code>object instanceof ContentItem && prop.isComponent()</code></dt>
|
|
* <dd> Copy ContentItem recursively, setting the version attribute,
|
|
* etc.</dd> <dt>
|
|
* <code>object instanceof ContentItem &&
|
|
* !prop.isComponent() (and target is an already-traversed
|
|
* component of the top-level item )</code></dt> <dd> Return reference to
|
|
* already-created copy of this item</dd> <dt>
|
|
* <code>object instanceof ContentItem &&
|
|
* !prop.isComponent() && prop.isRequired (and target is not an already-traversed
|
|
* component of the top-level item )</code></dt> <dd> Assert failure:
|
|
* required top-level item associations are not allowed here.</dd> <dt>
|
|
* <code>object instanceof ContentItem &&
|
|
* !prop.isComponent() && !prop.isRequired (and target is not an already-traversed
|
|
* component of the top-level item )</code></dt> <dd> Create PublishedLink
|
|
* for association; return null</dd> <dt>
|
|
* <code>!object instanceof ContentItem </code></dt> <dd> object is not a
|
|
* ContentItem, rely on default DomainCopier behavior</dd> </dl>
|
|
*
|
|
* @param source the
|
|
* <code>DomainObject</code> being copied
|
|
* @param target the new copy
|
|
* @param prop the
|
|
* <code>Property</code> 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;
|
|
}
|
|
}
|