001/*
002 *  Copyright 2011 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.survey.generators;
017
018import java.io.IOException;
019import java.util.List;
020import java.util.Map;
021
022import javax.jcr.RepositoryException;
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.StringUtils;
033import org.xml.sax.SAXException;
034
035import org.ametys.cms.data.Binary;
036import org.ametys.plugins.explorer.resources.Resource;
037import org.ametys.plugins.repository.AmetysObject;
038import org.ametys.plugins.repository.AmetysObjectIterable;
039import org.ametys.plugins.repository.AmetysObjectResolver;
040import org.ametys.plugins.repository.ModifiableTraversableAmetysObject;
041import org.ametys.plugins.repository.UnknownAmetysObjectException;
042import org.ametys.plugins.repository.jcr.JCRAmetysObject;
043import org.ametys.plugins.survey.dao.SurveyDAO;
044import org.ametys.plugins.survey.repository.AbstractSurveyElement;
045import org.ametys.plugins.survey.repository.Survey;
046import org.ametys.plugins.survey.repository.SurveyPage;
047import org.ametys.plugins.survey.repository.SurveyQuestion;
048import org.ametys.plugins.survey.repository.SurveyRule;
049import org.ametys.plugins.survey.repository.SurveyRule.RuleType;
050import org.ametys.web.repository.site.SiteManager;
051
052/**
053 * SAX surveys
054 *
055 */
056public class SurveysGenerator extends ServiceableGenerator
057{
058    /** The Ametys object resolver */
059    protected AmetysObjectResolver _resolver;
060    /** The site manager */
061    protected SiteManager _siteManager;
062    /** The DAO for surveys */
063    protected SurveyDAO _surveyDAO;
064    
065    @Override
066    public void service(ServiceManager serviceManager) throws ServiceException
067    {
068        super.service(serviceManager);
069        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
070        _siteManager = (SiteManager) serviceManager.lookup(SiteManager.ROLE);
071        _surveyDAO = (SurveyDAO) serviceManager.lookup(SurveyDAO.ROLE);
072    }
073    
074    @Override
075    public void generate() throws IOException, SAXException, ProcessingException
076    {
077        Request request = ObjectModelHelper.getRequest(objectModel);
078        
079        String siteName = request.getParameter("siteName");
080        String lang = request.getParameter("lang");
081        String id = request.getParameter("id");
082        boolean saxChildren = parameters.getParameterAsBoolean("saxChildren", true);
083        
084        contentHandler.startDocument();
085        
086        try
087        {
088            if (StringUtils.isEmpty(id) || id.equals("survey-root-node"))
089            {
090                XMLUtils.startElement(contentHandler, "surveys");
091                
092                ModifiableTraversableAmetysObject rootNode = getSurveyRootNode(siteName, lang);
093                
094                AmetysObjectIterable<Survey> surveys = rootNode.getChildren();
095                for (Survey survey : surveys)
096                {
097                    toSAX(survey, false);
098                }
099                
100                XMLUtils.endElement(contentHandler, "surveys");
101            }
102            else
103            {
104                AmetysObject ao = _resolver.resolveById(id);
105                if (ao instanceof Survey)
106                {
107                    toSAX((Survey) ao, saxChildren);
108                }
109                else if (ao instanceof SurveyPage)
110                {
111                    toSAX((SurveyPage) ao, saxChildren, false);
112                }
113                else if (ao instanceof SurveyQuestion)
114                {
115                    toSAX((SurveyQuestion) ao);
116                }
117            }
118        }
119        catch (RepositoryException e)
120        {
121            throw new ProcessingException("Unable to get surveys", e);
122        }
123        
124        contentHandler.endDocument();
125
126    }
127    
128    /**
129     * SAX a survey
130     * @param survey the survey to SAX
131     * @param saxChildren true to SAX children
132     * @throws SAXException if error occurs while SAXing
133     */
134    protected void toSAX (Survey survey, boolean saxChildren) throws SAXException
135    {
136        AttributesImpl attrs = new AttributesImpl();
137        attrs.addCDATAAttribute("id", survey.getId());  
138        attrs.addCDATAAttribute("name", survey.getName());
139        attrs.addCDATAAttribute("private", String.valueOf(_surveyDAO.isPrivate(survey)));
140        attrs.addCDATAAttribute("validated", String.valueOf(survey.isValidated()));
141        
142        XMLUtils.startElement(contentHandler, "survey", attrs);
143        XMLUtils.createElement(contentHandler, "title", survey.getTitle());
144        XMLUtils.createElement(contentHandler, "label", survey.getLabel());
145        
146        String description = survey.getDescription();
147        if (description != null)
148        {
149            XMLUtils.createElement(contentHandler, "description", description);
150        }
151        
152        String endingMessage = survey.getEndingMessage();
153        if (endingMessage != null)
154        {
155            XMLUtils.createElement(contentHandler, "endingMessage", endingMessage);
156        }
157        
158        toSAXPicture(survey);
159        
160        if (saxChildren)
161        {
162            AmetysObjectIterable<SurveyPage> pages = survey.getChildren();
163            for (SurveyPage page : pages)
164            {
165                toSAX(page, false, false);
166            }
167        }
168        
169        XMLUtils.endElement(contentHandler, "survey");
170    }
171    
172    /**
173     * SAX a survey page
174     * @param page the page to SAX
175     * @param saxChildren true to SAX children
176     * @param saxBranches true to SAX branch logic
177     * @throws SAXException if error occurs while SAXing
178     */
179    protected void toSAX (SurveyPage page, boolean saxChildren, boolean saxBranches) throws SAXException
180    {
181        AttributesImpl attrs = new AttributesImpl();
182        attrs.addCDATAAttribute("id", page.getId());
183        attrs.addCDATAAttribute("name", page.getName());
184        
185        XMLUtils.startElement(contentHandler, "page", attrs);
186        XMLUtils.createElement(contentHandler, "title", page.getTitle());
187        XMLUtils.createElement(contentHandler, "label", page.getLabel());
188        XMLUtils.createElement(contentHandler, "description", page.getDescription());
189        
190        toSAXPicture(page);
191        
192        if (saxChildren)
193        {
194            AmetysObjectIterable<SurveyQuestion> questions = page.getChildren();
195            for (SurveyQuestion question : questions)
196            {
197                toSAX(question);
198            }
199        }
200        
201        if (saxBranches)
202        {
203            saxBranches(page);
204        }
205        
206        XMLUtils.endElement(contentHandler, "page");
207    }
208    
209    /**
210     * SAX branch logic
211     * @param page the page
212     * @throws SAXException if error occurs while SAXing
213     */
214    protected void saxBranches (SurveyPage page) throws SAXException
215    {
216        XMLUtils.startElement(contentHandler, "branches");
217        
218        AmetysObjectIterable<SurveyQuestion> questions = page.getChildren();
219        for (SurveyQuestion question : questions)
220        {
221            List<SurveyRule> rules = question.getRules();
222            
223            for (SurveyRule rule : rules)
224            {
225                AttributesImpl attr = new AttributesImpl();
226                attr.addCDATAAttribute("id", question.getId());
227                attr.addCDATAAttribute("name", question.getName());
228                attr.addCDATAAttribute("value", rule.getOption());
229                RuleType type = rule.getType();
230                attr.addCDATAAttribute("type", type.name());
231                if (type == RuleType.JUMP)
232                {
233                    attr.addCDATAAttribute("page", rule.getPage());
234                }
235                XMLUtils.createElement(contentHandler, "rule", attr);
236            }
237        }
238        
239        SurveyRule rule = page.getRule();
240        if (rule != null)
241        {
242            AttributesImpl attr = new AttributesImpl();
243            RuleType type = rule.getType();
244            attr.addCDATAAttribute("type", type.name());
245            if (type == RuleType.JUMP)
246            {
247                attr.addCDATAAttribute("page", rule.getPage());
248            }
249            XMLUtils.createElement(contentHandler, "page-rule", attr);
250        }
251        
252        XMLUtils.endElement(contentHandler, "branches");
253    }
254    
255    /**
256     * SAX a survey question
257     * @param question the question to SAX
258     * @throws SAXException if error occurs while SAXing
259     */
260    protected void toSAX (SurveyQuestion question) throws SAXException
261    {
262        AttributesImpl attrs = new AttributesImpl();
263        attrs.addCDATAAttribute("id", question.getId());
264        attrs.addCDATAAttribute("name", question.getName());
265        attrs.addCDATAAttribute("type", question.getType().name());
266        attrs.addCDATAAttribute("mandatory", String.valueOf(question.isMandatory()));
267        attrs.addCDATAAttribute("modifiable", String.valueOf(!question.getSurvey().isValidated()));
268        
269        XMLUtils.startElement(contentHandler, "question", attrs);
270        XMLUtils.createElement(contentHandler, "label", question.getLabel());
271        XMLUtils.createElement(contentHandler, "title", question.getTitle());
272        
273        toSAXPicture(question);
274        
275        String regExpType = question.getRegExpType();
276        if (StringUtils.isNotEmpty(regExpType))
277        {
278            XMLUtils.createElement(contentHandler, "regexp", regExpType);
279        }
280        
281        String pattern = question.getRegExpPattern();
282        if (StringUtils.isNotEmpty(pattern))
283        {
284            XMLUtils.createElement(contentHandler, "pattern", pattern);
285        }
286        
287        Map<String, String> options = question.getOptions();
288        if (options.size() > 0)
289        {
290            AttributesImpl attr = new AttributesImpl();
291            attr.addCDATAAttribute("other-option", String.valueOf(question.hasOtherOption()));
292            XMLUtils.startElement(contentHandler, "options", attr);
293            for (String value : options.keySet())
294            {
295                attr = new AttributesImpl();
296                attr.addCDATAAttribute("value", value);
297                XMLUtils.createElement(contentHandler, "option", attr, options.get(value));
298            }
299            
300            XMLUtils.endElement(contentHandler, "options");
301        }
302        
303        Map<String, String> columns = question.getColumns();
304        if (columns.size() > 0)
305        {
306            XMLUtils.startElement(contentHandler, "columns");
307            for (String value : columns.keySet())
308            {
309                AttributesImpl attr = new AttributesImpl();
310                attr.addCDATAAttribute("value", value);
311                XMLUtils.createElement(contentHandler, "column", attr, columns.get(value));
312            }
313            XMLUtils.endElement(contentHandler, "columns");
314        }
315        
316        
317        XMLUtils.endElement(contentHandler, "question");
318    }
319    
320    /**
321     * SAX the picture of the element of a survey
322     * @param elmt The survey element
323     * @throws SAXException If an error occurred
324     */
325    protected void toSAXPicture (AbstractSurveyElement elmt) throws SAXException
326    {
327        String pictureType = elmt.getPictureType();
328        
329        if (pictureType != null)
330        {
331            AttributesImpl attrsPicture = new AttributesImpl();
332            attrsPicture.addCDATAAttribute("pictureType", pictureType);
333            if (pictureType.equals("resource"))
334            {
335                String resourceId = elmt.getResourcePictureId();
336                attrsPicture.addCDATAAttribute("pictureId", resourceId);
337                try
338                {
339                    Resource resource = _resolver.resolveById(resourceId);
340                    attrsPicture.addCDATAAttribute("pictureName", resource.getName());
341                    attrsPicture.addCDATAAttribute("pictureSize", Long.toString(resource.getLength()));
342                    attrsPicture.addCDATAAttribute("imageType", "explorer");
343                }
344                catch (UnknownAmetysObjectException e)
345                {
346                    getLogger().error("The resource of id'" + resourceId + "' does not exist anymore. The picture for element survey of id '" + elmt.getId() + "' will be ignored.", e);
347                }
348                
349            }
350            else if (pictureType.equals("external"))
351            {
352                Binary picMeta = elmt.getExternalPicture();
353                attrsPicture.addCDATAAttribute("picturePath", "picture");
354                attrsPicture.addCDATAAttribute("pictureName", picMeta.getFilename());
355                attrsPicture.addCDATAAttribute("pictureSize", Long.toString(picMeta.getLength()));
356                attrsPicture.addCDATAAttribute("imageType", "metadata");
357            }
358            XMLUtils.createElement(contentHandler, "picture", attrsPicture);
359        }
360        
361        XMLUtils.createElement(contentHandler, "pictureAlternative", StringUtils.defaultString(elmt.getPictureAlternative()));
362    }
363    
364    
365    /**
366     * Get the root node for surveys
367     * @param siteName the site name
368     * @param lang the language
369     * @return the root node
370     * @throws RepositoryException if an error occurs when retrieving the survey's root node
371     */
372    protected ModifiableTraversableAmetysObject getSurveyRootNode (String siteName, String lang) throws RepositoryException
373    {
374        ModifiableTraversableAmetysObject pluginsNode = _siteManager.getSite(siteName).getRootPlugins();
375        
376        ModifiableTraversableAmetysObject surveyNode = null;
377        if (!pluginsNode.hasChild("survey"))
378        {
379            surveyNode = ((ModifiableTraversableAmetysObject) pluginsNode.createChild("survey", "ametys:unstructured")).createChild("ametys:surveys", "ametys:unstructured");
380        }
381        else
382        {
383            surveyNode = pluginsNode.getChild("survey/ametys:surveys");
384        }
385        
386        if (!surveyNode.hasChild(lang))
387        {
388            surveyNode.createChild(lang, "ametys:unstructured");
389            ((JCRAmetysObject) pluginsNode).getNode().getSession().save();
390        }
391        
392        return pluginsNode.getChild("survey/ametys:surveys/" + lang);
393    }
394
395}