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.NoSuchWorkspaceException;
022import javax.jcr.Node;
023import javax.jcr.Repository;
024import javax.jcr.RepositoryException;
025import javax.jcr.Session;
026
027import org.apache.avalon.framework.parameters.Parameters;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.cocoon.environment.ObjectModelHelper;
031import org.apache.cocoon.environment.Redirector;
032import org.apache.cocoon.environment.Request;
033
034import org.ametys.cms.ObservationConstants;
035import org.ametys.cms.content.archive.ArchiveConstants;
036import org.ametys.cms.repository.CloneComponent;
037import org.ametys.cms.repository.Content;
038import org.ametys.cms.repository.WorkflowAwareContent;
039import org.ametys.core.cocoon.ActionResultGenerator;
040import org.ametys.core.observation.Event;
041import org.ametys.core.observation.ObservationManager;
042import org.ametys.core.user.UserIdentity;
043import org.ametys.plugins.repository.AmetysObjectResolver;
044import org.ametys.plugins.repository.provider.AbstractRepository;
045
046import com.opensymphony.workflow.InvalidInputException;
047import com.opensymphony.workflow.WorkflowException;
048
049/**
050 * Action for archiving a content.
051 */
052public class ArchiveContentAction extends ContentWorkflowAction
053{
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        WorkflowAwareContent content = _getContent(objectModel);
081        
082        UserIdentity currentUser = _getUser(objectModel);
083        String contentId = content.getId();
084        
085        Event deletingEvent = _prepareDeletingEvent (currentUser, content);
086        Event deletedEvent = _prepareDeletedEvent (currentUser, content);
087        
088        try
089        {
090            // Trigger the action.
091            Map<String, String> result = super._act(redirector, objectModel, source, parameters, actionId, inputs);
092            
093            Map<String, Object> resultMap = new HashMap<>();
094            
095            _observationManager.notify(deletingEvent);
096            
097            // Move the content and its workflow to the "archives" workspace.
098            archiveContent(content, objectModel, resultMap);
099            
100            Request request = ObjectModelHelper.getRequest(objectModel);
101            request.setAttribute(ActionResultGenerator.MAP_REQUEST_ATTR, resultMap);
102            
103            // Notify that a content has been removed from the default workspace.
104            _observationManager.notify(deletedEvent);
105            
106            return result;
107        }
108        catch (RepositoryException e)
109        {
110            throw new WorkflowException("Unable to archive the content " + contentId, e);
111        }
112    }
113    
114    /**
115     * Prepare event to notify observers
116     * @param issuer the responsible for the action
117     * @param content the archived content
118     * @return the event
119     */
120    protected Event _prepareDeletingEvent (UserIdentity issuer, Content content)
121    {
122        Map<String, Object> eventParams = new HashMap<>();
123        eventParams.put(ObservationConstants.ARGS_CONTENT, content);
124        eventParams.put(ObservationConstants.ARGS_CONTENT_NAME, content.getName());
125        eventParams.put(ObservationConstants.ARGS_CONTENT_ID, content.getId());
126        
127        return new Event(org.ametys.cms.ObservationConstants.EVENT_CONTENT_DELETING, issuer, eventParams);
128    }
129    
130    /**
131     * Prepare event to notify observers
132     * @param issuer the responsible for the action
133     * @param content the archived content
134     * @return the event
135     */
136    protected Event _prepareDeletedEvent (UserIdentity issuer, Content content)
137    {
138        Map<String, Object> eventParams = new HashMap<>();
139        eventParams.put(ObservationConstants.ARGS_CONTENT, content);
140        eventParams.put(ObservationConstants.ARGS_CONTENT_NAME, content.getName());
141        eventParams.put(ObservationConstants.ARGS_CONTENT_ID, content.getId());
142
143        return new Event(org.ametys.cms.ObservationConstants.EVENT_CONTENT_DELETED, issuer, eventParams);
144    }
145    
146    /**
147     * Archive a content.
148     * @param content the content to archive.
149     * @param objectModel the current object model.
150     * @param result the result map
151     * @throws RepositoryException The repository exception
152     */
153    protected void archiveContent(WorkflowAwareContent content, Map objectModel, Map<String, Object> result) throws RepositoryException
154    {
155        Session session = null;
156        Session archiveSession = null;
157        
158        try
159        {
160            archiveSession = getArchiveSession();
161            
162            Node contentNode = content.getNode();
163            
164            session = contentNode.getSession();
165            
166            _cloneComponent.cloneContentNodeWithWorkflow(archiveSession, contentNode);
167            
168            archiveSession.save();
169            
170            content.remove();
171            session.save();
172        }
173        finally
174        {
175            if (archiveSession != null)
176            {
177                archiveSession.logout();
178            }
179        }
180    }
181    
182    /**
183     * Get a repository session on the archive workspace.
184     * @return the archive session.
185     * @throws RepositoryException The repository exception
186     */
187    protected Session getArchiveSession() throws RepositoryException
188    {
189        Session session = null;
190        Session archiveSession = null;
191        
192        try
193        {
194            archiveSession = _repository.login(ArchiveConstants.ARCHIVE_WORKSPACE);
195            
196            return archiveSession;
197        }
198        catch (NoSuchWorkspaceException e)
199        {
200            session = _repository.login();
201            session.getWorkspace().createWorkspace(ArchiveConstants.ARCHIVE_WORKSPACE);
202            archiveSession = _repository.login(ArchiveConstants.ARCHIVE_WORKSPACE);
203
204            archiveSession.getRootNode().addNode(AmetysObjectResolver.ROOT_REPO, AmetysObjectResolver.ROOT_TYPE);
205            archiveSession.save();
206            
207            return archiveSession;
208        }
209        finally
210        {
211            if (session != null)
212            {
213                session.logout();
214            }
215        }
216    }
217    
218}