001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.bean.validation;
018
019import java.util.ArrayList;
020import java.util.List;
021
022import javax.validation.ConstraintViolation;
023import javax.validation.metadata.ConstraintDescriptor;
024
025import org.apache.wicket.util.string.Strings;
026import org.apache.wicket.validation.ValidationError;
027
028/**
029 * A default implementation of {@link IViolationTranslator}. The validation error is created with
030 * the constraint violation's default error message. Further, the violation is checked for a message
031 * key and if is found it is also added as a message key to the validation error. The keys are only
032 * used if they are in the bean validation's default format of '{key}'.
033 * 
034 * @author igor
035 */
036public class DefaultViolationTranslator implements IViolationTranslator
037{
038        @Override
039        public <T> ValidationError convert(ConstraintViolation<T> violation)
040        {
041                ConstraintDescriptor<?> desc = violation.getConstraintDescriptor();
042
043                ValidationError error = new ValidationError();
044                error.setMessage(violation.getMessage());
045
046                List<String> messages = getViolationMessages(violation, desc);
047                addErrorKeys(error, violation.getInvalidValue(), messages);
048
049                for (String key : desc.getAttributes().keySet())
050                {
051                        error.setVariable(key, desc.getAttributes().get(key));
052                }
053                
054                return error;
055        }
056
057        private List<String> getViolationMessages(ConstraintViolation<?> violation,
058                ConstraintDescriptor<?> desc)
059        {
060                String defaultMessage = (String)desc.getAttributes().get("message");
061                String violationMessage = violation.getMessage();
062                String violationMessageTemplate = violation.getMessageTemplate();               
063                List<String> messages = new ArrayList<String>();
064
065                //violation message is considered only if it is different from
066                //the interpolated message
067                if (!Strings.isEqual(violationMessage, violationMessageTemplate))
068                {
069                        messages.add(violationMessageTemplate);
070                }
071                
072                messages.add(violationMessage);
073                
074                //the default message is considered only if it is different from
075                //the violation message template
076                if (!Strings.isEqual(defaultMessage, violationMessageTemplate))
077                {
078                        messages.add(defaultMessage);
079                }
080
081                return messages;
082        }
083
084        private void addErrorKeys(ValidationError error, Object invalidValue, List<String> messages)
085        {
086                for (String message : messages)
087                {
088                        String messageKey = getMessageKey(message);
089
090                        if (messageKey != null)
091                        {
092                                if (invalidValue != null)
093                                {
094                                        error.addKey(messageKey + "." + invalidValue.getClass().getSimpleName());
095                                }
096
097                                error.addKey(messageKey);
098                        }
099                }
100        }
101
102        private String getMessageKey(String message)
103        {
104                if (!Strings.isEmpty(message) && message.startsWith("{") && message.endsWith("}"))
105                {
106                        return message.substring(1, message.length() - 1);
107                }
108        
109                return null;
110        }
111}