001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Julien Anguenot
011 *     Florent Guillaume
012 */
013
014package org.nuxeo.ecm.core.lifecycle.impl;
015
016import java.util.Collection;
017import java.util.List;
018import java.util.Map;
019
020import org.apache.commons.logging.Log;
021import org.apache.commons.logging.LogFactory;
022import org.nuxeo.ecm.core.api.LifeCycleException;
023import org.nuxeo.ecm.core.lifecycle.LifeCycle;
024import org.nuxeo.ecm.core.lifecycle.LifeCycleService;
025import org.nuxeo.ecm.core.lifecycle.LifeCycleState;
026import org.nuxeo.ecm.core.lifecycle.extensions.LifeCycleDescriptor;
027import org.nuxeo.ecm.core.lifecycle.extensions.LifeCycleTypesDescriptor;
028import org.nuxeo.ecm.core.model.Document;
029import org.nuxeo.runtime.model.ComponentName;
030import org.nuxeo.runtime.model.DefaultComponent;
031import org.nuxeo.runtime.model.Extension;
032
033/**
034 * Life cycle service implementation.
035 *
036 * @see org.nuxeo.ecm.core.lifecycle.LifeCycleService
037 * @author Julien Anguenot
038 * @author Florent Guillaume
039 */
040public class LifeCycleServiceImpl extends DefaultComponent implements LifeCycleService {
041
042    public static final ComponentName NAME = new ComponentName("org.nuxeo.ecm.core.lifecycle.LifeCycleService");
043
044    private static final Log log = LogFactory.getLog(LifeCycleServiceImpl.class);
045
046    protected LifeCycleRegistry lifeCycles = new LifeCycleRegistry();
047
048    protected LifeCycleTypeRegistry lifeCycleTypes = new LifeCycleTypeRegistry();
049
050    public LifeCycleServiceImpl() {
051    }
052
053    @Override
054    public LifeCycle getLifeCycleByName(String name) {
055        return lifeCycles.getLifeCycle(name);
056    }
057
058    @Override
059    public LifeCycle getLifeCycleFor(Document doc) {
060        String lifeCycleName = getLifeCycleNameFor(doc.getType().getName());
061        return getLifeCycleByName(lifeCycleName);
062    }
063
064    @Override
065    public String getLifeCycleNameFor(String typeName) {
066        return lifeCycleTypes.getLifeCycleNameForType(typeName);
067    }
068
069    @Override
070    public Collection<LifeCycle> getLifeCycles() {
071        return lifeCycles.getLifeCycles();
072    }
073
074    @Override
075    public Collection<String> getTypesFor(String lifeCycleName) {
076        return lifeCycleTypes.getTypesFor(lifeCycleName);
077    }
078
079    @Override
080    public Map<String, String> getTypesMapping() {
081        return lifeCycleTypes.getTypesMapping();
082    }
083
084    @Override
085    public void initialize(Document doc) throws LifeCycleException {
086        initialize(doc, null);
087    }
088
089    @Override
090    public void initialize(Document doc, String initialStateName) throws LifeCycleException {
091        String lifeCycleName;
092        LifeCycle documentLifeCycle = getLifeCycleFor(doc);
093        if (documentLifeCycle == null) {
094            lifeCycleName = "undefined";
095            if (initialStateName == null) {
096                initialStateName = "undefined";
097            }
098        } else {
099            lifeCycleName = documentLifeCycle.getName();
100            // set initial life cycle state
101            if (initialStateName == null) {
102                initialStateName = documentLifeCycle.getDefaultInitialStateName();
103            } else {
104                // check it's a valid state
105                LifeCycleState state = documentLifeCycle.getStateByName(initialStateName);
106                if (state == null) {
107                    throw new LifeCycleException(String.format("State '%s' is not a valid state " + "for lifecycle %s",
108                            initialStateName, lifeCycleName));
109                }
110            }
111        }
112        doc.setCurrentLifeCycleState(initialStateName);
113        doc.setLifeCyclePolicy(lifeCycleName);
114    }
115
116    @Override
117    public void followTransition(Document doc, String transitionName) throws LifeCycleException {
118        String lifeCycleState = doc.getLifeCycleState();
119        LifeCycle lifeCycle = getLifeCycleFor(doc);
120        if (lifeCycle.getAllowedStateTransitionsFrom(lifeCycleState).contains(transitionName)) {
121            String destinationStateName = lifeCycle.getTransitionByName(transitionName).getDestinationStateName();
122            doc.setCurrentLifeCycleState(destinationStateName);
123        } else {
124            throw new LifeCycleException("Not allowed to follow transition <" + transitionName + "> from state <"
125                    + lifeCycleState + '>');
126        }
127    }
128
129    @Override
130    public void reinitLifeCycle(Document doc) throws LifeCycleException {
131        LifeCycle documentLifeCycle = getLifeCycleFor(doc);
132        if (documentLifeCycle == null) {
133            log.debug("No lifecycle policy for this document. Nothing to do !");
134            return;
135        }
136        doc.setCurrentLifeCycleState(documentLifeCycle.getDefaultInitialStateName());
137    }
138
139    /**
140     * Register extensions.
141     */
142    @Override
143    public void registerExtension(Extension extension) {
144        Object[] contributions = extension.getContributions();
145        if (contributions != null) {
146            String point = extension.getExtensionPoint();
147            if (point.equals("lifecycle")) {
148                for (Object contribution : contributions) {
149                    LifeCycleDescriptor desc = (LifeCycleDescriptor) contribution;
150                    lifeCycles.addContribution(desc);
151                }
152            } else if (point.equals("lifecyclemanager")) {
153                log.warn("Ignoring deprecated lifecyclemanager extension point");
154            } else if (point.equals("types")) {
155                for (Object mapping : contributions) {
156                    LifeCycleTypesDescriptor desc = (LifeCycleTypesDescriptor) mapping;
157                    lifeCycleTypes.addContribution(desc);
158                }
159            }
160        }
161    }
162
163    /**
164     * Unregisters an extension.
165     */
166    @Override
167    public void unregisterExtension(Extension extension) {
168        super.unregisterExtension(extension);
169        Object[] contributions = extension.getContributions();
170        if (contributions != null) {
171            String point = extension.getExtensionPoint();
172            if (point.equals("lifecycle")) {
173                for (Object lifeCycle : contributions) {
174                    LifeCycleDescriptor lifeCycleDescriptor = (LifeCycleDescriptor) lifeCycle;
175                    lifeCycles.removeContribution(lifeCycleDescriptor);
176                }
177            } else if (point.equals("types")) {
178                for (Object contrib : contributions) {
179                    LifeCycleTypesDescriptor desc = (LifeCycleTypesDescriptor) contrib;
180                    lifeCycleTypes.removeContribution(desc);
181                }
182
183            }
184        }
185    }
186
187    @Override
188    public List<String> getNonRecursiveTransitionForDocType(String docTypeName) {
189        return lifeCycleTypes.getNonRecursiveTransitionForDocType(docTypeName);
190    }
191
192}