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}