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