001/* 002 * Copyright 2015 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.ArrayList; 019import java.util.Collections; 020import java.util.Comparator; 021import java.util.HashMap; 022import java.util.HashSet; 023import java.util.List; 024import java.util.Map; 025import java.util.Set; 026 027import javax.jcr.Node; 028import javax.jcr.RepositoryException; 029import javax.jcr.Session; 030 031import org.apache.avalon.framework.parameters.Parameters; 032import org.apache.avalon.framework.service.ServiceException; 033import org.apache.avalon.framework.service.ServiceManager; 034import org.apache.cocoon.ProcessingException; 035import org.apache.cocoon.acting.ServiceableAction; 036import org.apache.cocoon.environment.ObjectModelHelper; 037import org.apache.cocoon.environment.Redirector; 038import org.apache.cocoon.environment.Request; 039import org.apache.cocoon.environment.SourceResolver; 040 041import org.ametys.cms.content.ContentHelper; 042import org.ametys.cms.repository.Content; 043import org.ametys.cms.repository.WorkflowAwareContent; 044import org.ametys.cms.workflow.history.ElementWithWorkflow; 045import org.ametys.cms.workflow.history.HistoryStep; 046import org.ametys.cms.workflow.history.VersionInformation; 047import org.ametys.cms.workflow.history.WorkflowHistory; 048import org.ametys.cms.workflow.history.WorkflowHistoryHelper; 049import org.ametys.core.cocoon.JSonReader; 050import org.ametys.plugins.repository.AmetysObjectResolver; 051import org.ametys.plugins.repository.version.VersionAwareAmetysObject; 052import org.ametys.plugins.workflow.store.AbstractJackrabbitWorkflowStore; 053import org.ametys.plugins.workflow.support.WorkflowProvider; 054import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow; 055 056/** 057 * This action returns the workflow history of a content 058 * 059 */ 060public class ContentHistoryAction extends ServiceableAction 061{ 062 /** The workflow provider */ 063 protected WorkflowProvider _workflowProvider; 064 065 /** The ametys object resolver */ 066 protected AmetysObjectResolver _resolver; 067 068 /** The content helper */ 069 protected ContentHelper _contentHelper; 070 071 /** The workflow history helper */ 072 protected WorkflowHistoryHelper _workflowHistoryHelper; 073 074 @Override 075 public void service(ServiceManager serviceManager) throws ServiceException 076 { 077 super.service(serviceManager); 078 _workflowProvider = (WorkflowProvider) serviceManager.lookup(WorkflowProvider.ROLE); 079 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 080 _contentHelper = (ContentHelper) serviceManager.lookup(ContentHelper.ROLE); 081 _workflowHistoryHelper = (WorkflowHistoryHelper) serviceManager.lookup(WorkflowHistoryHelper.ROLE); 082 } 083 084 public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception 085 { 086 Request request = ObjectModelHelper.getRequest(objectModel); 087 088 String id = request.getParameter("contentId"); 089 Content content = _resolver.resolveById(id); 090 091 assert content instanceof VersionAwareAmetysObject; 092 093 Map<String, Object> result = new HashMap<>(); 094 List<Map<String, Object>> workflowSteps = new ArrayList<>(); 095 096 Set<String> validatedVersions = new HashSet<>(); 097 098 try 099 { 100 if (content instanceof WorkflowAwareContent) 101 { 102 WorkflowAwareContent workflowAwareContent = (WorkflowAwareContent) content; 103 104 AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(workflowAwareContent); 105 long workflowId = workflowAwareContent.getWorkflowId(); 106 int initialActionId = (int) _getInitialActionId(workflow, workflowAwareContent); 107 108 List<VersionInformation> versionsInformation = _resolveVersionInformations((VersionAwareAmetysObject) content); 109 ElementWithWorkflow element = new ElementWithWorkflow( 110 _contentHelper.getTitle(content), 111 workflowAwareContent.getCreationDate(), 112 workflowAwareContent.getCreator(), 113 versionsInformation 114 ); 115 116 WorkflowHistory workflowHistory = _workflowHistoryHelper.getWorkflowHistory(element, workflowId, workflow, initialActionId); 117 for (HistoryStep step : workflowHistory.getSteps()) 118 { 119 workflowSteps.add(_workflowHistoryHelper.historyStep2Json(step)); 120 } 121 validatedVersions = workflowHistory.getValidatedVersions(); 122 } 123 } 124 catch (RepositoryException e) 125 { 126 throw new ProcessingException("Unable to access version history", e); 127 } 128 129 for (Map<String, Object> stepInfo : workflowSteps) 130 { 131 @SuppressWarnings("unchecked") 132 List<Map<String, Object>> versions = (List<Map<String, Object>>) stepInfo.get("versions"); 133 134 for (Map<String, Object> version : versions) 135 { 136 String versionName = (String) version.get("name"); 137 if (validatedVersions.contains(versionName)) 138 { 139 version.put("valid", true); 140 } 141 } 142 } 143 144 result.put("workflow", workflowSteps); 145 request.setAttribute(JSonReader.OBJECT_TO_READ, result); 146 return EMPTY_MAP; 147 } 148 149 private long _getInitialActionId(AmetysObjectWorkflow workflow, WorkflowAwareContent waContent) 150 { 151 try 152 { 153 Session session = waContent.getNode().getSession(); 154 AbstractJackrabbitWorkflowStore workflowStore = (AbstractJackrabbitWorkflowStore) workflow.getConfiguration().getWorkflowStore(); 155 Node workflowEntryNode = workflowStore.getEntryNode(session, waContent.getWorkflowId()); 156 return workflowEntryNode.getProperty("ametys-internal:initialActionId").getLong(); 157 } 158 catch (Exception e) 159 { 160 getLogger().error("Unable to retrieves initial action id for workflow aware content : " + waContent.getId(), e); 161 return 0; 162 } 163 } 164 165 private List<VersionInformation> _resolveVersionInformations(VersionAwareAmetysObject content) throws RepositoryException 166 { 167 List<VersionInformation> versionsInformation = new ArrayList<>(); 168 169 for (String revision : content.getAllRevisions()) 170 { 171 VersionInformation versionInformation = new VersionInformation(revision, content.getRevisionTimestamp(revision)); 172 173 for (String label : content.getLabels(revision)) 174 { 175 versionInformation.addLabel(label); 176 } 177 178 versionsInformation.add(versionInformation); 179 } 180 181 // Sort by date descendant 182 Collections.sort(versionsInformation, new Comparator<VersionInformation>() 183 { 184 public int compare(VersionInformation o1, VersionInformation o2) 185 { 186 try 187 { 188 return -o1.getCreatedAt().compareTo(o2.getCreatedAt()); 189 } 190 catch (RepositoryException e) 191 { 192 throw new RuntimeException("Unable to retrieve a creation date", e); 193 } 194 } 195 }); 196 197 // Set the version name 198 int count = versionsInformation.size(); 199 for (VersionInformation versionInformation : versionsInformation) 200 { 201 versionInformation.setVersionName(String.valueOf(count--)); 202 } 203 204 return versionsInformation; 205 } 206}