/**
* Copyright 2010-2016 Ralph Schaer <ralphschaer@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.ralscha.extdirectspring.bean;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.springframework.context.MessageSource;
import org.springframework.util.Assert;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
/**
* Represents the result of a FORM_POST method call.
*/
public class ExtDirectFormPostResult {
private static final String ERRORS_PROPERTY = "errors";
private static final String SUCCESS_PROPERTY = "success";
private final Map<String, Object> result = new HashMap<String, Object>();
public ExtDirectFormPostResult() {
setSuccess(true);
}
public ExtDirectFormPostResult(boolean success) {
setSuccess(success);
}
public ExtDirectFormPostResult(BindingResult bindingResult) {
addErrors(null, null, bindingResult);
}
public ExtDirectFormPostResult(BindingResult bindingResult, boolean success) {
addErrors(null, null, bindingResult);
setSuccess(success);
}
public ExtDirectFormPostResult(Locale locale, MessageSource messageSource,
BindingResult bindingResult) {
addErrors(locale, messageSource, bindingResult);
}
public ExtDirectFormPostResult(Locale locale, MessageSource messageSource,
BindingResult bindingResult, boolean success) {
addErrors(locale, messageSource, bindingResult);
setSuccess(success);
}
/**
* Extracts errors from the bindingResult and inserts them into the error properties.
* Sets the property success to false if there are errors. Sets the property success
* to true if there are no errors.
*
* @param locale
* @param messageSource
* @param bindingResult
*/
private void addErrors(Locale locale, MessageSource messageSource,
BindingResult bindingResult) {
if (bindingResult != null && bindingResult.hasFieldErrors()) {
Map<String, List<String>> errorMap = new HashMap<String, List<String>>();
for (FieldError fieldError : bindingResult.getFieldErrors()) {
String message = fieldError.getDefaultMessage();
if (messageSource != null) {
Locale loc = locale != null ? locale : Locale.getDefault();
message = messageSource.getMessage(fieldError.getCode(),
fieldError.getArguments(), loc);
}
List<String> fieldErrors = errorMap.get(fieldError.getField());
if (fieldErrors == null) {
fieldErrors = new ArrayList<String>();
errorMap.put(fieldError.getField(), fieldErrors);
}
fieldErrors.add(message);
}
if (errorMap.isEmpty()) {
addResultProperty(SUCCESS_PROPERTY, Boolean.TRUE);
}
else {
addResultProperty(ERRORS_PROPERTY, errorMap);
addResultProperty(SUCCESS_PROPERTY, Boolean.FALSE);
}
}
else {
setSuccess(true);
}
}
/**
* resolve the messages codes along the implementation described in
* {@link org.springframework.validation.DefaultMessageCodesResolver}<br>
* stop at first message found<br>
* method is useless if no specific validation message have been set (example:
* javax.validation.constraints.NotNull.message.fax=Fax number is mandatory)<br>
* it will behave {@link #addErrors(Locale, MessageSource, BindingResult)} with a big
* overhead
*
* @param locale locale for internationalization
* @param messageSource source of validation code and message
* @param bindingResult Errors list to resolve
* @return this {@link #ExtDirectFormPostResult} for easy chaining
*/
public ExtDirectFormPostResult addErrorsResolveCode(Locale locale,
MessageSource messageSource, BindingResult bindingResult) {
if (bindingResult != null && bindingResult.hasFieldErrors()) {
Map<String, List<String>> errorMap = new HashMap<String, List<String>>();
for (FieldError fieldError : bindingResult.getFieldErrors()) {
String message = fieldError.getDefaultMessage();
if (messageSource != null) {
Locale loc = locale != null ? locale : Locale.getDefault();
for (String code : fieldError.getCodes()) {
try {
message = messageSource.getMessage(code,
fieldError.getArguments(), loc);
}
catch (Exception e) {
/**
* expected if code/message doesn't exist, default behavior to
* counter that, set to your message bundle,
* {@link org.springframework.context.support.AbstractMessageSource#setUseCodeAsDefaultMessage(true)}
* beware of side effects
*/
}
if (message != null && !message.equals(code)) {
break;
}
}
}
List<String> fieldErrors = errorMap.get(fieldError.getField());
if (fieldErrors == null) {
fieldErrors = new ArrayList<String>();
errorMap.put(fieldError.getField(), fieldErrors);
}
fieldErrors.add(message);
}
if (errorMap.isEmpty()) {
addResultProperty(SUCCESS_PROPERTY, Boolean.TRUE);
}
else {
addResultProperty(ERRORS_PROPERTY, errorMap);
addResultProperty(SUCCESS_PROPERTY, Boolean.FALSE);
}
}
else {
setSuccess(true);
}
return this;
}
/**
* Adds one error message to a specific field. Does not overwrite already existing
* errors.
*
* @param field the name of the field
* @param error the error message
*/
public void addError(String field, String error) {
Assert.notNull(field, "field must not be null");
Assert.notNull(error, "field must not be null");
addErrors(field, Collections.singletonList(error));
addResultProperty(SUCCESS_PROPERTY, Boolean.FALSE);
}
/**
* Adds multiple error messages to a specific field. Does not overwrite already
* existing errors.
*
* @param field the name of the field
* @param errors a collection of error messages
*/
@SuppressWarnings("unchecked")
public void addErrors(String field, List<String> errors) {
Assert.notNull(field, "field must not be null");
Assert.notNull(errors, "field must not be null");
// do not overwrite existing errors
Map<String, List<String>> errorMap = (Map<String, List<String>>) this.result
.get(ERRORS_PROPERTY);
if (errorMap == null) {
errorMap = new HashMap<String, List<String>>();
addResultProperty(ERRORS_PROPERTY, errorMap);
}
List<String> fieldErrors = errorMap.get(field);
if (fieldErrors == null) {
fieldErrors = new ArrayList<String>();
errorMap.put(field, fieldErrors);
}
fieldErrors.addAll(errors);
addResultProperty(SUCCESS_PROPERTY, Boolean.FALSE);
}
public void addResultProperty(String key, Object value) {
this.result.put(key, value);
}
public Map<String, Object> getResult() {
return this.result;
}
public void setSuccess(boolean flag) {
this.result.put(SUCCESS_PROPERTY, flag);
}
}