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