001/* 002 * (C) Copyright 2006-2018 Nuxeo (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 static java.util.function.Predicate.isEqual; 024import static org.nuxeo.ecm.core.api.LifeCycleConstants.DELETED_STATE; 025 026import java.util.Collection; 027import java.util.List; 028import java.util.Map; 029 030import org.apache.commons.logging.Log; 031import org.apache.commons.logging.LogFactory; 032import org.nuxeo.ecm.core.api.LifeCycleException; 033import org.nuxeo.ecm.core.lifecycle.LifeCycle; 034import org.nuxeo.ecm.core.lifecycle.LifeCycleService; 035import org.nuxeo.ecm.core.lifecycle.LifeCycleState; 036import org.nuxeo.ecm.core.lifecycle.extensions.LifeCycleDescriptor; 037import org.nuxeo.ecm.core.lifecycle.extensions.LifeCycleTypesDescriptor; 038import org.nuxeo.ecm.core.model.Document; 039import org.nuxeo.runtime.model.ComponentName; 040import org.nuxeo.runtime.model.DefaultComponent; 041import org.nuxeo.runtime.model.Extension; 042 043/** 044 * Life cycle service implementation. 045 * 046 * @see org.nuxeo.ecm.core.lifecycle.LifeCycleService 047 * @author Julien Anguenot 048 * @author Florent Guillaume 049 */ 050public class LifeCycleServiceImpl extends DefaultComponent implements LifeCycleService { 051 052 public static final ComponentName NAME = new ComponentName("org.nuxeo.ecm.core.lifecycle.LifeCycleService"); 053 054 private static final Log log = LogFactory.getLog(LifeCycleServiceImpl.class); 055 056 protected LifeCycleRegistry lifeCycles = new LifeCycleRegistry(); 057 058 protected LifeCycleTypeRegistry lifeCycleTypes = new LifeCycleTypeRegistry(); 059 060 public LifeCycleServiceImpl() { 061 } 062 063 @Override 064 public LifeCycle getLifeCycleByName(String name) { 065 return lifeCycles.getLifeCycle(name); 066 } 067 068 @Override 069 public LifeCycle getLifeCycleFor(Document doc) { 070 String lifeCycleName = getLifeCycleNameFor(doc.getType().getName()); 071 return getLifeCycleByName(lifeCycleName); 072 } 073 074 @Override 075 public String getLifeCycleNameFor(String typeName) { 076 return lifeCycleTypes.getLifeCycleNameForType(typeName); 077 } 078 079 @Override 080 public Collection<LifeCycle> getLifeCycles() { 081 return lifeCycles.getLifeCycles(); 082 } 083 084 @Override 085 public Collection<String> getTypesFor(String lifeCycleName) { 086 return lifeCycleTypes.getTypesFor(lifeCycleName); 087 } 088 089 @Override 090 public Map<String, String> getTypesMapping() { 091 return lifeCycleTypes.getTypesMapping(); 092 } 093 094 @Override 095 public void initialize(Document doc) throws LifeCycleException { 096 initialize(doc, null); 097 } 098 099 @Override 100 public void initialize(Document doc, String initialStateName) throws LifeCycleException { 101 String lifeCycleName; 102 LifeCycle documentLifeCycle = getLifeCycleFor(doc); 103 if (documentLifeCycle == null) { 104 lifeCycleName = "undefined"; 105 if (initialStateName == null) { 106 initialStateName = "undefined"; 107 } 108 } else { 109 lifeCycleName = documentLifeCycle.getName(); 110 // set initial life cycle state 111 if (initialStateName == null) { 112 initialStateName = documentLifeCycle.getDefaultInitialStateName(); 113 } else { 114 // check it's a valid state 115 LifeCycleState state = documentLifeCycle.getStateByName(initialStateName); 116 if (state == null) { 117 throw new LifeCycleException(String.format("State '%s' is not a valid state " + "for lifecycle %s", 118 initialStateName, lifeCycleName)); 119 } 120 } 121 } 122 doc.setCurrentLifeCycleState(initialStateName); 123 doc.setLifeCyclePolicy(lifeCycleName); 124 } 125 126 @Override 127 public void followTransition(Document doc, String transitionName) throws LifeCycleException { 128 String lifeCycleState = doc.getLifeCycleState(); 129 LifeCycle lifeCycle = getLifeCycleFor(doc); 130 if (lifeCycle != null && lifeCycle.getAllowedStateTransitionsFrom(lifeCycleState).contains(transitionName)) { 131 String destinationStateName = lifeCycle.getTransitionByName(transitionName).getDestinationStateName(); 132 doc.setCurrentLifeCycleState(destinationStateName); 133 } else { 134 throw new LifeCycleException( 135 "Not allowed to follow transition <" + transitionName + "> from state <" + lifeCycleState + '>'); 136 } 137 } 138 139 @Override 140 public void reinitLifeCycle(Document doc) throws LifeCycleException { 141 LifeCycle documentLifeCycle = getLifeCycleFor(doc); 142 if (documentLifeCycle == null) { 143 log.debug("No lifecycle policy for this document. Nothing to do !"); 144 return; 145 } 146 doc.setCurrentLifeCycleState(documentLifeCycle.getDefaultInitialStateName()); 147 } 148 149 /** 150 * Register extensions. 151 */ 152 @Override 153 public void registerExtension(Extension extension) { 154 Object[] contributions = extension.getContributions(); 155 if (contributions != null) { 156 String point = extension.getExtensionPoint(); 157 if (point.equals("lifecycle")) { 158 for (Object contribution : contributions) { 159 LifeCycleDescriptor desc = (LifeCycleDescriptor) contribution; 160 lifeCycles.addContribution(desc); 161 // look for delete state to warn about usage 162 if (!"default".equals(desc.getName()) 163 && desc.getStates().stream().map(LifeCycleState::getName).anyMatch( 164 isEqual(DELETED_STATE))) { 165 log.warn("The 'deleted' state is deprecated and shouldn't be use anymore." 166 + " Please consider removing it from you life cycle policy and use trash service instead."); 167 } 168 } 169 } else if (point.equals("lifecyclemanager")) { 170 log.warn("Ignoring deprecated lifecyclemanager extension point"); 171 } else if (point.equals("types")) { 172 for (Object mapping : contributions) { 173 LifeCycleTypesDescriptor desc = (LifeCycleTypesDescriptor) mapping; 174 lifeCycleTypes.addContribution(desc); 175 } 176 } 177 } 178 } 179 180 /** 181 * Unregisters an extension. 182 */ 183 @Override 184 public void unregisterExtension(Extension extension) { 185 super.unregisterExtension(extension); 186 Object[] contributions = extension.getContributions(); 187 if (contributions != null) { 188 String point = extension.getExtensionPoint(); 189 if (point.equals("lifecycle")) { 190 for (Object lifeCycle : contributions) { 191 LifeCycleDescriptor lifeCycleDescriptor = (LifeCycleDescriptor) lifeCycle; 192 lifeCycles.removeContribution(lifeCycleDescriptor); 193 } 194 } else if (point.equals("types")) { 195 for (Object contrib : contributions) { 196 LifeCycleTypesDescriptor desc = (LifeCycleTypesDescriptor) contrib; 197 lifeCycleTypes.removeContribution(desc); 198 } 199 200 } 201 } 202 } 203 204 @Override 205 public List<String> getNonRecursiveTransitionForDocType(String docTypeName) { 206 return lifeCycleTypes.getNonRecursiveTransitionForDocType(docTypeName); 207 } 208 209}