/*
* Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nuxeo - initial API and implementation
*
* $Id$
*/
package org.eclipse.ecr.core.lifecycle.event;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.ecr.core.NXCore;
import org.eclipse.ecr.core.api.ClientException;
import org.eclipse.ecr.core.api.CoreSession;
import org.eclipse.ecr.core.api.DocumentModel;
import org.eclipse.ecr.core.api.DocumentModelList;
import org.eclipse.ecr.core.api.LifeCycleConstants;
import org.eclipse.ecr.core.event.Event;
import org.eclipse.ecr.core.event.EventBundle;
import org.eclipse.ecr.core.event.EventContext;
import org.eclipse.ecr.core.event.PostCommitEventListener;
import org.eclipse.ecr.core.event.impl.DocumentEventContext;
/**
* Listener for life cycle change events.
* <p>
* If event occurs on a folder, it will recurse on children to perform the same
* transition if possible.
* <p>
* If the transition event is about marking documents as "deleted", and a child
* cannot perform the transition, it will be removed.
* <p>
* Undelete transitions are not processed, but this listener instead looks for a
* specific documentUndeleted event. This is because we want to undelete
* documents (parents) under which we don't want to recurse.
*/
public class BulkLifeCycleChangeListener implements PostCommitEventListener {
private static final Log log = LogFactory.getLog(BulkLifeCycleChangeListener.class);
@Override
public void handleEvent(EventBundle events) throws ClientException {
if (!events.containsEventName(LifeCycleConstants.TRANSITION_EVENT)
&& !events.containsEventName(LifeCycleConstants.DOCUMENT_UNDELETED)) {
return;
}
for (Event event : events) {
String name = event.getName();
if (LifeCycleConstants.TRANSITION_EVENT.equals(name)
|| LifeCycleConstants.DOCUMENT_UNDELETED.equals(name)) {
processTransition(event);
}
}
}
protected void processTransition(Event event) {
log.debug("Processing lifecycle change in async listener");
EventContext ctx = event.getContext();
if (!(ctx instanceof DocumentEventContext)) {
return;
}
DocumentEventContext docCtx = (DocumentEventContext) ctx;
DocumentModel doc = docCtx.getSourceDocument();
if (!doc.isFolder()) {
return;
}
CoreSession session = docCtx.getCoreSession();
if (session == null) {
log.error("Can not process lifeCycle change since session is null");
return;
}
String transition;
String targetState;
if (LifeCycleConstants.TRANSITION_EVENT.equals(event.getName())) {
transition = (String) docCtx.getProperty(LifeCycleConstants.TRANSTION_EVENT_OPTION_TRANSITION);
if (isNonRecursiveTransition(transition, doc.getType())) {
// transition should not recurse into children
return;
}
if (LifeCycleConstants.UNDELETE_TRANSITION.equals(transition)) {
// not processed (as we can undelete also parents)
// a specific event documentUndeleted will be used instead
return;
}
targetState = (String) docCtx.getProperty(LifeCycleConstants.TRANSTION_EVENT_OPTION_TO);
} else { // LifeCycleConstants.DOCUMENT_UNDELETED
transition = LifeCycleConstants.UNDELETE_TRANSITION;
targetState = ""; // unused
}
try {
DocumentModelList docs = session.getChildren(doc.getRef());
changeDocumentsState(session, docs, transition, targetState);
session.save();
} catch (ClientException e) {
log.error("Unable to get children", e);
return;
}
}
protected boolean isNonRecursiveTransition(String transition, String type) {
List<String> nonRecursiveTransitions = NXCore.getLifeCycleService().getNonRecursiveTransitionForDocType(
type);
return nonRecursiveTransitions.contains(transition);
}
// change doc state and recurse in children
protected void changeDocumentsState(CoreSession documentManager,
DocumentModelList docModelList, String transition,
String targetState) throws ClientException {
for (DocumentModel docMod : docModelList) {
boolean removed = false;
if (docMod.getCurrentLifeCycleState() == null) {
if (LifeCycleConstants.DELETED_STATE.equals(targetState)) {
log.debug("Doc has no lifecycle, deleting ...");
documentManager.removeDocument(docMod.getRef());
removed = true;
}
} else if (docMod.getAllowedStateTransitions().contains(transition)) {
docMod.followTransition(transition);
} else {
if (targetState.equals(docMod.getCurrentLifeCycleState())) {
log.debug("Document" + docMod.getRef()
+ " is already in the target LifeCycle state");
} else if (LifeCycleConstants.DELETED_STATE.equals(targetState)) {
log.debug("Impossible to change state of "
+ docMod.getRef() + " :removing");
documentManager.removeDocument(docMod.getRef());
removed = true;
} else {
log.debug("Document"
+ docMod.getRef()
+ " has no transition to the target LifeCycle state");
}
}
if (docMod.isFolder() && !removed) {
changeDocumentsState(documentManager,
documentManager.getChildren(docMod.getRef()),
transition, targetState);
}
}
}
}