001/*
002 *  Copyright 2010 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.web.workflow;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.Iterator;
021import java.util.List;
022import java.util.Map;
023import java.util.Set;
024
025import org.apache.avalon.framework.context.Context;
026import org.apache.avalon.framework.context.ContextException;
027import org.apache.avalon.framework.context.Contextualizable;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.cocoon.components.ContextHelper;
031import org.apache.cocoon.environment.Request;
032import org.apache.cocoon.xml.AttributesImpl;
033import org.apache.cocoon.xml.XMLUtils;
034import org.apache.commons.lang.StringUtils;
035import org.xml.sax.ContentHandler;
036import org.xml.sax.SAXException;
037
038import org.ametys.cms.repository.Content;
039import org.ametys.cms.repository.ContentTypeExpression;
040import org.ametys.cms.repository.LanguageExpression;
041import org.ametys.core.user.User;
042import org.ametys.plugins.repository.AmetysRepositoryException;
043import org.ametys.plugins.repository.query.expression.Expression;
044import org.ametys.plugins.repository.query.expression.Expression.Operator;
045import org.ametys.plugins.repository.query.expression.OrExpression;
046import org.ametys.plugins.repository.query.expression.StringExpression;
047import org.ametys.web.repository.content.WebContent;
048import org.ametys.web.repository.page.ContentTypesAssignmentHandler;
049import org.ametys.web.repository.page.Page;
050import org.ametys.web.repository.site.Site;
051import org.ametys.web.repository.site.SiteManager;
052
053/**
054 * Component for saxing tasks specific to an user.<br>
055 * The algorithm is the following :
056 * <ul>
057 *   <li>First, we get all granted sites for the user with the right manager.
058 *   <li>If there is at least one site allowed, we get all workflows 
059 *       associated with the granted sites.
060 *   <li>Then for each step of each task from the configuration, we get
061 *       all workflows where this step is in current steps and where
062 *       the workflow is contains in the previous list.
063 *   <li>For each workflow matching the previous conditions we
064 *       test if the user has all the rights associated with the step (from
065 *       the configuration) and then we get the content from this workflow.
066 *   <li>Finally, for each content, we sax its first page in order to access
067 *       it directly from an URL. 
068 * </ul>
069 */
070public class WorkflowTasksComponent extends org.ametys.cms.workflow.WorkflowTasksComponent implements Contextualizable
071{
072    
073    /** The avalon role. */
074    @SuppressWarnings("hiding")
075    public static final String ROLE = WorkflowTasksComponent.class.getName();
076
077    /** The site manager. */
078    protected SiteManager _siteManager;
079    
080    /** The avalon context. */
081    protected Context _context;
082
083    /** The content types assignment handler */
084    protected ContentTypesAssignmentHandler _cTypeHandler;
085    
086    @Override
087    public void service(ServiceManager serviceManager) throws ServiceException
088    {
089        super.service(serviceManager);
090        _siteManager = (SiteManager) serviceManager.lookup(SiteManager.ROLE);
091        _cTypeHandler = (ContentTypesAssignmentHandler) serviceManager.lookup(ContentTypesAssignmentHandler.ROLE);
092    }
093    
094    @Override
095    public void contextualize(Context context) throws ContextException
096    {
097        _context = context;
098    }
099    
100    @Override
101    public void toSAX(ContentHandler ch, User user) throws SAXException
102    {
103        XMLUtils.startElement(ch, "tasks");
104        
105        long start = System.currentTimeMillis();
106        
107        Set<String> grantedSites = _siteManager.getGrantedSites(user.getIdentity());
108        long gsEnd = System.currentTimeMillis();
109        long wfEnd = 0;
110        
111        Request request = ContextHelper.getRequest(_context);
112        for (String siteName : grantedSites)
113        {
114            Site site = _siteManager.getSite(siteName);
115            
116            request.setAttribute("siteName", siteName);
117            
118            AttributesImpl siteAttr = new AttributesImpl();
119            siteAttr.addCDATAAttribute("name", siteName);
120            siteAttr.addCDATAAttribute("title", site.getTitle());
121            siteAttr.addCDATAAttribute("siteContext", "/" + siteName);
122            
123            XMLUtils.startElement(ch, "site", siteAttr);
124            
125            long wfStart = System.currentTimeMillis();
126            // Get the workflow corresponding to the configuration.
127            Map<Task, Collection<Content>> workflows = _getCorrespondingWorkflows(user);
128            wfEnd = System.currentTimeMillis();
129            
130            getLogger().info("Contents retrieved in " + (wfEnd - wfStart) + "ms for site '" + siteName + "'");
131            
132            for (Task task : workflows.keySet())
133            {
134                _saxTask(ch, task, workflows.get(task));
135            }
136            
137            XMLUtils.endElement(ch, "site");
138        }
139        
140        long end = System.currentTimeMillis();
141        
142        // Display performance indicators.
143        AttributesImpl attrs = new AttributesImpl();
144        
145        attrs.addCDATAAttribute("Total", Long.toString(end - start));
146        attrs.addCDATAAttribute("GS", Long.toString(gsEnd - start));
147        attrs.addCDATAAttribute("WF", Long.toString(wfEnd - gsEnd));
148        attrs.addCDATAAttribute("SAX", Long.toString(end - wfEnd));
149        
150        XMLUtils.createElement(ch, "render", attrs);
151        
152        XMLUtils.endElement(ch, "tasks");
153    }
154    
155    @Override
156    public void toSAX(ContentHandler ch, User user, String taskId) throws SAXException
157    {
158        XMLUtils.startElement(ch, "tasks");
159        
160        long start = System.currentTimeMillis();
161        
162        Set<String> grantedSites = _siteManager.getGrantedSites(user.getIdentity());
163        long gsEnd = System.currentTimeMillis();
164        long wfEnd = 0;
165        
166        Request request = ContextHelper.getRequest(_context);
167        for (String siteName : grantedSites)
168        {
169            Site site = _siteManager.getSite(siteName);
170            
171            request.setAttribute("siteName", siteName);
172            
173            AttributesImpl siteAttr = new AttributesImpl();
174            siteAttr.addCDATAAttribute("name", siteName);
175            siteAttr.addCDATAAttribute("title", site.getTitle());
176            siteAttr.addCDATAAttribute("siteContext", "/" + siteName);
177            
178            XMLUtils.startElement(ch, "site", siteAttr);
179            
180            long wfStart = System.currentTimeMillis();
181            
182            Task task = _tasks.get(taskId);
183            Collection<Content> contents = _getTaskContents(user, task);
184            
185            wfEnd = System.currentTimeMillis();
186            getLogger().info("Contents retrieved in " + (wfEnd - wfStart) + "ms for site '" + siteName + "'");
187            
188            _saxTask(ch, task, contents);
189            
190            XMLUtils.endElement(ch, "site");
191        }
192        
193        long end = System.currentTimeMillis();
194        
195        // Display performance indicators.
196        AttributesImpl attrs = new AttributesImpl();
197        
198        attrs.addCDATAAttribute("Total", Long.toString(end - start));
199        attrs.addCDATAAttribute("GS", Long.toString(gsEnd - start));
200        attrs.addCDATAAttribute("WF", Long.toString(wfEnd - gsEnd));
201        attrs.addCDATAAttribute("SAX", Long.toString(end - wfEnd));
202        
203        XMLUtils.createElement(ch, "render", attrs);
204        
205        XMLUtils.endElement(ch, "tasks");
206    }
207    
208    /**
209     * SAX the contents for given user, site and task
210     * @param ch the content handler to SAX into
211     * @param user the user
212     * @param siteName the site name
213     * @param language the language.
214     * @param taskId the task id
215     * @throws SAXException if an error occurred while saxing
216     */
217    public void toSAX(ContentHandler ch, User user, String siteName, String language, String taskId) throws SAXException
218    {
219        XMLUtils.startElement(ch, "tasks");
220        
221        long start = System.currentTimeMillis();
222        long wfEnd = 0;
223        
224        Request request = ContextHelper.getRequest(_context);
225        Site site = _siteManager.getSite(siteName);
226        
227        request.setAttribute("siteName", siteName);
228        request.setAttribute("language", language);
229        
230        AttributesImpl siteAttr = new AttributesImpl();
231        siteAttr.addCDATAAttribute("name", siteName);
232        siteAttr.addCDATAAttribute("title", site.getTitle());
233        siteAttr.addCDATAAttribute("siteContext", "/" + siteName);
234        if (language != null)
235        {
236            siteAttr.addCDATAAttribute("language", language);
237        }
238        
239        XMLUtils.startElement(ch, "site", siteAttr);
240        
241        long wfStart = System.currentTimeMillis();
242        
243        if (taskId != null)
244        {
245            Task task = _tasks.get(taskId);
246            Collection<Content> contents = _getTaskContents(user, task);
247            
248            wfEnd = System.currentTimeMillis();
249            
250            if (getLogger().isInfoEnabled())
251            {
252                getLogger().info("Contents retrieved in " + (wfEnd - wfStart) + "ms for site '" + siteName + "'");
253            }
254            
255            _saxTask(ch, task, contents);
256        }
257        else
258        {
259            Map<Task, Collection<Content>> workflows = _getCorrespondingWorkflows(user);
260            wfEnd = System.currentTimeMillis();
261            
262            if (getLogger().isInfoEnabled())
263            {
264                getLogger().info("Contents retrieved in " + (wfEnd - wfStart) + "ms for site '" + siteName + "'");
265            }
266            
267            for (Task task : workflows.keySet())
268            {
269                _saxTask(ch, task, workflows.get(task));
270            }
271        }
272        
273        XMLUtils.endElement(ch, "site");
274    
275        long end = System.currentTimeMillis();
276        
277        // Display performance indicators.
278        AttributesImpl attrs = new AttributesImpl();
279        
280        attrs.addCDATAAttribute("Total", Long.toString(end - start));
281        attrs.addCDATAAttribute("WF", Long.toString(wfEnd - start));
282        attrs.addCDATAAttribute("SAX", Long.toString(end - wfEnd));
283        
284        XMLUtils.createElement(ch, "render", attrs);
285        
286        XMLUtils.endElement(ch, "tasks");
287    }
288    
289    /**
290     * Get the list of contents for a given user, task and site.
291     * @param user the user.
292     * @param taskId the task ID.
293     * @param siteName the site name.
294     * @param language the language.
295     * @param limit the maximum number of results, 0 for all.
296     * @return the contents as an iterable collection of contents.
297     * @throws AmetysRepositoryException if an error occurred
298     */
299    public Collection<Content> getContents(User user, String taskId, String siteName, String language, int limit) throws AmetysRepositoryException
300    {
301        Request request = ContextHelper.getRequest(_context);
302        request.setAttribute("siteName", siteName);
303        request.setAttribute("language", siteName);
304        
305        return super.getContents(user, taskId, limit);
306    }
307    
308    @Override
309    protected List<Expression> _getContentsAndExpressions(TaskStep step, User user)
310    {
311        List<Expression> exprs = super._getContentsAndExpressions(step, user);
312        
313        Request request = ContextHelper.getRequest(_context);
314        String siteName = (String) request.getAttribute("siteName");
315        if (StringUtils.isNotEmpty(siteName))
316        {
317            exprs.add(new StringExpression("site", Operator.EQ, siteName));
318        }
319        
320        Expression cTypeExpr = _getContentTypeExpression (siteName);
321        if (cTypeExpr != null)
322        {
323            exprs.add(cTypeExpr);
324        }
325        
326        String language = (String) request.getAttribute("language");
327        if (StringUtils.isNotEmpty(language))
328        {
329            exprs.add(new LanguageExpression(Operator.EQ, language));
330        }
331        
332        return exprs;
333    }
334    
335    /**
336     * The content type expression 
337     * @param siteName the site name
338     * @return The content type expression 
339     */
340    protected Expression _getContentTypeExpression (String siteName)
341    {
342        Site site = _siteManager.getSite(siteName);
343        
344        List<Expression> cTypeExprs = new ArrayList<>();
345        
346        Set<String> cTypeIds = _cTypeHandler.getAvailableContentTypes(site, false);
347        for (String cTypeId : cTypeIds)
348        {
349            cTypeExprs.add(new ContentTypeExpression(Operator.EQ, cTypeId));
350        }
351        
352        if (cTypeIds.size() == 0)
353        {
354            return null;
355        }
356        
357        return new OrExpression(cTypeExprs.toArray(new Expression[cTypeExprs.size()]));
358    }
359    
360    @Override
361    protected void _saxAdditionalAttributes(Content content, Task task, AttributesImpl attrs) throws SAXException
362    {
363        if (content instanceof WebContent)
364        {
365            WebContent webContent = (WebContent) content;
366            Iterator<Page> pages = webContent.getReferencingPages().iterator();
367            if (pages.hasNext())
368            {
369                Page page = pages.next();
370                attrs.addCDATAAttribute("pageTitle", page.getTitle());
371                attrs.addCDATAAttribute("pageUri", page.getSitemapName() + "/" + page.getPathInSitemap());
372                attrs.addCDATAAttribute("pageId", page.getId());
373            }
374        }
375    }
376}