001/*
002 *  Copyright 2011 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.Repository;
023import javax.jcr.RepositoryException;
024import javax.jcr.Session;
025
026import org.apache.avalon.framework.parameters.Parameters;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.cocoon.environment.ObjectModelHelper;
030import org.apache.cocoon.environment.Redirector;
031import org.apache.cocoon.environment.Request;
032import org.apache.commons.lang.ArrayUtils;
033
034import org.ametys.cms.ObservationConstants;
035import org.ametys.cms.repository.CloneComponent;
036import org.ametys.cms.repository.Content;
037import org.ametys.cms.repository.WorkflowAwareContent;
038import org.ametys.core.observation.Event;
039import org.ametys.core.observation.ObservationManager;
040import org.ametys.core.user.UserIdentity;
041import org.ametys.plugins.repository.AmetysObjectResolver;
042import org.ametys.plugins.repository.provider.AbstractRepository;
043import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector;
044import org.ametys.plugins.repository.version.VersionableAmetysObject;
045import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow;
046
047import com.opensymphony.workflow.InvalidInputException;
048import com.opensymphony.workflow.WorkflowException;
049
050/**
051 * Unarchive a content.
052 */
053public class UnarchiveContentAction extends ContentWorkflowAction
054{
055    /** The repository. */
056    protected Repository _repository;
057    
058    /** The ametys object resolver. */
059    protected AmetysObjectResolver _resolver;
060    
061    /** The clone component. */
062    protected CloneComponent _cloneComponent;
063    
064    /** Observation manager available to subclasses. */
065    protected ObservationManager _observationManager;
066    
067    @Override
068    public void service(ServiceManager serviceManager) throws ServiceException
069    {
070        super.service(serviceManager);
071        _repository = (Repository) serviceManager.lookup(AbstractRepository.ROLE);
072        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
073        _cloneComponent = (CloneComponent) serviceManager.lookup(CloneComponent.ROLE);
074        _observationManager = (ObservationManager) serviceManager.lookup(ObservationManager.ROLE);
075    }
076    
077    @Override
078    protected Map<String, String> _act(Redirector redirector, Map objectModel, String source, Parameters parameters, int actionId, Map inputs) throws InvalidInputException, WorkflowException
079    {
080        Request request = ObjectModelHelper.getRequest(objectModel);
081        
082        WorkflowAwareContent archivedContent = _getContent(objectModel);
083        UserIdentity user = _getUser(objectModel);
084        
085        String contentId = archivedContent.getId();
086        
087        try
088        {
089            Event unarchiveEvent = _prepareArchivedEvent(user, archivedContent);
090            
091            // Move the content and its workflow back to the default workspace.
092            unarchiveContent(archivedContent);
093            
094            // Resolve the content in the default workspace.
095            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, "default");
096            WorkflowAwareContent content = _resolver.resolveById(contentId);
097            
098            if (content instanceof VersionableAmetysObject)
099            {
100                ((VersionableAmetysObject) content).checkpoint();
101            }
102            
103            request.setAttribute(Content.class.getName(), content);
104            inputs.put(AbstractContentWorkflowComponent.CONTENT_KEY, content);
105            
106            // Trigger the action.
107            Map<String, String> result = super._act(redirector, objectModel, source, parameters, actionId, inputs);
108            
109            // Notify that a content has been added to the default workspace.
110            Map<String, Object> eventParams = new HashMap<>();
111            eventParams.put(ObservationConstants.ARGS_CONTENT, content);
112            eventParams.put(ObservationConstants.ARGS_CONTENT_ID, contentId);
113            
114            _observationManager.notify(new Event(ObservationConstants.EVENT_CONTENT_ADDED, user, eventParams));
115            
116            // Notify that the archived content has been deleted from the archive workspace
117            _observationManager.notify(unarchiveEvent);
118            
119            return result;
120        }
121        catch (RepositoryException e)
122        {
123            throw new WorkflowException("Error unarchiving the content " + contentId, e);
124        }
125    }
126    
127    /**
128     * Prepare event to notify observers
129     * @param issuer the responsible for the action
130     * @param content the content after being archived
131     * @return the event
132     * @throws RepositoryException if an error occurred
133     */
134    protected Event _prepareArchivedEvent (UserIdentity issuer, Content content) throws RepositoryException
135    {
136        Map<String, Object> eventParams = new HashMap<>();
137        eventParams.put(ObservationConstants.ARGS_CONTENT, content);
138        eventParams.put(ObservationConstants.ARGS_CONTENT_NAME, content.getName());
139        eventParams.put(ObservationConstants.ARGS_CONTENT_ID, content.getId());
140
141        return new Event(org.ametys.cms.ObservationConstants.EVENT_CONTENT_UNARCHIVED, issuer, eventParams);
142    }
143    
144    /**
145     * Test if the action can be executed.
146     * @param content the content
147     * @param actionId the action ID.
148     * @param inputs the workflow inputs.
149     * @return true if the action is valid in the current environment, false otherwise.
150     */
151    protected boolean isActionValid(WorkflowAwareContent content, int actionId, Map inputs)
152    {
153        long workflowId = content.getWorkflowId();
154        
155        AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(content);
156        int[] availableActions = workflow.getAvailableActions(workflowId, inputs);
157        
158        return ArrayUtils.contains(availableActions, actionId);
159    }
160    
161    /**
162     * Unarchive a content.
163     * @param content the content (in the archives workspace).
164     * @throws RepositoryException If an error occurred
165     */
166    protected void unarchiveContent(WorkflowAwareContent content) throws RepositoryException
167    {
168        Session defaultSession = null;
169        Session archiveSession = null;
170        
171        try
172        {
173            // Open a session on the default workspace.
174            defaultSession = _repository.login("default");
175            
176            // The content node in the archives workspace.
177            Node contentNode = content.getNode();
178            archiveSession = contentNode.getSession();
179            
180            // Clone the content in the default workspace.
181            _cloneComponent.cloneContentNodeWithWorkflow(defaultSession, contentNode);
182            
183            // Remove the content in the archives workspace.
184            content.remove();
185            
186            // Save everything.
187            defaultSession.save();
188            archiveSession.save();
189        }
190        finally
191        {
192            if (defaultSession != null)
193            {
194                defaultSession.logout();
195            }
196        }
197    }
198}