001/* 002 * Copyright 2013 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.plugins.cart.generators; 017 018import java.io.IOException; 019import java.util.Collections; 020import java.util.Comparator; 021import java.util.Date; 022import java.util.List; 023 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.cocoon.ProcessingException; 027import org.apache.cocoon.environment.ObjectModelHelper; 028import org.apache.cocoon.environment.Request; 029import org.apache.cocoon.generation.ServiceableGenerator; 030import org.apache.cocoon.xml.AttributesImpl; 031import org.apache.cocoon.xml.XMLUtils; 032import org.apache.commons.lang.ArrayUtils; 033import org.apache.commons.lang.StringUtils; 034import org.xml.sax.SAXException; 035 036import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 037import org.ametys.cms.repository.Content; 038import org.ametys.cms.repository.WorkflowAwareContent; 039import org.ametys.core.user.CurrentUserProvider; 040import org.ametys.core.user.User; 041import org.ametys.core.user.UserIdentity; 042import org.ametys.core.user.UserManager; 043import org.ametys.core.util.DateUtils; 044import org.ametys.plugins.cart.Cart; 045import org.ametys.plugins.cart.CartElement; 046import org.ametys.plugins.cart.CartsDAO; 047import org.ametys.plugins.cart.ContentElement; 048import org.ametys.plugins.cart.QueryFromDirectoryElement; 049import org.ametys.plugins.repository.AmetysObjectResolver; 050import org.ametys.plugins.repository.AmetysRepositoryException; 051import org.ametys.plugins.repository.version.VersionAwareAmetysObject; 052import org.ametys.plugins.workflow.store.AmetysStep; 053import org.ametys.plugins.workflow.support.WorkflowHelper; 054import org.ametys.plugins.workflow.support.WorkflowProvider; 055import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow; 056import org.ametys.runtime.i18n.I18nizableText; 057 058import com.opensymphony.workflow.WorkflowException; 059import com.opensymphony.workflow.spi.Step; 060 061/** 062 * SAX a {@link Cart} 063 * 064 */ 065public class CartElementsGenerator extends ServiceableGenerator 066{ 067 /** The Ametys object resolver */ 068 protected AmetysObjectResolver _resolver; 069 /** The workflow provider */ 070 protected WorkflowProvider _workflowProvider; 071 /** The workflow helper */ 072 protected WorkflowHelper _workflowHelper; 073 /** The current user provider */ 074 protected CurrentUserProvider _userProvider; 075 /** The user manager */ 076 protected UserManager _userManager; 077 /** The carts DAO */ 078 protected CartsDAO _cartsDAO; 079 /** The content type extension point */ 080 protected ContentTypeExtensionPoint _cTypeEP; 081 082 @Override 083 public void service(ServiceManager smanager) throws ServiceException 084 { 085 super.service(smanager); 086 _cTypeEP = (ContentTypeExtensionPoint) smanager.lookup(ContentTypeExtensionPoint.ROLE); 087 _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE); 088 _workflowProvider = (WorkflowProvider) smanager.lookup(WorkflowProvider.ROLE); 089 _workflowHelper = (WorkflowHelper) smanager.lookup(WorkflowHelper.ROLE); 090 _userManager = (UserManager) smanager.lookup(UserManager.ROLE); 091 _userProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE); 092 _cartsDAO = (CartsDAO) smanager.lookup(CartsDAO.ROLE); 093 } 094 095 @Override 096 public void generate() throws IOException, SAXException, ProcessingException 097 { 098 Request request = ObjectModelHelper.getRequest(objectModel); 099 String id = request.getParameter("cartId"); 100 101 Cart cart = _resolver.resolveById(id); 102 103 contentHandler.startDocument(); 104 105 UserIdentity user = _userProvider.getUser(); 106 if (_cartsDAO.canRead(user, cart)) 107 { 108 AttributesImpl attrs = new AttributesImpl(); 109 attrs.addCDATAAttribute("id", cart.getId()); 110 111 XMLUtils.startElement(contentHandler, "cart", attrs); 112 113 XMLUtils.createElement(contentHandler, "label", cart.getTitle()); 114 XMLUtils.createElement(contentHandler, "description", cart.getDescription()); 115 116 List<CartElement> elements = cart.getElements(); 117 for (CartElement elmt : elements) 118 { 119 _saxElement(elmt); 120 } 121 122 XMLUtils.createElement(contentHandler, "total", String.valueOf(elements.size())); 123 124 XMLUtils.endElement(contentHandler, "cart"); 125 } 126 else 127 { 128 XMLUtils.createElement(contentHandler, "not-allowed"); 129 } 130 131 contentHandler.endDocument(); 132 } 133 134 /** 135 * SAX an element of the cart 136 * @param elmt The element to SAX 137 * @throws SAXException if something goes wrong when saxing the element 138 */ 139 protected void _saxElement (CartElement elmt) throws SAXException 140 { 141 List<I18nizableText> groups = elmt.getGroups(); 142 143 for (I18nizableText group : groups) 144 { 145 AttributesImpl attrs = new AttributesImpl(); 146 attrs.addCDATAAttribute("id", elmt.getId()); 147 148 XMLUtils.startElement(contentHandler, "cartElement", attrs); 149 150 elmt.getTitle().toSAX(contentHandler, "title"); 151 elmt.getDescription().toSAX(contentHandler, "description"); 152 group.toSAX(contentHandler, "group"); 153 154 XMLUtils.createElement(contentHandler, "creation", DateUtils.zonedDateTimeToString(elmt.getCreationDate())); 155 156 UserIdentity creatorIdentity = elmt.getCreator(); 157 User creator = _userManager.getUser(creatorIdentity); 158 XMLUtils.createElement(contentHandler, "creator", creator != null ? creator.getFullName() : StringUtils.EMPTY); 159 160 XMLUtils.createElement(contentHandler, "lastModification", DateUtils.zonedDateTimeToString(elmt.getLastModified())); 161 162 UserIdentity lastContributorIdentity = elmt.getLastContributor(); 163 User lastContributor = _userManager.getUser(lastContributorIdentity); 164 XMLUtils.createElement(contentHandler, "lastContributor", lastContributor != null ? lastContributor.getFullName() : StringUtils.EMPTY); 165 166 String glyphIcon = elmt.getGlyphIcon(); 167 if (glyphIcon != null) 168 { 169 XMLUtils.createElement(contentHandler, "iconGlyph", glyphIcon); 170 } 171 172 String smallIcon = elmt.getSmallIcon(); 173 if (smallIcon != null) 174 { 175 XMLUtils.createElement(contentHandler, "smallIcon", smallIcon); 176 } 177 String mediumIcon = elmt.getSmallIcon(); 178 if (mediumIcon != null) 179 { 180 XMLUtils.createElement(contentHandler, "mediumIcon", mediumIcon); 181 } 182 183 XMLUtils.createElement(contentHandler, "type", elmt.getType()); 184 185 if (elmt instanceof ContentElement) 186 { 187 Content content = _resolver.resolveById(elmt.getId()); 188 _saxWorkflowStep(content); 189 } 190 else if (elmt instanceof QueryFromDirectoryElement queryElement) 191 { 192 XMLUtils.createElement(contentHandler, "documentation", queryElement.getQuery().getDocumentation()); 193 XMLUtils.createElement(contentHandler, "queryType", queryElement.getQuery().getType()); 194 } 195 196 XMLUtils.endElement(contentHandler, "cartElement"); 197 } 198 } 199 200 /** 201 * SAX the workflow step if the content is a <code>WorkflowAwareContent</code> 202 * @param content The content 203 * @throws SAXException if an error occurs while SAXing. 204 */ 205 protected void _saxWorkflowStep (Content content) throws SAXException 206 { 207 if (content instanceof WorkflowAwareContent) 208 { 209 WorkflowAwareContent waContent = (WorkflowAwareContent) content; 210 211 try 212 { 213 AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(waContent); 214 long workflowId = waContent.getWorkflowId(); 215 String workflowName = workflow.getWorkflowName(workflowId); 216 217 Step currentStep = _getCurrentStep(waContent, workflow); 218 219 int currentStepId = currentStep.getStepId(); 220 221 I18nizableText workflowStepName = new I18nizableText("application", _workflowHelper.getStepName(workflowName, currentStepId)); 222 223 AttributesImpl atts = new AttributesImpl(); 224 atts.addAttribute("", "id", "id", "CDATA", String.valueOf(currentStepId)); 225 if ("application".equals(workflowStepName.getCatalogue())) 226 { 227 atts.addAttribute("", "icon-small", "icon-small", "CDATA", "/plugins/cms/resources_workflow/" + workflowStepName.getKey() + "-small.png"); 228 atts.addAttribute("", "icon-medium", "icon-medium", "CDATA", "/plugins/cms/resources_workflow/" + workflowStepName.getKey() + "-medium.png"); 229 atts.addAttribute("", "icon-large", "icon-large", "CDATA", "/plugins/cms/resources_workflow/" + workflowStepName.getKey() + "-large.png"); 230 } 231 else 232 { 233 String pluginName = workflowStepName.getCatalogue().substring("plugin.".length()); 234 atts.addAttribute("", "icon-small", "icon-small", "CDATA", "/plugins/" + pluginName + "/resources/img/workflow/" + workflowStepName.getKey() + "-small.png"); 235 atts.addAttribute("", "icon-medium", "icon-medium", "CDATA", "/plugins/" + pluginName + "/resources/img/workflow/" + workflowStepName.getKey() + "-medium.png"); 236 atts.addAttribute("", "icon-large", "icon-large", "CDATA", "/plugins/" + pluginName + "/resources/img/workflow/" + workflowStepName.getKey() + "-large.png"); 237 } 238 239 XMLUtils.startElement(contentHandler, "workflow-step", atts); 240 workflowStepName.toSAX(contentHandler); 241 XMLUtils.endElement(contentHandler, "workflow-step"); 242 } 243 catch (AmetysRepositoryException e) 244 { 245 // Current step id was not positioned 246 } 247 catch (WorkflowException e) 248 { 249 // Ignore, just don't SAX the workflow step. 250 } 251 } 252 } 253 254 /** 255 * Get a content's step, wherever it works on the base version or not. 256 * @param content the content. 257 * @param workflow the workflow instance bound to this content 258 * @return the content's workflow step. 259 * @throws WorkflowException if an error occurs. 260 */ 261 protected Step _getCurrentStep(WorkflowAwareContent content, AmetysObjectWorkflow workflow) throws WorkflowException 262 { 263 long workflowId = content.getWorkflowId(); 264 Step currentStep = (Step) workflow.getCurrentSteps(workflowId).get(0); 265 266 if (content instanceof VersionAwareAmetysObject) 267 { 268 VersionAwareAmetysObject vaContent = (VersionAwareAmetysObject) content; 269 String currentRevision = vaContent.getRevision(); 270 271 if (currentRevision != null) 272 { 273 274 String[] allRevisions = vaContent.getAllRevisions(); 275 int currentRevIndex = ArrayUtils.indexOf(allRevisions, currentRevision); 276 277 if (currentRevIndex > -1 && currentRevIndex < (allRevisions.length - 1)) 278 { 279 String nextRevision = allRevisions[currentRevIndex + 1]; 280 281 Date currentRevTimestamp = vaContent.getRevisionTimestamp(); 282 Date nextRevTimestamp = vaContent.getRevisionTimestamp(nextRevision); 283 284 // Get all steps between the two revisions. 285 List<Step> steps = _workflowHelper.getStepsBetween(workflow, workflowId, currentRevTimestamp, nextRevTimestamp); 286 287 // In the old workflow structure 288 // We take the second, which is current revision's last step. 289 if (steps.size() > 0 && steps.get(0) instanceof AmetysStep) 290 { 291 AmetysStep amStep = (AmetysStep) steps.get(0); 292 if (amStep.getProperty("actionFinishDate") != null) 293 { 294 // New workflow structure detected: cut the first workflow step 295 // in the list, as it belongs to the next version. 296 steps = steps.subList(1, steps.size()); 297 } 298 } 299 300 // Order by step descendant. 301 Collections.sort(steps, new Comparator<Step>() 302 { 303 public int compare(Step step1, Step step2) 304 { 305 return -Long.valueOf(step1.getId()).compareTo(step2.getId()); 306 } 307 }); 308 309 // The first step in the list is the current version's last workflow step. 310 if (steps.size() > 0) 311 { 312 currentStep = steps.get(0); 313 } 314 } 315 } 316 } 317 return currentStep; 318 } 319}