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.answer; 017 018import java.net.URI; 019import java.net.URISyntaxException; 020import java.time.LocalDate; 021import java.time.ZoneId; 022import java.time.ZonedDateTime; 023import java.time.format.FormatStyle; 024import java.util.ArrayList; 025import java.util.Arrays; 026import java.util.Collection; 027import java.util.Collections; 028import java.util.Date; 029import java.util.HashMap; 030import java.util.HashSet; 031import java.util.Iterator; 032import java.util.LinkedHashMap; 033import java.util.List; 034import java.util.Map; 035import java.util.Set; 036import java.util.regex.Pattern; 037 038import org.apache.avalon.framework.parameters.Parameters; 039import org.apache.avalon.framework.service.ServiceException; 040import org.apache.avalon.framework.service.ServiceManager; 041import org.apache.cocoon.acting.ServiceableAction; 042import org.apache.cocoon.environment.Cookie; 043import org.apache.cocoon.environment.ObjectModelHelper; 044import org.apache.cocoon.environment.Redirector; 045import org.apache.cocoon.environment.Request; 046import org.apache.cocoon.environment.Response; 047import org.apache.cocoon.environment.SourceResolver; 048import org.apache.cocoon.environment.http.HttpCookie; 049import org.apache.commons.lang.StringUtils; 050 051import org.ametys.core.right.RightManager; 052import org.ametys.core.user.CurrentUserProvider; 053import org.ametys.core.user.UserIdentity; 054import org.ametys.core.util.DateUtils; 055import org.ametys.plugins.repository.AmetysObjectIterable; 056import org.ametys.plugins.repository.AmetysObjectResolver; 057import org.ametys.plugins.repository.UnknownAmetysObjectException; 058import org.ametys.plugins.survey.SurveyDateUtils; 059import org.ametys.plugins.survey.data.SurveyAnswer; 060import org.ametys.plugins.survey.data.SurveyAnswerDao; 061import org.ametys.plugins.survey.data.SurveySession; 062import org.ametys.plugins.survey.repository.Survey; 063import org.ametys.plugins.survey.repository.SurveyAccessHelper; 064import org.ametys.plugins.survey.repository.SurveyPage; 065import org.ametys.plugins.survey.repository.SurveyQuestion; 066import org.ametys.plugins.survey.repository.SurveyRule; 067import org.ametys.runtime.i18n.I18nizableTextParameter; 068import org.ametys.runtime.i18n.I18nizableDate; 069import org.ametys.runtime.i18n.I18nizableText; 070import org.ametys.web.URIPrefixHandler; 071import org.ametys.web.repository.page.Page; 072 073/** 074 * Process the user answers to the survey. 075 */ 076public class ProcessInputAction extends ServiceableAction 077{ 078 079 /** The name of the cookie storing the taken surveys. */ 080 public static final String COOKIE_NAME = "org.ametys.survey.answeredSurveys"; 081 082 /** The ametys object resolver. */ 083 protected AmetysObjectResolver _resolver; 084 /** The ametys object resolver. */ 085 protected SurveyAnswerDao _answerDao; 086 /** The user provider. */ 087 protected CurrentUserProvider _userProvider; 088 /** The uri prefix handler. */ 089 protected URIPrefixHandler _prefixHandler; 090 /** The survey access helper */ 091 protected SurveyAccessHelper _accessHelper; 092 093 /** The plugin name */ 094 protected String _pluginName; 095 096 private RightManager _rightManager; 097 098 @Override 099 public void service(ServiceManager serviceManager) throws ServiceException 100 { 101 super.service(serviceManager); 102 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 103 _answerDao = (SurveyAnswerDao) serviceManager.lookup(SurveyAnswerDao.ROLE); 104 _userProvider = (CurrentUserProvider) serviceManager.lookup(CurrentUserProvider.ROLE); 105 _prefixHandler = (URIPrefixHandler) serviceManager.lookup(URIPrefixHandler.ROLE); 106 _accessHelper = (SurveyAccessHelper) serviceManager.lookup(SurveyAccessHelper.ROLE); 107 _rightManager = (RightManager) serviceManager.lookup(RightManager.ROLE); 108 } 109 110 @Override 111 public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception 112 { 113 Request request = ObjectModelHelper.getRequest(objectModel); 114 Response response = ObjectModelHelper.getResponse(objectModel); 115 116 _pluginName = getPluginName(request); 117 118 String surveyId = request.getParameter("surveyId"); 119 if (StringUtils.isNotEmpty(surveyId)) 120 { 121 // Get the survey object. 122 Survey survey = _resolver.resolveById(surveyId); 123 124 SurveyErrors errors = new SurveyErrors(); 125 126 if (!checkAccess(survey, request, errors)) 127 { 128 request.setAttribute("survey", survey); 129 request.setAttribute("survey-errors", errors); 130 return null; 131 } 132 133 // Get the user input. 134 SurveyInput surveyInput = getInput(survey, request); 135 136 // Validate the user input. 137 validateInput(survey, surveyInput, errors, request); 138 139 // If there were errors in the input, store it as a request attribute and stop. 140 if (errors.hasErrors()) 141 { 142 request.setAttribute("survey", survey); 143 request.setAttribute("survey-errors", errors); 144 return null; 145 } 146 147 // Add the user session into the database. 148 _answerDao.addSession(surveyInput); 149 150 setCookie(request, response, surveyId); 151 152 // Redirect if necessary. 153 String redirectPageId = survey.getRedirection(); 154 if (StringUtils.isNotEmpty(redirectPageId)) 155 { 156 try 157 { 158 Page page = _resolver.resolveById(redirectPageId); 159 redirector.globalRedirect(false, _prefixHandler.getAbsoluteUriPrefix(page.getSiteName()) + "/" + page.getSitemapName() + "/" + page.getPathInSitemap() + ".html"); 160 } 161 catch (UnknownAmetysObjectException e) 162 { 163 getLogger().warn("The survey '" + survey.getId() + "' wants to redirect to the unexisting page '" + redirectPageId + "'. Redirecting to default page.", e); 164 } 165 } 166 } 167 168 return EMPTY_MAP; 169 } 170 171 /** 172 * Get the plugin name 173 * @param request The request 174 * @return The plugin name 175 */ 176 protected String getPluginName (Request request) 177 { 178 return (String) request.getAttribute("pluginName"); 179 } 180 181 /** 182 * Check if user can answer to the survey 183 * @param survey The survey 184 * @param request The request 185 * @param errors The survey errors 186 * @return false if the access failed 187 */ 188 protected boolean checkAccess(Survey survey, Request request, SurveyErrors errors) 189 { 190 UserIdentity user = getAuthenticatedUser(request); 191 192 if (!_rightManager.hasReadAccess(user, survey)) 193 { 194 // User is not authorized 195 errors.addErrors("survey-access", Collections.singletonList(new I18nizableText("plugin." + _pluginName, "PLUGINS_SURVEY_RENDER_UNAUTHORIZED"))); 196 return false; 197 } 198 199 String surveyId = survey.getId(); 200 Date submissionDate = _accessHelper.getSubmissionDate(surveyId, user); 201 202 if (submissionDate != null) 203 { 204 LocalDate localDate = DateUtils.asLocalDate(submissionDate); 205 // The authenticated user has already answered to the survey 206 Map<String, I18nizableTextParameter> i18nParams = new HashMap<>(); 207 i18nParams.put("date", new I18nizableDate(localDate, FormatStyle.MEDIUM)); 208 errors.addErrors("survey-access", Collections.singletonList(new I18nizableText("plugin." + _pluginName, "PLUGINS_SURVEY_RENDER_ALREADY_TAKEN_ON", i18nParams))); 209 return false; 210 } 211 212 // Finally check cookies 213 if (user == null && _accessHelper.getCookieName(request, survey) != null) 214 { 215 // Anonymous user has already answered to the survey 216 errors.addErrors("survey-access", Collections.singletonList(new I18nizableText("plugin." + _pluginName, "PLUGINS_SURVEY_RENDER_ALREADY_TAKEN"))); 217 return false; 218 } 219 220 // User can access to the survey 221 return true; 222 } 223 224 /** 225 * Get the authenticated user 226 * @param request The request 227 * @return The authenticated user 228 */ 229 protected UserIdentity getAuthenticatedUser (Request request) 230 { 231 return _userProvider.getUser(); 232 } 233 234 /** 235 * Get the user input. 236 * @param survey the survey. 237 * @param request the request. 238 * @return the user input. 239 */ 240 protected SurveyInput getInput(Survey survey, Request request) 241 { 242 String clientIp = getClientIp(request); 243 UserIdentity user = getAuthenticatedUser(request); 244 245 SurveyInput surveySession = new SurveyInput(); 246 247 List<SurveyInputAnswer> answers = new ArrayList<>(); 248 249 surveySession.setSurveyId(survey.getId()); 250 surveySession.setSubmittedAt(new Date()); 251 surveySession.setUser(user); 252 surveySession.setIpAddress(clientIp); 253 surveySession.setAnswerList(answers); 254 255 try (AmetysObjectIterable<SurveyQuestion> questions = survey.getQuestions()) 256 { 257 for (SurveyQuestion question : questions) 258 { 259 Map<String, Set<String>> values = getValues(question, request); 260 261 SurveyInputAnswer answer = new SurveyInputAnswer(question, values); 262 answers.add(answer); 263 } 264 265 return surveySession; 266 } 267 } 268 269 /** 270 * Get an answer value from the request. 271 * @param question the corresponding question. 272 * @param request the request. 273 * @return the answer value. 274 */ 275 protected Map<String, Set<String>> getValues(SurveyQuestion question, Request request) 276 { 277 Map<String, Set<String>> values = new LinkedHashMap<>(); 278 279 String name = question.getName(); 280 switch (question.getType()) 281 { 282 case SINGLE_MATRIX: 283 case MULTIPLE_MATRIX: 284 Collection<String> options = question.getOptions().keySet(); 285 286 for (String option : options) 287 { 288 String paramName = name + "_" + option; 289 String[] paramValues = request.getParameterValues(paramName); 290 291 if (paramValues != null) 292 { 293 values.put(option, new HashSet<>(Arrays.asList(paramValues))); 294 } 295 } 296 break; 297 case FREE_TEXT: 298 case MULTILINE_FREE_TEXT: 299 String[] textValues = request.getParameterValues(name); 300 if (textValues != null) 301 { 302 values.put("values", new HashSet<>(Arrays.asList(textValues))); 303 } 304 break; 305 case SINGLE_CHOICE: 306 case MULTIPLE_CHOICE: 307 default: 308 List<String> valuesAsList = new ArrayList<>(); 309 String[] paramValues = request.getParameterValues(name); 310 if (paramValues != null) 311 { 312 for (String value : paramValues) 313 { 314 if (value.equals("__internal_other")) 315 { 316 valuesAsList.add(request.getParameter("__internal_other_" + name)); 317 } 318 else 319 { 320 valuesAsList.add(value); 321 } 322 } 323 values.put("values", new HashSet<>(valuesAsList)); 324 } 325 break; 326 } 327 328 return values; 329 } 330 331 /** 332 * Validate the user input. 333 * @param survey the survey. 334 * @param input the user input. 335 * @param errors the errors. 336 * @param request the request. 337 */ 338 protected void validateInput(Survey survey, SurveyInput input, SurveyErrors errors, Request request) 339 { 340 SurveyRule ruleToExecute = null; 341 342 Map<String, SurveyInputAnswer> answers = input.getAnswerMap(); 343 344 for (SurveyPage page : survey.getPages()) 345 { 346 if (ruleToExecute == null || processPage(page, ruleToExecute)) 347 { 348 // Reset the current rule. 349 ruleToExecute = null; 350 351 AmetysObjectIterable<SurveyQuestion> questions = page.getQuestions(); 352 353 for (SurveyQuestion question : questions) 354 { 355 SurveyInputAnswer answer = answers.get(question.getName()); 356 357 switch (question.getType()) 358 { 359 case FREE_TEXT: 360 case MULTILINE_FREE_TEXT: 361 errors.addErrors(question.getName(), validateText(answer, request)); 362 ruleToExecute = evaluateTextRules(question, answer); 363 break; 364 case SINGLE_CHOICE: 365 case MULTIPLE_CHOICE: 366 errors.addErrors(question.getName(), validateChoice(answer, request)); 367 ruleToExecute = evaluateChoiceRules(question, answer); 368 break; 369 case SINGLE_MATRIX: 370 case MULTIPLE_MATRIX: 371 errors.addErrors(question.getName(), validateMatrix(answer, request)); 372 ruleToExecute = evaluateMatrixRules(question, answer); 373 break; 374 default: 375 break; 376 } 377 } 378 379 SurveyRule pageRule = page.getRule(); 380 381 if (ruleToExecute == null && pageRule != null) 382 { 383 ruleToExecute = pageRule; 384 } 385 } 386 } 387 } 388 389 /** 390 * Test if a page is to be processed, depending on the rule. 391 * @param page the page to test. 392 * @param rule the rule to execute. 393 * @return true to process the page, false otherwise. 394 */ 395 protected boolean processPage(SurveyPage page, SurveyRule rule) 396 { 397 boolean processPage = false; 398 399 switch (rule.getType()) 400 { 401 case JUMP: 402 // If the page is the targeted page, it passes the condition. 403 processPage = page.getId().equals(rule.getPage()); 404 break; 405 case SKIP: 406 // If the page is the skipped page, it is not displayed. 407 processPage = !page.getId().equals(rule.getPage()); 408 break; 409 case FINISH: 410 // When finished, no more page is displayed. 411 break; 412 default: 413 break; 414 } 415 416 return processPage; 417 } 418 419 /** 420 * Evaluate rules on a text question. 421 * @param question the text question. 422 * @param answer the user answer to the question. 423 * @return the matched rule. 424 */ 425 protected SurveyRule evaluateTextRules(SurveyQuestion question, SurveyInputAnswer answer) 426 { 427 return null; 428 } 429 430 /** 431 * Evaluate rules on a choice question. 432 * @param question the choice question. 433 * @param answer the user answer to the question. 434 * @return the matched rule. 435 */ 436 protected SurveyRule evaluateChoiceRules(SurveyQuestion question, SurveyInputAnswer answer) 437 { 438 SurveyRule matchedRule = null; 439 440 Map<String, Set<String>> valueMap = answer.getValuesMap(); 441 if (valueMap.containsKey("values")) 442 { 443 Set<String> values = answer.getValuesMap().get("values"); 444 445 Iterator<SurveyRule> questionRules = question.getRules().iterator(); 446 while (questionRules.hasNext() && matchedRule == null) 447 { 448 SurveyRule rule = questionRules.next(); 449 450 if (values.contains(rule.getOption())) 451 { 452 // Condition met, store the action. 453 matchedRule = rule; 454 } 455 } 456 } 457 458 return matchedRule; 459 } 460 461 /** 462 * Evaluate rules on a matrix question. 463 * @param question the matrix question. 464 * @param answer the user answer to the question. 465 * @return the matched rule. 466 */ 467 protected SurveyRule evaluateMatrixRules(SurveyQuestion question, SurveyInputAnswer answer) 468 { 469 return null; 470 } 471 472 /** 473 * Validate a text field. 474 * @param answer the user answer to the question. 475 * @param request the request. 476 * @return the error list. 477 */ 478 protected List<I18nizableText> validateText(SurveyInputAnswer answer, Request request) 479 { 480 List<I18nizableText> errors = new ArrayList<>(); 481 482 SurveyQuestion question = answer.getQuestion(); 483 484 boolean isBlank = isBlank(answer); 485 486 final String textPrefix = "PLUGINS_SURVEY_RENDER_ERROR_TEXT_"; 487 488 if (question.isMandatory() && isBlank) 489 { 490 errors.add(new I18nizableText("plugin." + _pluginName, textPrefix + "MANDATORY")); 491 } 492 493 if (!isBlank) 494 { 495 errors.addAll(validatePattern(answer, textPrefix)); 496 } 497 498 return errors; 499 } 500 501 /** 502 * Validate a choice question answer. 503 * @param answer the user answer to the question. 504 * @param request the request. 505 * @return the error list. 506 */ 507 protected List<I18nizableText> validateChoice(SurveyInputAnswer answer, Request request) 508 { 509 List<I18nizableText> errors = new ArrayList<>(); 510 511 SurveyQuestion question = answer.getQuestion(); 512 513 boolean isBlank = isBlank(answer); 514 515 final String textPrefix = "PLUGINS_SURVEY_RENDER_ERROR_CHOICE_"; 516 517 if (question.isMandatory() && isBlank) 518 { 519 errors.add(new I18nizableText("plugin." + _pluginName, textPrefix + "MANDATORY")); 520 } 521 522 return errors; 523 } 524 525 /** 526 * Validate a matrix question answer. 527 * @param answer the user answer to the question. 528 * @param request the request. 529 * @return the error list. 530 */ 531 protected List<I18nizableText> validateMatrix(SurveyInputAnswer answer, Request request) 532 { 533 List<I18nizableText> errors = new ArrayList<>(); 534 535 SurveyQuestion question = answer.getQuestion(); 536 537 boolean isBlank = isBlank(answer); 538 539 final String textPrefix = "PLUGINS_SURVEY_RENDER_ERROR_MATRIX_"; 540 541 if (question.isMandatory() && isBlank) 542 { 543 errors.add(new I18nizableText("plugin." + _pluginName, textPrefix + "MANDATORY")); 544 } 545 546 return errors; 547 } 548 549 /** 550 * Validate an answer against a pattern. 551 * @param answer the user answer to the question. 552 * @param keyPrefix the error i18n key prefix. 553 * @return the error list. 554 */ 555 protected List<I18nizableText> validatePattern(SurveyInputAnswer answer, String keyPrefix) 556 { 557 List<I18nizableText> errors = new ArrayList<>(); 558 559 SurveyQuestion question = answer.getQuestion(); 560 String regex = question.getRegExpPattern(); 561 String value = answer.getValue(); 562 563 if (StringUtils.isNotBlank(regex)) 564 { 565 if (!Pattern.matches(regex, value)) 566 { 567 errors.add(new I18nizableText("plugin." + _pluginName, keyPrefix + "PATTERN")); 568 } 569 } 570 571 return errors; 572 } 573 574 /** 575 * Test if the answer is empty. 576 * @param answer the user answer. 577 * @return true if the answer is empty. 578 */ 579 protected boolean isBlank(SurveyInputAnswer answer) 580 { 581 boolean blank = answer.getValuesMap().isEmpty(); 582 583 for (Set<String> values : answer.getValuesMap().values()) 584 { 585 if (StringUtils.isEmpty(StringUtils.join(values, ""))) 586 { 587 return true; 588 } 589 } 590 591 return blank; 592 } 593 594 /** 595 * Indicate in a cookie that the survey was taken. 596 * @param request the request. 597 * @param response the response. 598 * @param surveyId the ID of the survey that was just taken. 599 */ 600 protected void setCookie(Request request, Response response, String surveyId) 601 { 602 Map<String, Cookie> cookieMap = request.getCookieMap(); 603 604 Cookie cookie = null; 605 String cookieValue = surveyId + "#" + SurveyDateUtils.zonedDateTimeToString(ZonedDateTime.now(ZoneId.of("UTC"))); 606 if (cookieMap.containsKey(COOKIE_NAME)) 607 { 608 cookie = cookieMap.get(COOKIE_NAME); 609 String newValue = cookie.getValue() + '|' + cookieValue; 610 cookie.setValue(newValue); 611 } 612 else 613 { 614 cookie = response.createCookie(COOKIE_NAME, cookieValue); 615 cookie.setSecure(request.isSecure()); 616 ((HttpCookie) cookie).getServletCookie().setHttpOnly(false); // Cookie is also manipulated by the javascript 617 } 618 619 cookie.setVersion(1); 620 cookie.setMaxAge(30 * 24 * 3600); // 30 days 621 622 String absPrefix = _prefixHandler.getAbsoluteUriPrefix(); 623 624 String host = null; 625 626 try 627 { 628 URI frontUri = new URI(absPrefix); 629 host = frontUri.getHost(); 630 String path = frontUri.getPath(); 631 cookie.setPath(StringUtils.isEmpty(path) ? "/" : path); 632 } 633 catch (URISyntaxException e) 634 { 635 getLogger().warn("The front URI seems to be invalid.", e); 636 } 637 638 if (StringUtils.isNotEmpty(host)) 639 { 640 cookie.setDomain(host); 641 response.addCookie(cookie); 642 } 643 } 644 645 /** 646 * Get a forwarded client IP address if available. 647 * @param request The servlet request object. 648 * @return The HTTP <code>X-Forwarded-For</code> header value if present, 649 * or the default remote address if not. 650 */ 651 protected final String getClientIp(final Request request) 652 { 653 String ip = ""; 654 655 String forwardedIpHeader = request.getHeader("X-Forwarded-For"); 656 657 if (StringUtils.isNotEmpty(forwardedIpHeader)) 658 { 659 String[] forwardedIps = forwardedIpHeader.split("[\\s,]+"); 660 String forwardedIp = forwardedIps[forwardedIps.length - 1]; 661 if (StringUtils.isNotBlank(forwardedIp)) 662 { 663 ip = forwardedIp.trim(); 664 } 665 } 666 667 if (StringUtils.isBlank(ip)) 668 { 669 ip = request.getRemoteAddr(); 670 } 671 672 return ip; 673 } 674 675 /** 676 * Survey session with answers. 677 */ 678 public class SurveyInput extends SurveySession 679 { 680 /** Answers. */ 681 protected List<SurveyInputAnswer> _inputAnswers; 682 683 @Override 684 public List<SurveyInputAnswer> getAnswers() 685 { 686 return _inputAnswers; 687 } 688 689 /** 690 * Get the answers as a Map indexed by question ID. 691 * @return the answer Map. 692 */ 693 public Map<String, SurveyInputAnswer> getAnswerMap() 694 { 695 Map<String, SurveyInputAnswer> answerMap = new LinkedHashMap<>(); 696 697 for (SurveyInputAnswer answer : _inputAnswers) 698 { 699 answerMap.put(answer.getQuestionId(), answer); 700 } 701 702 return answerMap; 703 } 704 705 /** 706 * Set the answers. 707 * @param answers the answers to set 708 */ 709 public void setAnswerList(List<SurveyInputAnswer> answers) 710 { 711 this._inputAnswers = answers; 712 } 713 } 714 715 /** 716 * Class representing a survey answer, i.e. the response of a user to a question of the survey. 717 */ 718 public class SurveyInputAnswer extends SurveyAnswer 719 { 720 721 /** The question. */ 722 protected SurveyQuestion _question; 723 724 /** The answer values. */ 725 protected Map<String, Set<String>> _values; 726 727 /** 728 * Build a SurveyAnswer object. 729 */ 730 public SurveyInputAnswer() 731 { 732 this(null, null); 733 } 734 735 /** 736 * Build a SurveyAnswer object. 737 * @param question the question ID. 738 * @param values the answer value. 739 */ 740 public SurveyInputAnswer(SurveyQuestion question, Map<String, Set<String>> values) 741 { 742 this._question = question; 743 this._values = values; 744 } 745 746 /** 747 * Get the question. 748 * @return the question 749 */ 750 public SurveyQuestion getQuestion() 751 { 752 return _question; 753 } 754 755 /** 756 * Set the question. 757 * @param question the question to set 758 */ 759 public void setQuestion(SurveyQuestion question) 760 { 761 this._question = question; 762 } 763 764 @Override 765 public String getQuestionId() 766 { 767 return _question.getName(); 768 } 769 770 @Override 771 public void setQuestionId(String questionId) 772 { 773 throw new IllegalAccessError("Set the question instead of the question ID."); 774 } 775 776 /** 777 * Get the values. 778 * @return the values 779 */ 780 public Map<String, Set<String>> getValuesMap() 781 { 782 return _values; 783 } 784 785 /** 786 * Set the values. 787 * @param values the values to set 788 */ 789 public void setValueMap(Map<String, Set<String>> values) 790 { 791 this._values = values; 792 } 793 794 @Override 795 public String getValue() 796 { 797 String value = ""; 798 799 switch (_question.getType()) 800 { 801 case SINGLE_MATRIX: 802 case MULTIPLE_MATRIX: 803 StringBuilder valueBuff = new StringBuilder(); 804 805 for (String option : _values.keySet()) 806 { 807 Set<String> values = _values.get(option); 808 809 if (valueBuff.length() > 0) 810 { 811 valueBuff.append(";"); 812 } 813 valueBuff.append(option).append(":").append(StringUtils.join(values, ",")); 814 } 815 816 value = valueBuff.toString(); 817 break; 818 case FREE_TEXT: 819 case MULTILINE_FREE_TEXT: 820 case SINGLE_CHOICE: 821 case MULTIPLE_CHOICE: 822 default: 823 value = StringUtils.defaultString(StringUtils.join(_values.get("values"), ",")); 824 break; 825 } 826 827 return value; 828 } 829 830 @Override 831 public void setValue(String value) 832 { 833 throw new IllegalAccessError("Set the value map instead of the vlaue."); 834 } 835 836 } 837 838}