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