/* * 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: * Julien Anguenot * Florent Guillaume */ package org.eclipse.ecr.core.lifecycle.impl; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.ecr.core.lifecycle.LifeCycle; import org.eclipse.ecr.core.lifecycle.LifeCycleException; import org.eclipse.ecr.core.lifecycle.LifeCycleService; import org.eclipse.ecr.core.lifecycle.LifeCycleState; import org.eclipse.ecr.core.lifecycle.extensions.LifeCycleDescriptor; import org.eclipse.ecr.core.lifecycle.extensions.LifeCycleTypesDescriptor; import org.eclipse.ecr.core.model.Document; import org.eclipse.ecr.runtime.model.ComponentName; import org.eclipse.ecr.runtime.model.DefaultComponent; import org.eclipse.ecr.runtime.model.Extension; /** * Life cycle service implementation. * * @see org.eclipse.ecr.core.lifecycle.LifeCycleService * * @author Julien Anguenot * @author Florent Guillaume */ public class LifeCycleServiceImpl extends DefaultComponent implements LifeCycleService { public static final ComponentName NAME = new ComponentName( "org.eclipse.ecr.core.lifecycle.LifeCycleService"); private static final Log log = LogFactory.getLog(LifeCycleServiceImpl.class); /** Lifecycle name -> life cycle descriptor instance. */ private final Map<String, LifeCycle> lifeCycles; /** Type name -> life cycle name. */ private final Map<String, String> typesMapping; /** * a Mapping from doc type => list of transition that should no recurse. */ protected final Map<String, List<String>> docTypeToNonRecursiveTransition = new HashMap<String, List<String>>(); public LifeCycleServiceImpl() { lifeCycles = new HashMap<String, LifeCycle>(); typesMapping = new HashMap<String, String>(); } @Override public LifeCycle getLifeCycleByName(String name) { return lifeCycles.get(name); } @Override public LifeCycle getLifeCycleFor(Document doc) { String lifeCycleName = getLifeCycleNameFor(doc.getType().getName()); return getLifeCycleByName(lifeCycleName); } @Override public String getLifeCycleNameFor(String typeName) { return typesMapping.get(typeName); } @Override public Collection<LifeCycle> getLifeCycles() { return lifeCycles.values(); } @Override public Collection<String> getTypesFor(String lifeCycleName) { Collection<String> types = new ArrayList<String>(); for (String typeName : typesMapping.keySet()) { if (typesMapping.get(typeName).equals(lifeCycleName)) { types.add(typeName); } } return types; } @Override public Map<String, String> getTypesMapping() { return typesMapping; } @Override public void initialize(Document doc) throws LifeCycleException { initialize(doc, null); } @Override public void initialize(Document doc, String initialStateName) throws LifeCycleException { String lifeCycleName; LifeCycle documentLifeCycle = getLifeCycleFor(doc); if (documentLifeCycle == null) { lifeCycleName = "undefined"; if (initialStateName == null) { initialStateName = "undefined"; } } else { lifeCycleName = documentLifeCycle.getName(); // set initial life cycle state if (initialStateName == null) { initialStateName = documentLifeCycle.getDefaultInitialStateName(); } else { // check it's a valid state LifeCycleState state = documentLifeCycle.getStateByName(initialStateName); if (state == null) { throw new LifeCycleException(String.format( "State '%s' is not a valid state " + "for lifecycle %s", initialStateName, lifeCycleName)); } else if (!documentLifeCycle.getInitialStateNames().contains( initialStateName)) { log.warn(String.format( "State '%s' is not a valid initial state " + "for lifecycle %s", initialStateName, lifeCycleName)); } } } doc.setCurrentLifeCycleState(initialStateName); doc.setLifeCyclePolicy(lifeCycleName); } @Override public void followTransition(Document doc, String transitionName) throws LifeCycleException { String lifeCycleState = doc.getLifeCycleState(); LifeCycle lifeCycle = getLifeCycleFor(doc); if (lifeCycle.getAllowedStateTransitionsFrom(lifeCycleState).contains( transitionName)) { String destinationStateName = lifeCycle.getTransitionByName( transitionName).getDestinationStateName(); doc.setCurrentLifeCycleState(destinationStateName); } else { throw new LifeCycleException("Not allowed to follow transition <" + transitionName + "> from state <" + lifeCycleState + '>'); } } @Override public void reinitLifeCycle(Document doc) throws LifeCycleException { LifeCycle documentLifeCycle = getLifeCycleFor(doc); if (documentLifeCycle == null) { log.debug("No lifecycle policy for this document. Nothing to do !"); return; } doc.setCurrentLifeCycleState(documentLifeCycle.getDefaultInitialStateName()); } /** * Register extensions. */ @Override public void registerExtension(Extension extension) throws Exception { Object[] contributions = extension.getContributions(); if (contributions != null) { String point = extension.getExtensionPoint(); if (point.equals("lifecycle")) { for (Object contribution : contributions) { LifeCycleDescriptor desc = (LifeCycleDescriptor) contribution; log.info("Registering lifecycle: " + desc.getName()); lifeCycles.put(desc.getName(), desc.getLifeCycle()); } } else if (point.equals("lifecyclemanager")) { log.warn("Ignoring deprecated lifecyclemanager extension point"); } else if (point.equals("types")) { for (Object mapping : contributions) { LifeCycleTypesDescriptor desc = (LifeCycleTypesDescriptor) mapping; log.info("Registering lifecycle types mapping: " + desc.getDocumentType() + "-" + desc.getLifeCycleName()); typesMapping.put(desc.getDocumentType(), desc.getLifeCycleName()); String transitionArray = desc.getNoRecursionForTransitions(); List<String> transitions = new ArrayList<String>(); if (transitionArray != null && !transitionArray.isEmpty()) { transitions = Arrays.asList(desc.getNoRecursionForTransitions().split( ",")); } docTypeToNonRecursiveTransition.put(desc.getDocumentType(), transitions); } } } } /** * Unregisters an extension. */ @Override public void unregisterExtension(Extension extension) throws Exception { super.unregisterExtension(extension); Object[] contributions = extension.getContributions(); if (contributions != null) { String point = extension.getExtensionPoint(); if (point.equals("lifecycle")) { for (Object lifeCycle : contributions) { LifeCycleDescriptor lifeCycleDescriptor = (LifeCycleDescriptor) lifeCycle; log.debug("Unregistering lifecycle: " + lifeCycleDescriptor.getName()); lifeCycles.remove(lifeCycleDescriptor.getName()); } } else if (point.equals("types")) { for (Object contrib : contributions) { LifeCycleTypesDescriptor desc = (LifeCycleTypesDescriptor) contrib; typesMapping.remove(desc.getDocumentType()); } } } } @Override public List<String> getNonRecursiveTransitionForDocType(String docTypeName) { return docTypeToNonRecursiveTransition.get(docTypeName); } }