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; 045import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector; 046 047import com.opensymphony.workflow.InvalidInputException; 048import com.opensymphony.workflow.WorkflowException; 049 050/** 051 * Action for archiving a content. 052 */ 053public class ArchiveContentAction extends ContentWorkflowAction 054{ 055 056 /** The repository. */ 057 protected Repository _repository; 058 059 /** The ametys object resolver. */ 060 protected AmetysObjectResolver _resolver; 061 062 /** The clone component. */ 063 protected CloneComponent _cloneComponent; 064 065 /** Observation manager available to subclasses. */ 066 protected ObservationManager _observationManager; 067 068 @Override 069 public void service(ServiceManager serviceManager) throws ServiceException 070 { 071 super.service(serviceManager); 072 _repository = (Repository) serviceManager.lookup(AbstractRepository.ROLE); 073 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 074 _cloneComponent = (CloneComponent) serviceManager.lookup(CloneComponent.ROLE); 075 _observationManager = (ObservationManager) serviceManager.lookup(ObservationManager.ROLE); 076 } 077 078 @Override 079 protected Map<String, String> _act(Redirector redirector, Map objectModel, String source, Parameters parameters, int actionId, Map inputs) throws InvalidInputException, WorkflowException 080 { 081 WorkflowAwareContent content = _getContent(objectModel); 082 083 UserIdentity currentUser = _getUser(objectModel); 084 String contentId = content.getId(); 085 086 Event deletingEvent = _prepareDeletingEvent(currentUser, content); 087 Event deletedEvent = _prepareDeletedEvent(currentUser, content); 088 089 try 090 { 091 // Trigger the action. 092 Map<String, String> result = super._act(redirector, objectModel, source, parameters, actionId, inputs); 093 094 Map<String, Object> resultMap = new HashMap<>(); 095 096 _observationManager.notify(deletingEvent); 097 098 // Move the content and its workflow to the "archives" workspace. 099 archiveContent(content, objectModel, resultMap); 100 101 Request request = ObjectModelHelper.getRequest(objectModel); 102 request.setAttribute(ActionResultGenerator.MAP_REQUEST_ATTR, resultMap); 103 104 // Notify that a content has been removed from the default workspace. 105 _observationManager.notify(deletedEvent); 106 107 String currentWsp = RequestAttributeWorkspaceSelector.getForcedWorkspace(request); 108 try 109 { 110 // Resolve the content in the default workspace. 111 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, ArchiveConstants.ARCHIVE_WORKSPACE); 112 WorkflowAwareContent archivedContent = _resolver.resolveById(contentId); 113 114 if (archivedContent != null) 115 { 116 // Notify that the archived content has been created from the archive workspace 117 Map<String, Object> eventParams = new HashMap<>(); 118 eventParams.put(ObservationConstants.ARGS_CONTENT, archivedContent); 119 eventParams.put(ObservationConstants.ARGS_CONTENT_NAME, archivedContent.getName()); 120 eventParams.put(ObservationConstants.ARGS_CONTENT_ID, archivedContent.getId()); 121 _observationManager.notify(new Event(org.ametys.cms.ObservationConstants.EVENT_CONTENT_ARCHIVED, currentUser, eventParams)); 122 } 123 } 124 finally 125 { 126 // Restore context 127 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWsp); 128 } 129 130 return result; 131 } 132 catch (RepositoryException e) 133 { 134 throw new WorkflowException("Unable to archive the content " + contentId, e); 135 } 136 } 137 138 /** 139 * Prepare event to notify observers 140 * @param issuer the responsible for the action 141 * @param content the archived content 142 * @return the event 143 */ 144 protected Event _prepareDeletingEvent (UserIdentity issuer, Content content) 145 { 146 Map<String, Object> eventParams = new HashMap<>(); 147 eventParams.put(ObservationConstants.ARGS_CONTENT, content); 148 eventParams.put(ObservationConstants.ARGS_CONTENT_NAME, content.getName()); 149 eventParams.put(ObservationConstants.ARGS_CONTENT_ID, content.getId()); 150 151 return new Event(org.ametys.cms.ObservationConstants.EVENT_CONTENT_DELETING, issuer, eventParams); 152 } 153 154 /** 155 * Prepare event to notify observers 156 * @param issuer the responsible for the action 157 * @param content the archived content 158 * @return the event 159 */ 160 protected Event _prepareDeletedEvent (UserIdentity issuer, Content content) 161 { 162 Map<String, Object> eventParams = new HashMap<>(); 163 eventParams.put(ObservationConstants.ARGS_CONTENT, content); 164 eventParams.put(ObservationConstants.ARGS_CONTENT_NAME, content.getName()); 165 eventParams.put(ObservationConstants.ARGS_CONTENT_ID, content.getId()); 166 167 return new Event(org.ametys.cms.ObservationConstants.EVENT_CONTENT_DELETED, issuer, eventParams); 168 } 169 170 /** 171 * Archive a content. 172 * @param content the content to archive. 173 * @param objectModel the current object model. 174 * @param result the result map 175 * @throws RepositoryException The repository exception 176 */ 177 protected void archiveContent(WorkflowAwareContent content, Map objectModel, Map<String, Object> result) throws RepositoryException 178 { 179 Session session = null; 180 Session archiveSession = null; 181 182 try 183 { 184 archiveSession = getArchiveSession(); 185 186 Node contentNode = content.getNode(); 187 188 session = contentNode.getSession(); 189 190 _cloneComponent.cloneContentNodeWithWorkflow(archiveSession, contentNode); 191 192 archiveSession.save(); 193 194 content.remove(); 195 session.save(); 196 } 197 finally 198 { 199 if (archiveSession != null) 200 { 201 archiveSession.logout(); 202 } 203 } 204 } 205 206 /** 207 * Get a repository session on the archive workspace. 208 * @return the archive session. 209 * @throws RepositoryException The repository exception 210 */ 211 protected Session getArchiveSession() throws RepositoryException 212 { 213 Session session = null; 214 Session archiveSession = null; 215 216 try 217 { 218 archiveSession = _repository.login(ArchiveConstants.ARCHIVE_WORKSPACE); 219 220 return archiveSession; 221 } 222 catch (NoSuchWorkspaceException e) 223 { 224 session = _repository.login(); 225 session.getWorkspace().createWorkspace(ArchiveConstants.ARCHIVE_WORKSPACE); 226 archiveSession = _repository.login(ArchiveConstants.ARCHIVE_WORKSPACE); 227 228 archiveSession.getRootNode().addNode(AmetysObjectResolver.ROOT_REPO, AmetysObjectResolver.ROOT_TYPE); 229 archiveSession.save(); 230 231 return archiveSession; 232 } 233 finally 234 { 235 if (session != null) 236 { 237 session.logout(); 238 } 239 } 240 } 241 242}