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}