/*
 * Copyright (c) 2010-2014. Axon Framework
 *
 * 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.axonframework.messaging.interceptors;

import org.axonframework.common.AxonNonTransientException;
import org.springframework.util.StringUtils;

import java.util.Set;
import java.util.TreeSet;
import javax.validation.ConstraintViolation;

/**
 * Exception indicating that a Message has been refused due to a structural validation failure. Typically, resending
 * the same message will result in the exact same exception.
 * <p/>
 * Provides a set of JSR303 constraint violations that provide details about the exact failure of the message.
 *
 * @author Allard Buijze
 * @since 1.1
 */
public class JSR303ViolationException extends AxonNonTransientException {

    private static final long serialVersionUID = -1585918243998401966L;
    private final Set<ConstraintViolation<Object>> violations;

    /**
     * Initializes an exception with the given {@code message} and {@code violations}.
     *
     * @param violations The violations that were detected
     */
    public JSR303ViolationException(Set<ConstraintViolation<Object>> violations) {
        super("One or more JSR303 constraints were violated: " + System.lineSeparator()
            + StringUtils.collectionToDelimitedString(convert(violations), System.lineSeparator()));
        this.violations = violations;
    }

    /**
     * Returns the violations that were detected when this exception was thrown.
     *
     * @return the violations that were detected when this exception was thrown
     */
    public Set<ConstraintViolation<Object>> getViolations() {
        return violations;
    }

    /**
     * Convert the violations to a human readable format, sorted by class and property e.g.
     * <pre>
     *   property ab in class my.some.Klass may not be null
     *   property cd in class my.some.OtherClass length must be between 0 and 3
     *   property cd in class my.some.OtherClass must match "ab.*"
     *
     * </pre>
     * <pre>property notNull in class my.some.TheClass may not be null</pre>
     */
    protected static Set<String> convert(Set<ConstraintViolation<Object>> violations) {
        // sort the violations on bean class and property name
        Set<String> sortedViolations = new TreeSet<>();
        for (ConstraintViolation<Object> violation : violations) {
            String msg = "property " + violation.getPropertyPath();
            msg += " in " + violation.getRootBeanClass();
            msg += " " + violation.getMessage();
            sortedViolations.add(msg);
        }
        return sortedViolations;
    }
}

@@ -716,53 +716,35 @@
 on;%0A
+%0A
 import 
-org.springframework.util.StringUtils;%0A
+java.util.Iterator;
 %0Aimp
@@ -1750,91 +1750,26 @@
   + 
-StringUtils.collectionToDelimitedString(convert(violations), System.lineSeparator()
+convert(violations
 ));%0A
@@ -2540,27 +2540,22 @@
  static 
-Set%3C
 String
-%3E
  convert
@@ -3024,31 +3024,305 @@
     
-return sortedViolations
+StringBuffer sb = new StringBuffer();%0A        Iterator%3CString%3E it = sortedViolations.iterator();%0A        while (it.hasNext()) %7B%0A            sb.append(it.next());%0A            if (it.hasNext()) %7B%0A                sb.append(System.lineSeparator());%0A            %7D%0A        %7D%0A        return sb.toString()
 ;%0A  

improve exception message in case of jsr303 validation, this time without Spring