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.time.ZoneId; 020import java.time.ZonedDateTime; 021import java.util.Arrays; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.HashSet; 025import java.util.Map; 026import java.util.Set; 027 028import org.apache.avalon.framework.parameters.ParameterException; 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031import org.apache.cocoon.ProcessingException; 032import org.apache.cocoon.generation.ServiceableGenerator; 033import org.apache.cocoon.xml.AttributesImpl; 034import org.apache.cocoon.xml.XMLUtils; 035import org.apache.commons.lang.StringUtils; 036import org.xml.sax.SAXException; 037 038import org.ametys.core.user.UserIdentity; 039import org.ametys.core.util.DateUtils; 040import org.ametys.plugins.repository.AmetysObjectResolver; 041import org.ametys.plugins.survey.data.SurveyAnswer; 042import org.ametys.plugins.survey.data.SurveyAnswerDao; 043import org.ametys.plugins.survey.data.SurveySession; 044import org.ametys.plugins.survey.repository.Survey; 045import org.ametys.plugins.survey.repository.SurveyQuestion; 046 047/** 048 * Generates a specific survey user session from its ID. 049 */ 050public class SurveySessionGenerator extends ServiceableGenerator 051{ 052 053 /** The ametys object resolver. */ 054 protected AmetysObjectResolver _resolver; 055 056 /** The survey data DAO. */ 057 protected SurveyAnswerDao _surveyDao; 058 059 @Override 060 public void service(ServiceManager serviceManager) throws ServiceException 061 { 062 super.service(serviceManager); 063 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 064 _surveyDao = (SurveyAnswerDao) serviceManager.lookup(SurveyAnswerDao.ROLE); 065 } 066 067 @Override 068 public void generate() throws IOException, SAXException, ProcessingException 069 { 070// Request request = ObjectModelHelper.getRequest(objectModel); 071 072 // Get the session ID. 073 int sessionId; 074 try 075 { 076 sessionId = parameters.getParameterAsInteger("id"); 077 } 078 catch (ParameterException e) 079 { 080 throw new ProcessingException("Session ID is mandatory.", e); 081 } 082 083 // Retrieve the corresponding session from the database. 084 SurveySession surveySession = _surveyDao.getSessionWithAnswers(sessionId); 085 086 // Resolve the corresponding survey. 087 Survey survey = _resolver.resolveById(surveySession.getSurveyId()); 088 089 contentHandler.startDocument(); 090 091 // Generate the session and its answers. 092 saxSession(surveySession, survey, true); 093 094 contentHandler.endDocument(); 095 } 096 097 /** 098 * Generate the data of a survey user session. 099 * @param surveySession the survey session. 100 * @param survey the survey. 101 * @param withAnswers true to generate answers along, false otherwise. 102 * @throws SAXException if an error occurs while saxing the session 103 */ 104 protected void saxSession(SurveySession surveySession, Survey survey, boolean withAnswers) throws SAXException 105 { 106 ZonedDateTime submittedAt = surveySession.getSubmittedAt().toInstant().atZone(ZoneId.systemDefault()); 107 108 AttributesImpl attrs = new AttributesImpl(); 109 attrs.addCDATAAttribute("id", Integer.toString(surveySession.getId())); 110 attrs.addCDATAAttribute("submittedAt", DateUtils.getISODateTimeFormatter().format(submittedAt)); 111 UserIdentity user = surveySession.getUser(); 112 if (user != null) 113 { 114 attrs.addCDATAAttribute("user", UserIdentity.userIdentityToString(user)); 115 } 116 117 XMLUtils.startElement(contentHandler, "session", attrs); 118 119 if (withAnswers) 120 { 121 saxAnswers(surveySession, survey); 122 } 123 124 XMLUtils.endElement(contentHandler, "session"); 125 } 126 127 /** 128 * Generate the answers of a given session. 129 * @param surveySession the survey session. 130 * @param survey the survey. 131 * @throws SAXException if an error occurs while saxing the answers 132 */ 133 protected void saxAnswers(SurveySession surveySession, Survey survey) throws SAXException 134 { 135 AttributesImpl attrs = new AttributesImpl(); 136 137 Map<String, SurveyAnswer> answerMap = getAnswerMap(surveySession); 138 139 for (SurveyQuestion question : survey.getQuestions()) 140 { 141 SurveyAnswer answer = answerMap.get(question.getName()); 142 143 attrs.clear(); 144 attrs.addCDATAAttribute("name", question.getName()); 145 attrs.addCDATAAttribute("title", question.getTitle()); 146 attrs.addCDATAAttribute("type", question.getType().toString()); 147 attrs.addCDATAAttribute("mandatory", Boolean.toString(question.isMandatory())); 148 XMLUtils.startElement(contentHandler, "question", attrs); 149 150 if (answer != null) 151 { 152 Map<String, Set<String>> values = getValueMap(question, answer.getValue()); 153 154 for (String option : values.keySet()) 155 { 156 attrs.clear(); 157 attrs.addCDATAAttribute("name", option); 158 XMLUtils.startElement(contentHandler, "option", attrs); 159 160 for (String value : values.get(option)) 161 { 162 attrs.clear(); 163 attrs.addCDATAAttribute("value", value); 164 XMLUtils.createElement(contentHandler, "answer", attrs); 165 } 166 167 XMLUtils.endElement(contentHandler, "option"); 168 } 169 } 170 171 XMLUtils.endElement(contentHandler, "question"); 172 } 173 } 174 175 /** 176 * Get the answers of a survey session as a Map, indexed by question ID. 177 * @param surveySession the survey session. 178 * @return the answers as a Map, indexed by question ID. 179 */ 180 protected Map<String, SurveyAnswer> getAnswerMap(SurveySession surveySession) 181 { 182 Map<String, SurveyAnswer> answerMap = new HashMap<>(); 183 184 for (SurveyAnswer answer : surveySession.getAnswers()) 185 { 186 answerMap.put(answer.getQuestionId(), answer); 187 } 188 189 return answerMap; 190 } 191 192 /** 193 * Get the user-input value as a Map from the database value, which is a single serialized string. 194 * @param question the question. 195 * @param value the value from the database. 196 * @return the value as a Map. 197 */ 198 protected Map<String, Set<String>> getValueMap(SurveyQuestion question, String value) 199 { 200 Map<String, Set<String>> values = new HashMap<>(); 201 202 if (value != null) 203 { 204 switch (question.getType()) 205 { 206 case SINGLE_MATRIX: 207 case MULTIPLE_MATRIX: 208 String[] entries = StringUtils.split(value, ';'); 209 for (String entry : entries) 210 { 211 String[] keyValue = StringUtils.split(entry, ':'); 212 if (keyValue.length == 2 && StringUtils.isNotEmpty(keyValue[0])) 213 { 214 Set<String> valueSet = new HashSet<>(Arrays.asList(StringUtils.split(keyValue[1], ','))); 215 216 values.put(keyValue[0], valueSet); 217 } 218 } 219 break; 220 case SINGLE_CHOICE: 221 case MULTIPLE_CHOICE: 222 Set<String> valueSet = new HashSet<>(Arrays.asList(StringUtils.split(value, ','))); 223 values.put("values", valueSet); 224 break; 225 case FREE_TEXT: 226 case MULTILINE_FREE_TEXT: 227 default: 228 values.put("values", Collections.singleton(value)); 229 break; 230 } 231 } 232 233 return values; 234 } 235 236}