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