001/* 002 * Copyright 2013 Anyware Services 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 */ 016package org.ametys.cms.workflow; 017 018import java.util.HashMap; 019import java.util.Map; 020 021import javax.jcr.Node; 022import javax.jcr.RepositoryException; 023import javax.jcr.lock.Lock; 024import javax.jcr.lock.LockManager; 025 026import org.apache.avalon.framework.activity.Initializable; 027import org.apache.commons.lang.StringUtils; 028 029import org.ametys.cms.ObservationConstants; 030import org.ametys.cms.repository.WorkflowAwareContent; 031import org.ametys.core.observation.Event; 032import org.ametys.core.observation.ObservationManager; 033import org.ametys.plugins.repository.RepositoryConstants; 034import org.ametys.plugins.repository.lock.LockAwareAmetysObject; 035import org.ametys.plugins.repository.version.VersionableAmetysObject; 036import org.ametys.plugins.workflow.EnhancedFunction; 037import org.ametys.plugins.workflow.support.WorkflowProvider; 038import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow; 039 040import com.opensymphony.workflow.WorkflowException; 041import com.opensymphony.workflow.spi.Step; 042 043/** 044 * Abstract workflow function working on a Content, which provides common content methods. 045 */ 046public abstract class AbstractContentFunction extends AbstractContentWorkflowComponent implements EnhancedFunction, Initializable 047{ 048 /** The key in transiant var for the event to notify after the function */ 049 public static final String EVENT_TO_NOTIFY_KEY = "event-to-notify"; 050 051 /** The workflow provider. */ 052 protected WorkflowProvider _workflowProvider; 053 /** The observation manager */ 054 protected ObservationManager _observationManager; 055 056 @Override 057 public void initialize() throws Exception 058 { 059 _workflowProvider = (WorkflowProvider) _manager.lookup(WorkflowProvider.ROLE); 060 _observationManager = (ObservationManager) _manager.lookup(ObservationManager.ROLE); 061 } 062 063 /** 064 * Add the content lock token to the current session if the content is locked. 065 * @param content the content. 066 * @throws WorkflowException if an error occurs. 067 * @throws RepositoryException if a repository error occurs. 068 */ 069 protected void _addLockToken(WorkflowAwareContent content) throws WorkflowException, RepositoryException 070 { 071 if (content != null && content instanceof LockAwareAmetysObject) 072 { 073 LockAwareAmetysObject lockAwareContent = (LockAwareAmetysObject) content; 074 if (lockAwareContent.isLocked()) 075 { 076 Node node = content.getNode(); 077 078 LockManager lockManager = node.getSession().getWorkspace().getLockManager(); 079 080 Lock lock = lockManager.getLock(node.getPath()); 081 Node lockHolder = lock.getNode(); 082 083 lockManager.addLockToken(lockHolder.getProperty(RepositoryConstants.METADATA_LOCKTOKEN).getString()); 084 } 085 } 086 } 087 088 /** 089 * Set the content's current step ID without notifying the observers that the content's workflow has changed. 090 * @param content the content. 091 * @param transientVars The workflow transient vars. 092 * @throws WorkflowException if an error occurs. 093 */ 094 protected void _setCurrentStepId(WorkflowAwareContent content, Map transientVars) throws WorkflowException 095 { 096 if (content != null) 097 { 098 // Save the current step. 099 AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(content); 100 Step currentStep = (Step) workflow.getCurrentSteps(content.getWorkflowId()).iterator().next(); 101 content.setCurrentStepId(currentStep.getStepId()); 102 content.saveChanges(); 103 } 104 } 105 106 /** 107 * Set the content's current step ID and notify the observers that the content's workflow has changed. 108 * @param content the content. 109 * @param transientVars The workflow transient vars. 110 * @throws WorkflowException if an error occurs. 111 */ 112 protected void _setCurrentStepIdAndNotify(WorkflowAwareContent content, Map transientVars) throws WorkflowException 113 { 114 if (content != null) 115 { 116 // Save the current step. 117 AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(content); 118 Step currentStep = (Step) workflow.getCurrentSteps(content.getWorkflowId()).iterator().next(); 119 content.setCurrentStepId(currentStep.getStepId()); 120 content.saveChanges(); 121 122 _notify(content, transientVars); 123 } 124 } 125 126 /** 127 * Notify the event 128 * @param content the content 129 * @param transientVars the workflow transient vars 130 * @throws WorkflowException if an error occurs 131 */ 132 @SuppressWarnings("unchecked") 133 protected void _notify(WorkflowAwareContent content, Map transientVars) throws WorkflowException 134 { 135 String eventId = (String) transientVars.getOrDefault(EVENT_TO_NOTIFY_KEY, _getDefaultEvent()); 136 if (StringUtils.isNotBlank(eventId)) 137 { 138 Map<String, Object> eventParams = new HashMap<>(); 139 eventParams.put(ObservationConstants.ARGS_CONTENT, content); 140 eventParams.put(ObservationConstants.ARGS_CONTENT_ID, content.getId()); 141 _observationManager.notify(new Event(eventId, getUser(transientVars), eventParams)); 142 } 143 } 144 145 /** 146 * Get the default event to notify 147 * @return the default event 148 */ 149 protected String _getDefaultEvent() 150 { 151 return ObservationConstants.EVENT_CONTENT_WORKFLOW_CHANGED; 152 } 153 154 /** 155 * Persists the current version and create a new one. 156 * @param content the content. 157 * @throws WorkflowException if an error occurs. 158 */ 159 protected void _createVersion(WorkflowAwareContent content) throws WorkflowException 160 { 161 if (content != null) 162 { 163 // Create a new version 164 if (content instanceof VersionableAmetysObject) 165 { 166 ((VersionableAmetysObject) content).checkpoint(); 167 } 168 } 169 } 170 171 /** 172 * Add a label on the content. 173 * @param content the content. 174 * @param label the label to add. 175 * @throws WorkflowException if an error occurs. 176 * @throws RepositoryException if an error occurs. 177 */ 178 protected void _addLabel(WorkflowAwareContent content, String label) throws WorkflowException, RepositoryException 179 { 180 if (content != null) 181 { 182 if (content instanceof VersionableAmetysObject) 183 { 184 ((VersionableAmetysObject) content).addLabel(label, true); 185 } 186 } 187 } 188 189}