/* 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 org.riotfamily.forms; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.riotfamily.common.util.DocumentWriter; import org.riotfamily.common.util.Generics; import org.springframework.beans.InvalidPropertyException; import org.springframework.util.StringUtils; import org.springframework.validation.AbstractErrors; import org.springframework.validation.Errors; import org.springframework.validation.FieldError; import org.springframework.validation.MessageCodesResolver; import org.springframework.validation.ObjectError; public class FormErrors extends AbstractErrors { private static final String GENERAL_FORM_ERROR_MESSAGE_KEY = "error.form.hasErrors"; private static final String GENERAL_FORM_ERROR_DEFAULT_MESSAGE = "Please correct the error(s) below."; private Form form; private List<ObjectError> errors = Generics.newLinkedList(); private MessageCodesResolver messageCodesResolver; public FormErrors(Form form) { this.form = form; this.messageCodesResolver = form.getFormContext().getMessageResolver() .getMessageCodesResolver(); } public Form getForm() { return form; } /** * Resolve the given error code into message codes. * Calls the MessageCodesResolver with appropriate parameters. * @param errorCode the error code to resolve into message codes * @return the resolved message codes * @see #setMessageCodesResolver */ private String[] resolveMessageCodes(String errorCode) { return messageCodesResolver.resolveMessageCodes(errorCode, getObjectName()); } private String[] resolveMessageCodes(String errorCode, String field) { String fixedField = fixedField(field); Class<?> fieldType = getFieldType(fixedField); return messageCodesResolver.resolveMessageCodes(errorCode, getObjectName(), fixedField, fieldType); } public void renderErrors(Element element) { List<String> errors = getErrors(element); if (errors != null) { PrintWriter writer = element.getForm().getFormContext().getWriter(); DocumentWriter tag = new DocumentWriter(writer); tag.start("ul") .attribute("id", element.getId() + "-error") .attribute("class", "errors"); for (String error : errors) { tag.start("li").body(error).end(); } tag.end(); } } public void renderGlobalErrors() { List<String> errors = getErrors(null); if (errors != null) { PrintWriter writer = form.getFormContext().getWriter(); DocumentWriter tag = new DocumentWriter(writer); tag.start("ul") .attribute("class", "errors"); for (String error : errors) { tag.start("li").body(error).end(); } tag.end(); } } public List<String> getErrors(Element element) { if (element == null) { return getErrorMessages(getGlobalErrors()); } else if (element instanceof Editor) { Editor editor = (Editor) element; List<FieldError> fieldErrors = getFieldErrors(editor.getFieldName()); return getErrorMessages(fieldErrors); } return null; } private List<String> getErrorMessages(List<? extends ObjectError> errors) { ArrayList<String> messages = Generics.newArrayList(); for (ObjectError error : errors) { String message = form.getFormContext().getMessageResolver().getMessage(error); if (!StringUtils.hasLength(message)) { message = StringUtils.arrayToCommaDelimitedString(error.getCodes()); } messages.add(message); } return messages; } public void removeError(ObjectError error) { errors.remove(error); } public void removeErrors(Element element) { if (element instanceof Editor) { Editor editor = (Editor) element; errors.removeAll(getFieldErrors(editor.getFieldName())); } } public void removeAllErrors() { errors.clear(); } public String getGeneralFormError() { return form.getFormContext().getMessageResolver().getMessage( GENERAL_FORM_ERROR_MESSAGE_KEY, null, GENERAL_FORM_ERROR_DEFAULT_MESSAGE); } public boolean hasErrors(Element element) { if (!(element instanceof Editor)) { return false; } Editor editor = (Editor) element; return hasFieldErrors(editor.getFieldName()); } public void addError(ObjectError error) { errors.add(error); } // ----------------------------------------------------------------------- // Implementation of the Errors interface // ----------------------------------------------------------------------- public Object getFieldValue(String field) { try { return form.getEditor(field).getValue(); } catch (InvalidPropertyException e) { return null; } } public void addAllErrors(Errors errors) { this.errors.addAll(errors.getAllErrors()); } public List<FieldError> getFieldErrors() { List<FieldError> result = Generics.newLinkedList(); for (ObjectError error : errors) { if (error instanceof FieldError) { result.add((FieldError) error); } } return Collections.unmodifiableList(result); } public List<ObjectError> getGlobalErrors() { List<ObjectError> result = Generics.newLinkedList(); for (ObjectError error : errors) { if (!(error instanceof FieldError)) { result.add(error); } } return Collections.unmodifiableList(result); } public String getObjectName() { return form.getId(); } public void reject(String errorCode, Object[] args, String defaultMessage) { addError(new ObjectError(getObjectName(), resolveMessageCodes(errorCode), args, defaultMessage)); } public void rejectValue(String field, String errorCode, Object[] args, String defaultMessage) { if ("".equals(getNestedPath()) && !StringUtils.hasLength(field)) { // We're at the top of the nested object hierarchy, // so the present level is not a field but rather the top object. // The best we can do is register a global error here... reject(errorCode, args, defaultMessage); return; } String fixedField = fixedField(field); Object newVal = getFieldValue(fixedField); FieldError fe = new FieldError( getObjectName(), fixedField, newVal, false, resolveMessageCodes(errorCode, field), args, defaultMessage); addError(fe); } }