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