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