You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bval.apache.org by rm...@apache.org on 2013/08/26 15:59:20 UTC

svn commit: r1517540 [7/15] - in /bval/branches/bval-11/bval-jsr: ./ src/ src/main/ src/main/appended-resources/ src/main/appended-resources/META-INF/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/bval/ src/main/j...

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultConstraintValidatorFactory.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultConstraintValidatorFactory.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultConstraintValidatorFactory.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultConstraintValidatorFactory.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr;
+
+import org.apache.bval.cdi.BValExtension;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorFactory;
+import javax.validation.ValidationException;
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+
+/**
+ * Description: create constraint instances with the default / no-arg constructor <br/>
+ */
+public class DefaultConstraintValidatorFactory implements ConstraintValidatorFactory, Closeable {
+    private final Collection< BValExtension.Releasable<?>> releasables = new CopyOnWriteArrayList<BValExtension.Releasable<?>>();
+    private Boolean useCdi = null; // store it to avoid NoClassDefFoundError when cdi is not present (it is slow) + lazily (to wait cdi is started)
+
+    /**
+     * Instantiate a Constraint.
+     *
+     * @return Returns a new Constraint instance
+     *         The ConstraintFactory is <b>not</b> responsible for calling Constraint#initialize
+     */
+    public <T extends ConstraintValidator<?, ?>> T getInstance(final Class<T> constraintClass) {
+        if (useCdi == null) {
+            synchronized (this) {
+                if (useCdi == null) {
+                    try {
+                        useCdi = BValExtension.getInstance() != null && BValExtension.getInstance().getBeanManager() != null;
+                    } catch (final NoClassDefFoundError error) {
+                        useCdi = false;
+                    } catch (final Exception e) {
+                        useCdi = false;
+                    }
+                }
+            }
+        }
+
+        // 2011-03-27 jw: Do not use PrivilegedAction.
+        // Otherwise any user code would be executed with the privileges of this class.
+        try {
+            if (useCdi) {
+                try {
+                    final BValExtension.Releasable<T> instance = BValExtension.inject(constraintClass);
+                    releasables.add(instance);
+                    return instance.getInstance();
+                } catch (final Exception e) {
+                    return constraintClass.newInstance();
+                } catch (final NoClassDefFoundError error) {
+                    return constraintClass.newInstance();
+                }
+            }
+            return constraintClass.newInstance();
+        } catch (final Exception ex) {
+            throw new ValidationException("Cannot instantiate : " + constraintClass, ex);
+        }
+    }
+
+    public void releaseInstance(final ConstraintValidator<?, ?> instance) {
+        // no-op
+    }
+
+    public void close() throws IOException {
+        for (final BValExtension.Releasable<?> releasable : releasables) {
+            // ensure to call this callback
+            releaseInstance(ConstraintValidator.class.cast(releasable.getInstance()));
+            releasable.release();
+        }
+        releasables.clear();
+    }
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultMessageInterpolator.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultMessageInterpolator.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultMessageInterpolator.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultMessageInterpolator.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,306 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you 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.apache.bval.jsr;
+
+import org.apache.bval.el.MessageEvaluator;
+import org.apache.bval.util.reflection.Reflection;
+import org.apache.commons.lang3.ArrayUtils;
+
+import javax.validation.MessageInterpolator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Description: Resource bundle backed message interpolator.
+ * This message resolver resolve message descriptors
+ * into human-readable messages. It uses ResourceBundles to find the messages.
+ * This class is threadsafe.<br/>
+ */
+public class DefaultMessageInterpolator implements MessageInterpolator {
+    private static final Logger log = Logger.getLogger(DefaultMessageInterpolator.class.getName());
+    private static final boolean LOG_FINEST = log.isLoggable(Level.FINEST);
+    private static final String DEFAULT_VALIDATION_MESSAGES = "org.apache.bval.jsr.ValidationMessages";
+    private static final String USER_VALIDATION_MESSAGES = "ValidationMessages";
+
+    /** Regular expression used to do message interpolation. */
+    private static final Pattern messageParameterPattern = Pattern.compile("(\\{[\\w\\.]+\\})");
+
+    /** The default locale for the current user. */
+    private Locale defaultLocale;
+
+    /** User specified resource bundles hashed against their locale. */
+    private final Map<Locale, ResourceBundle> userBundlesMap =
+          new ConcurrentHashMap<Locale, ResourceBundle>();
+
+    /** Builtin resource bundles hashed against their locale. */
+    private final Map<Locale, ResourceBundle> defaultBundlesMap = new ConcurrentHashMap<Locale, ResourceBundle>();
+
+    private final MessageEvaluator evaluator;
+
+    /**
+     * Create a new DefaultMessageInterpolator instance.
+     */
+    public DefaultMessageInterpolator() {
+        this(null);
+    }
+
+    /**
+     * Create a new DefaultMessageInterpolator instance.
+     * @param resourceBundle
+     */
+    public DefaultMessageInterpolator(ResourceBundle resourceBundle) {
+        defaultLocale = Locale.getDefault();
+
+        // feed the cache with defaults at least
+        findDefaultResourceBundle(defaultLocale);
+        if (resourceBundle == null) {
+            findUserResourceBundle(defaultLocale);
+        } else {
+            userBundlesMap.put(defaultLocale, resourceBundle);
+        }
+
+        MessageEvaluator ev = null;
+        try {
+            ev = MessageEvaluator.class.cast(getClass().getClassLoader().loadClass("org.apache.bval.el.ELFacade").newInstance());
+        } catch (final Throwable e) { // can be exception or error
+            // no-op
+        }
+        evaluator = ev;
+    }
+
+    /** {@inheritDoc} */
+    public String interpolate(String message, Context context) {
+        // probably no need for caching, but it could be done by parameters since the map
+        // is immutable and uniquely built per Validation definition, the comparison has to be based on == and not equals though
+        return interpolate(message, context, defaultLocale);
+    }
+
+    /** {@inheritDoc} */
+    public String interpolate(String message, Context context, Locale locale) {
+        return interpolateMessage(message,
+                context.getConstraintDescriptor().getAttributes(), locale, context.getValidatedValue());
+    }
+
+    /**
+     * Runs the message interpolation according to algorithm specified in JSR 303.
+     * <br/>
+     * Note:
+     * <br/>
+     * Lookups in user bundles are recursive whereas lookups in default bundle are not!
+     *
+     * @param message              the message to interpolate
+     * @param annotationParameters the parameters of the annotation for which to interpolate this message
+     * @param locale               the <code>Locale</code> to use for the resource bundle.
+     * @return the interpolated message.
+     */
+    private String interpolateMessage(String message,
+                                      Map<String, Object> annotationParameters,
+                                      Locale locale, Object validatedValue) {
+        ResourceBundle userResourceBundle = findUserResourceBundle(locale);
+        ResourceBundle defaultResourceBundle = findDefaultResourceBundle(locale);
+
+        String userBundleResolvedMessage;
+        String resolvedMessage = message;
+        boolean evaluatedDefaultBundleOnce = false;
+        do {
+            // search the user bundle recursive (step1)
+            userBundleResolvedMessage =
+                  replaceVariables(resolvedMessage, userResourceBundle, locale, true);
+
+            // exit condition - we have at least tried to validate against the default bundle and there were no
+            // further replacements
+            if (evaluatedDefaultBundleOnce &&
+                  !hasReplacementTakenPlace(userBundleResolvedMessage, resolvedMessage)) {
+                break;
+            }
+
+            // search the default bundle non recursive (step2)
+            resolvedMessage = replaceVariables(userBundleResolvedMessage,
+                  defaultResourceBundle, locale, false);
+
+            evaluatedDefaultBundleOnce = true;
+        } while (true);
+
+        // resolve annotation attributes (step 4)
+        resolvedMessage = replaceAnnotationAttributes(resolvedMessage, annotationParameters);
+
+        // EL handling
+        if (evaluator != null) {
+            resolvedMessage = evaluator.interpolate(resolvedMessage, annotationParameters, validatedValue);
+        }
+
+        // curly braces need to be scaped in the original msg, so unescape them now
+        resolvedMessage = resolvedMessage.replace( "\\{", "{" ).replace( "\\}", "}" ).replace( "\\\\", "\\" ).replace( "\\$", "$" );
+
+        return resolvedMessage;
+    }
+
+    private boolean hasReplacementTakenPlace(String origMessage, String newMessage) {
+        return !origMessage.equals(newMessage);
+    }
+
+    /**
+     * Search current thread classloader for the resource bundle. If not found, search validator (this) classloader.
+     *
+     * @param locale The locale of the bundle to load.
+     * @return the resource bundle or <code>null</code> if none is found.
+     */
+    private ResourceBundle getFileBasedResourceBundle(Locale locale) {
+        ResourceBundle rb = null;
+        final ClassLoader classLoader = Reflection.INSTANCE.getClassLoader(DefaultMessageInterpolator.class);
+        if (classLoader != null) {
+            rb = loadBundle(classLoader, locale,
+                  USER_VALIDATION_MESSAGES + " not found by thread local classloader");
+        }
+
+        // 2011-03-27 jw: No privileged action required.
+        // A class can always access the classloader of itself and of subclasses.
+        if (rb == null) {
+            rb = loadBundle(getClass().getClassLoader(), locale, USER_VALIDATION_MESSAGES + " not found by validator classloader");
+        }
+        if (LOG_FINEST) {
+            if (rb != null) {
+                log.log(Level.FINEST, String.format("%s found", USER_VALIDATION_MESSAGES));
+            } else {
+                log.log(Level.FINEST, String.format("%s not found. Delegating to %s", USER_VALIDATION_MESSAGES, DEFAULT_VALIDATION_MESSAGES));
+            }
+        }
+        return rb;
+    }
+
+    private ResourceBundle loadBundle(ClassLoader classLoader, Locale locale,
+                                      String message) {
+        ResourceBundle rb = null;
+        try {
+            rb = ResourceBundle.getBundle(USER_VALIDATION_MESSAGES, locale, classLoader);
+        } catch (final MissingResourceException e) {
+            log.fine(message);
+        }
+        return rb;
+    }
+
+    private String replaceVariables(String message, ResourceBundle bundle, Locale locale,
+                                    boolean recurse) {
+        final Matcher matcher = messageParameterPattern.matcher(message);
+        final StringBuffer sb = new StringBuffer(64);
+        String resolvedParameterValue;
+        while (matcher.find()) {
+            final String parameter = matcher.group(1);
+            resolvedParameterValue = resolveParameter(parameter, bundle, locale, recurse);
+
+            matcher.appendReplacement(sb, sanitizeForAppendReplacement(resolvedParameterValue));
+        }
+        matcher.appendTail(sb);
+        return sb.toString();
+    }
+
+    private String replaceAnnotationAttributes(final String message,
+                                               final Map<String, Object> annotationParameters) {
+        Matcher matcher = messageParameterPattern.matcher(message);
+        StringBuffer sb = new StringBuffer(64);
+        while (matcher.find()) {
+            String resolvedParameterValue;
+            String parameter = matcher.group(1);
+            Object variable = annotationParameters.get(removeCurlyBrace(parameter));
+            if (variable != null) {
+                if (variable.getClass().isArray()) {
+                    resolvedParameterValue = ArrayUtils.toString(variable);
+                } else {
+                    resolvedParameterValue = variable.toString();
+                }
+            } else {
+                resolvedParameterValue = parameter;
+            }
+            matcher.appendReplacement(sb, sanitizeForAppendReplacement(resolvedParameterValue));
+        }
+        matcher.appendTail(sb);
+        return sb.toString();
+    }
+
+    private String resolveParameter(String parameterName, ResourceBundle bundle,
+                                    Locale locale, boolean recurse) {
+        String parameterValue;
+        try {
+            if (bundle != null) {
+                parameterValue = bundle.getString(removeCurlyBrace(parameterName));
+                if (recurse) {
+                    parameterValue = replaceVariables(parameterValue, bundle, locale, recurse);
+                }
+            } else {
+                parameterValue = parameterName;
+            }
+        } catch (final MissingResourceException e) {
+            // return parameter itself
+            parameterValue = parameterName;
+        }
+
+        return parameterValue;
+    }
+
+    private String removeCurlyBrace(String parameter) {
+        return parameter.substring(1, parameter.length() - 1);
+    }
+
+    private ResourceBundle findDefaultResourceBundle(Locale locale) {
+        ResourceBundle bundle = defaultBundlesMap.get(locale);
+        if (bundle == null)
+        {
+            bundle = ResourceBundle.getBundle(DEFAULT_VALIDATION_MESSAGES, locale);
+            defaultBundlesMap.put(locale, bundle);
+        }
+        return bundle;
+    }
+
+    private ResourceBundle findUserResourceBundle(Locale locale) {
+        ResourceBundle bundle = userBundlesMap.get(locale);
+        if (bundle == null)
+        {
+            bundle = getFileBasedResourceBundle(locale);
+            if (bundle != null) {
+                userBundlesMap.put(locale, bundle);
+            }
+        }
+        return bundle;
+    }
+
+    /**
+     * Set the default locale used by this {@link DefaultMessageInterpolator}.
+     * @param locale
+     */
+    public void setLocale(Locale locale) {
+        defaultLocale = locale;
+    }
+
+    /**
+     * Escapes the string to comply with
+     * {@link Matcher#appendReplacement(StringBuffer, String)} requirements.
+     *
+     * @param src
+     *            The original string.
+     * @return The sanitized string.
+     */
+    private String sanitizeForAppendReplacement(String src) {
+        return src.replace("\\", "\\\\").replace("$", "\\$");
+    }
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultValidationProviderResolver.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultValidationProviderResolver.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultValidationProviderResolver.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/DefaultValidationProviderResolver.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you 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.apache.bval.jsr;
+
+
+import javax.validation.ValidationException;
+import javax.validation.ValidationProviderResolver;
+import javax.validation.spi.ValidationProvider;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+public class DefaultValidationProviderResolver implements ValidationProviderResolver {
+
+    //TODO - Spec recommends caching per classloader
+    private static final String SPI_CFG =
+        "META-INF/services/javax.validation.spi.ValidationProvider";
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<ValidationProvider<?>> getValidationProviders() {
+        List<ValidationProvider<?>> providers = new ArrayList<ValidationProvider<?>>();
+        try {
+            // get our classloader
+            ClassLoader cl = Thread.currentThread().getContextClassLoader();
+            if (cl == null)
+                cl = DefaultValidationProviderResolver.class.getClassLoader();
+            // find all service provider cfgs
+            Enumeration<URL> cfgs = cl.getResources(SPI_CFG);
+            while (cfgs.hasMoreElements()) {
+                URL url = cfgs.nextElement();
+                BufferedReader br = null;
+                try {
+                    br = new BufferedReader(new InputStreamReader(url.openStream()), 256);
+                    String line = br.readLine();
+                    // cfgs may contain multiple providers and/or comments
+                    while (line != null) {
+                        line = line.trim();
+                        if (!line.startsWith("#")) {
+                            try {
+                                // try loading the specified class
+                                final Class<?> provider = cl.loadClass(line);
+                                // create an instance to return
+                                final ValidationProvider<?> vp;
+                                if (System.getSecurityManager() == null) {
+                                    try {
+                                        vp = (ValidationProvider<?>) provider.newInstance();
+                                    } catch (final Exception ex) {
+                                        throw new ValidationException("Cannot instantiate : " + provider, ex);
+                                    }
+                                } else {
+                                    vp = AccessController.doPrivileged(new PrivilegedAction<ValidationProvider<?>>() {
+                                        public ValidationProvider<?> run() {
+                                            try {
+                                                return (ValidationProvider<?>) provider.newInstance();
+                                            } catch (final Exception ex) {
+                                                throw new ValidationException("Cannot instantiate : " + provider, ex);
+                                            }
+                                        }
+                                    });
+                                }
+                                providers.add(vp);
+
+                            } catch (ClassNotFoundException e) {
+                                throw new ValidationException("Failed to load provider " +
+                                    line + " configured in file " + url, e);
+                            }
+                        }
+                        line = br.readLine();
+                    }
+                    br.close();
+                } catch (IOException e) {
+                    throw new ValidationException("Error trying to read " + url, e);
+                } finally {
+                    if (br != null)
+                        br.close();
+                }
+            }
+        } catch (IOException e) {
+            throw new ValidationException("Error trying to read a " + SPI_CFG, e);
+        }
+        // caller must handle the case of no providers found
+        return providers;
+    }
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/ElementDescriptorImpl.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/ElementDescriptorImpl.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/ElementDescriptorImpl.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/ElementDescriptorImpl.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you 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.apache.bval.jsr;
+
+import org.apache.bval.jsr.groups.Group;
+import org.apache.bval.model.MetaBean;
+import org.apache.bval.model.Validation;
+
+import javax.validation.ConstraintDeclarationException;
+import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.ElementDescriptor;
+import javax.validation.metadata.GroupConversionDescriptor;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+/**
+ * Description: MetaData class<br/>
+ */
+public abstract class ElementDescriptorImpl implements ElementDescriptor {
+    private final Set<GroupConversionDescriptor> groupConversions = new CopyOnWriteArraySet<GroupConversionDescriptor>();
+    private boolean cascaded;
+    private final Collection<Object> validated = new CopyOnWriteArraySet<Object>();
+
+    /**
+     * Get a set of {@link ConstraintDescriptor}s from the specified array of
+     * {@link Validation}s.
+     * 
+     * @param validations
+     * @return {@link ConstraintDescriptor} set
+     */
+    protected static Set<ConstraintDescriptor<?>> getConstraintDescriptors(final Validation[] validations) {
+        final Set<ConstraintDescriptor<?>> result = new HashSet<ConstraintDescriptor<?>>(validations.length);
+        for (Validation validation : validations) {
+            if (validation instanceof ConstraintValidation<?>) {
+                result.add((ConstraintValidation<?>) validation);
+            }
+        }
+        return result;
+    }
+
+    /** the MetaBean of this element */
+    protected final MetaBean metaBean;
+
+    /** the raw type of this element */
+    protected final Class<?> elementClass;
+
+    private Set<ConstraintDescriptor<?>> constraintDescriptors;
+
+    private final Map<Group, Group> groupMapping = new HashMap<Group, Group>();
+
+    /**
+     * Create a new ElementDescriptorImpl instance.
+     * 
+     * @param metaBean
+     * @param elementClass
+     * @param validations
+     */
+    protected ElementDescriptorImpl(MetaBean metaBean, Class<?> elementClass, Validation[] validations) {
+        this.metaBean = metaBean;
+        this.elementClass = elementClass;
+        setConstraintDescriptors(getConstraintDescriptors(validations));
+    }
+
+    /**
+     * Create a new ElementDescriptorImpl instance.
+     *
+     * @param elementClass
+     * @param validations
+     */
+    protected ElementDescriptorImpl(Class<?> elementClass, Validation[] validations) {
+        this(null, elementClass, validations);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @return Statically defined returned type.
+     */
+    public Class<?> getElementClass() {
+        return elementClass;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public ElementDescriptor.ConstraintFinder findConstraints() {
+        return new ConstraintFinderImpl(metaBean, new HashSet((Set) constraintDescriptors));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Set<ConstraintDescriptor<?>> getConstraintDescriptors() {
+        return constraintDescriptors.isEmpty() ? Collections.<ConstraintDescriptor<?>> emptySet() : Collections
+            .unmodifiableSet(constraintDescriptors);
+    }
+
+    /**
+     * Get the mutable {@link ConstraintDescriptor} {@link Set}.
+     * 
+     * @return Set of {@link ConstraintDescriptor}
+     */
+    public Set<ConstraintDescriptor<?>> getMutableConstraintDescriptors() {
+        return constraintDescriptors;
+    }
+
+    /**
+     * {@inheritDoc} return true if at least one constraint declaration is
+     * present on the element.
+     */
+    public boolean hasConstraints() {
+        return !getConstraintDescriptors().isEmpty();
+    }
+
+    /**
+     * Set the constraintDescriptors for this element.
+     * 
+     * @param constraintDescriptors
+     *            to set
+     */
+    public void setConstraintDescriptors(Set<ConstraintDescriptor<?>> constraintDescriptors) {
+        this.constraintDescriptors = constraintDescriptors;
+    }
+
+    /**
+     * Get the model {@link MetaBean} used.
+     * 
+     * @return MetaBean
+     */
+    public MetaBean getMetaBean() {
+        return metaBean;
+    }
+
+    public void addGroupMapping(final Group from, final Group to) {
+        groupMapping.put(from, to);
+    }
+
+    public Group mapGroup(final Group current) {
+        final Group mapping = groupMapping.get(current);
+        if (mapping != null) {
+            return mapping;
+        }
+        return current;
+    }
+
+    public Set<GroupConversionDescriptor> getGroupConversions() {
+        return groupConversions;
+    }
+
+    public void addGroupConversion(final GroupConversionDescriptor descriptor) {
+        groupConversions.add(descriptor);
+        final Group from = new Group(descriptor.getFrom());
+        if (mapGroup(from) != from) { // ref == is fine
+            throw new ConstraintDeclarationException("You can't map twice from the same group");
+        }
+        addGroupMapping(from, new Group(descriptor.getTo()));
+    }
+
+    public boolean isCascaded() {
+        return cascaded;
+    }
+
+    public void setCascaded(final boolean cascaded) {
+        this.cascaded = cascaded;
+    }
+
+    public boolean isValidated(final Object object) {
+        return validated.contains(object);
+    }
+
+    public void setValidated(final Object object) {
+        this.validated.add(object);
+    }
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/GraphBeanIdentity.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/GraphBeanIdentity.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/GraphBeanIdentity.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/GraphBeanIdentity.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr;
+
+/**
+ * Class that stores the needed properties to avoid circular paths when
+ * validating an object graph.
+ * <p>
+ * These properties are:
+ * <ul>
+ * <li>The ref of the bean to which the validation would be applied.</li>
+ * <li>The current group being validated.</li>
+ * </ul>
+ * 
+ * FIXME: Owner is currently not used in identity checking, and probably
+ * never will be.  So it is likely to be deleted.
+ * 
+ * @author Carlos Vara
+ */
+public class GraphBeanIdentity {
+    
+    private final Object bean;
+    private final Class<?> group;
+    private final Class<?> owner;
+
+    /**
+     * Create a new GraphBeanIdentity instance.
+     * @param bean
+     * @param group
+     * @param owner
+     */
+    public GraphBeanIdentity(Object bean, Class<?> group, Class<?> owner) {
+        this.bean = bean;
+        this.group = group;
+        this.owner = owner;
+    }
+    
+    /**
+     * Get the bean.
+     * @return Object
+     */
+    public Object getBean() {
+        return bean;
+    }
+
+    /**
+     * Get the group being validated.
+     * @return Class
+     */
+    public Class<?> getGroup() {
+        return group;
+    }
+
+    /**
+     * Get the owning class
+     * @return
+     */
+    public Class<?> getOwner() {
+        return owner;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object obj) {
+
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj == null) {
+            return false;
+        }
+
+        if (!(obj instanceof GraphBeanIdentity)) {
+            return false;
+        }
+
+        GraphBeanIdentity other = (GraphBeanIdentity) obj;
+
+        // Bean ref must be the same
+        if (this.bean != other.bean) {
+            return false;
+        }
+
+        // Group ref must be the same
+        if (this.group != other.group) {
+            return false;
+        }
+        
+//        // Owner ref must be the same
+//        if (this.owner != other.owner) {
+//            return false;
+//        }
+
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result
+                + ((this.bean == null) ? 0 : this.bean.hashCode());
+        result = prime * result
+                + ((this.group == null) ? 0 : this.group.hashCode());
+//        result = prime * result
+//                + ((this.owner == null) ? 0 : this.owner.hashCode());
+        return result;
+    }
+
+    
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContext.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContext.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContext.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContext.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you 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.apache.bval.jsr;
+
+
+import org.apache.bval.jsr.groups.Group;
+import org.apache.bval.jsr.groups.Groups;
+import org.apache.bval.jsr.util.PathImpl;
+import org.apache.bval.model.MetaBean;
+import org.apache.bval.model.ValidationContext;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ElementKind;
+import javax.validation.MessageInterpolator;
+import javax.validation.ParameterNameProvider;
+import javax.validation.Path;
+import javax.validation.TraversableResolver;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * Description: JSR-303 {@link ValidationContext} extension. <br/>
+ */
+public interface GroupValidationContext<T>
+      extends ValidationContext<ConstraintValidationListener<T>> {
+    
+    /**
+     * Get the groups of this {@link GroupValidationContext}.
+     * @return the groups in their sequence for validation
+     */
+    Groups getGroups();
+
+    void setCurrentGroups(Groups groups);
+
+    /**
+     * Set the current {@link Group}.
+     * @param group to set
+     */
+    void setCurrentGroup(Group group);
+
+    /**
+     * Get the current {@link Group}.
+     * @return Group
+     */
+    Group getCurrentGroup();
+
+    /**
+     * Get the property path.
+     * @return {@link PathImpl}
+     */
+    PathImpl getPropertyPath();
+
+    /**
+     * Get the root {@link MetaBean}.
+     * @return {@link MetaBean}
+     */
+    MetaBean getRootMetaBean();
+
+    /**
+     * Set the {@link ConstraintValidation}.
+     * @param constraint to set
+     */
+    void setConstraintValidation(ConstraintValidation<?> constraint);
+
+    /**
+     * Get the {@link ConstraintValidation}.
+     * @return {@link ConstraintValidation}
+     */
+    ConstraintValidation<?> getConstraintValidation();
+
+    /**
+     * Get the value being validated.
+     * @return Object
+     */
+    Object getValidatedValue();
+
+    /**
+     * Set a fixed value for the context.
+     * @param value to set
+     */
+    void setFixedValue(Object value);
+
+    /**
+     * Get the message resolver.
+     * @return {@link MessageInterpolator}
+     */
+    MessageInterpolator getMessageResolver();
+
+    /**
+     * Get the {@link TraversableResolver}.
+     * @return {@link TraversableResolver}
+     */
+    TraversableResolver getTraversableResolver();
+
+    /**
+     * Accumulate a validated constraint.
+     * @param constraint
+     * @return true when the constraint for the object in this path was not
+     *         already validated in this context
+     */
+    boolean collectValidated(ConstraintValidator<?, ?> constraint);
+
+    /**
+     * Get the current owning class.
+     * @return Class
+     */
+    Class<?> getCurrentOwner();
+
+    /**
+     * Set the current owning class.
+     * @param currentOwner to set
+     */
+    void setCurrentOwner(Class<?> currentOwner);
+
+    void setKind(ElementKind type);
+
+    ElementKind getElementKind();
+
+    Object getReturnValue();
+
+    Object[] getParameters();
+
+    void setParameters(Object[] parameters);
+
+    void setReturnValue(Object returnValue);
+
+    ParameterNameProvider getParameterNameProvider();
+
+    void setMethod(Method method);
+
+    Method getMethod();
+
+    void setConstructor(Constructor<?> method);
+
+    Constructor<?> getConstructor();
+
+    void moveDown(Path.Node node);
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContextImpl.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContextImpl.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContextImpl.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContextImpl.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,369 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you 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.apache.bval.jsr;
+
+import org.apache.bval.BeanValidationContext;
+import org.apache.bval.jsr.groups.Group;
+import org.apache.bval.jsr.groups.Groups;
+import org.apache.bval.jsr.resolver.CachingTraversableResolver;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.jsr.util.PathImpl;
+import org.apache.bval.model.MetaBean;
+import org.apache.bval.model.MetaProperty;
+import org.apache.bval.util.AccessStrategy;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ElementKind;
+import javax.validation.MessageInterpolator;
+import javax.validation.ParameterNameProvider;
+import javax.validation.Path;
+import javax.validation.TraversableResolver;
+import javax.validation.ValidationException;
+import javax.validation.metadata.ConstraintDescriptor;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Description: instance per validation process, not thread-safe<br/>
+ */
+final class GroupValidationContextImpl<T> extends BeanValidationContext<ConstraintValidationListener<T>> implements
+    GroupValidationContext<T>, MessageInterpolator.Context {
+
+    private final MessageInterpolator messageResolver;
+    private final PathImpl path;
+    private final MetaBean rootMetaBean;
+    private final ParameterNameProvider parameterNameProvider;
+
+    /**
+     * the groups in the sequence of validation to take place
+     */
+    private Groups groups;
+    /**
+     * the current group during the validation process
+     */
+    private Group currentGroup;
+
+    private Class<?> currentOwner;
+
+    /**
+     * contains the validation constraints that have already been processed
+     * during this validation routine (as part of a previous group match)
+     */
+    private HashSet<ConstraintValidatorIdentity> validatedConstraints = new HashSet<ConstraintValidatorIdentity>();
+
+    private ConstraintValidation<?> constraintValidation;
+    private final TraversableResolver traversableResolver;
+
+    private Object[] parameters;
+    private Object returnValue;
+    private Method method;
+    private Constructor<?> constructor;
+
+    /**
+     * Create a new GroupValidationContextImpl instance.
+     *
+     * @param listener
+     * @param aMessageResolver
+     * @param traversableResolver
+     * @param parameterNameProvider
+     * @param rootMetaBean
+     */
+    public GroupValidationContextImpl(ConstraintValidationListener<T> listener, MessageInterpolator aMessageResolver,
+                                      TraversableResolver traversableResolver, ParameterNameProvider parameterNameProvider, MetaBean rootMetaBean) {
+        // inherited variable 'validatedObjects' is of type:
+        // HashMap<GraphBeanIdentity, Set<PathImpl>> in this class
+        super(listener, new HashMap<GraphBeanIdentity, Set<PathImpl>>());
+        this.messageResolver = aMessageResolver;
+        this.traversableResolver = CachingTraversableResolver.cacheFor(traversableResolver);
+        this.parameterNameProvider = parameterNameProvider;
+        this.rootMetaBean = rootMetaBean;
+        this.path = PathImpl.create();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setCurrentIndex(Integer index) {
+        NodeImpl leaf = path.getLeafNode();
+        if (leaf.getName() == null) {
+            leaf.setIndex(index);
+        } else {
+            path.addNode(NodeImpl.atIndex(index));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setCurrentKey(Object key) {
+        NodeImpl leaf = path.getLeafNode();
+        if (leaf.getName() == null) {
+            leaf.setKey(key);
+        } else {
+            path.addNode(NodeImpl.atKey(key));
+        }
+    }
+
+    public void setKind(final ElementKind type) {
+        path.getLeafNode().setKind(type);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void moveDown(MetaProperty prop, AccessStrategy access) {
+        moveDown(prop.getName());
+        super.moveDown(prop, access);
+    }
+
+    @Override
+    public void moveDown(final String prop) {
+        path.addProperty(prop);
+    }
+
+    public void moveDown(final Path.Node node) {
+        path.addNode(node);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void moveUp(Object bean, MetaBean metaBean) {
+        NodeImpl leaf = path.getLeafNode();
+        if (leaf.isInIterable() && leaf.getName() != null) {
+            leaf.setName(null);
+        } else {
+            path.removeLeafNode();
+        }
+        super.moveUp(bean, metaBean); // call super!
+    }
+
+    /**
+     * {@inheritDoc} Here, state equates to bean identity + group.
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public boolean collectValidated() {
+
+        // Combination of bean+group+owner (owner is currently ignored)
+        GraphBeanIdentity gbi = new GraphBeanIdentity(getBean(), getCurrentGroup().getGroup(), getCurrentOwner());
+
+        Set<PathImpl> validatedPathsForGBI = (Set<PathImpl>) validatedObjects.get(gbi);
+        if (validatedPathsForGBI == null) {
+            validatedPathsForGBI = new HashSet<PathImpl>();
+            validatedObjects.put(gbi, validatedPathsForGBI);
+        }
+
+        // If any of the paths is a subpath of the current path, there is a
+        // circular dependency, so return false
+        for (PathImpl validatedPath : validatedPathsForGBI) {
+            if (path.isSubPathOf(validatedPath)) {
+                return false;
+            }
+        }
+
+        // Else, add the currentPath to the set of validatedPaths
+        validatedPathsForGBI.add(PathImpl.copy(path));
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean collectValidated(ConstraintValidator<?, ?> constraint) {
+        ConstraintValidatorIdentity cvi = new ConstraintValidatorIdentity(getBean(), getPropertyPath(), constraint);
+        return this.validatedConstraints.add(cvi);
+    }
+
+    /**
+     * Reset the validated constraints.
+     */
+    public void resetValidatedConstraints() {
+        validatedConstraints.clear();
+    }
+
+    /**
+     * {@inheritDoc} If an associated object is validated, add the association
+     * field or JavaBeans property name and a dot ('.') as a prefix to the
+     * previous rules. uses prop[index] in property path for elements in
+     * to-many-relationships.
+     * 
+     * @return the path in dot notation
+     */
+    public PathImpl getPropertyPath() {
+        PathImpl currentPath = PathImpl.copy(path);
+        if (getMetaProperty() != null) {
+            currentPath.addProperty(getMetaProperty().getName());
+        }
+        return currentPath;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public MetaBean getRootMetaBean() {
+        return rootMetaBean;
+    }
+
+    /**
+     * Set the Groups.
+     * 
+     * @param groups
+     */
+    public void setGroups(Groups groups) {
+        this.groups = groups;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Groups getGroups() {
+        return groups;
+    }
+
+    public void setCurrentGroups(final Groups g) {
+        groups = g;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Group getCurrentGroup() {
+        return currentGroup;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCurrentGroup(Group currentGroup) {
+        this.currentGroup = currentGroup;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setConstraintValidation(ConstraintValidation<?> constraint) {
+        constraintValidation = constraint;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ConstraintValidation<?> getConstraintValidation() {
+        return constraintValidation;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ConstraintDescriptor<?> getConstraintDescriptor() {
+        return constraintValidation;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object getValidatedValue() {
+        if (getMetaProperty() != null) {
+            return getPropertyValue(constraintValidation.getAccess());
+        } else {
+            return getBean();
+        }
+    }
+
+    public <T> T unwrap(Class<T> type) {
+        if (type.isInstance(this)) {
+            return type.cast(this);
+        }
+        throw new ValidationException("Type " + type + " not supported");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageInterpolator getMessageResolver() {
+        return messageResolver;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public TraversableResolver getTraversableResolver() {
+        return traversableResolver;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Class<?> getCurrentOwner() {
+        return this.currentOwner;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCurrentOwner(Class<?> currentOwner) {
+        this.currentOwner = currentOwner;
+    }
+
+    public ElementKind getElementKind() {
+        return path.getLeafNode().getKind();
+    }
+
+    public Object getReturnValue() {
+        return returnValue;
+    }
+
+    public Object[] getParameters() {
+        return parameters;
+    }
+
+    public void setParameters(final Object[] parameters) {
+        this.parameters = parameters;
+    }
+
+    public void setReturnValue(final Object returnValue) {
+        this.returnValue = returnValue;
+    }
+
+    public ParameterNameProvider getParameterNameProvider() {
+        return parameterNameProvider;
+    }
+
+    public void setMethod(final Method method) {
+        this.method = method;
+    }
+
+    public Method getMethod() {
+        return method;
+    }
+
+    public Constructor<?> getConstructor() {
+        return constructor;
+    }
+
+    public void setConstructor(final Constructor<?> constructor) {
+        this.constructor = constructor;
+    }
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/IncompatiblePropertyValueException.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/IncompatiblePropertyValueException.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/IncompatiblePropertyValueException.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/IncompatiblePropertyValueException.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr;
+
+import javax.validation.ValidationException;
+
+/**
+ * Internal exception thrown when trying to validate a value for a property for which it is not assignment-compatible.
+ * 
+ * @version $Rev: 1031833 $ $Date: 2010-11-05 16:53:03 -0500 (Fri, 05 Nov 2010) $
+ * 
+ * @author Matt Benson
+ */
+public class IncompatiblePropertyValueException extends ValidationException {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Create a new {@link IncompatiblePropertyValueException} instance.
+     * 
+     * @param message
+     */
+    public IncompatiblePropertyValueException(String message) {
+        super(message);
+    }
+
+    /**
+     * Create a new IncompatiblePropertyValueException instance.
+     */
+    public IncompatiblePropertyValueException() {
+        super();
+    }
+
+    /**
+     * Create a new IncompatiblePropertyValueException instance.
+     * 
+     * @param message
+     * @param cause
+     */
+    public IncompatiblePropertyValueException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Create a new IncompatiblePropertyValueException instance.
+     * 
+     * @param cause
+     */
+    public IncompatiblePropertyValueException(Throwable cause) {
+        super(cause);
+    }
+
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/InvocableElementDescriptor.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/InvocableElementDescriptor.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/InvocableElementDescriptor.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/InvocableElementDescriptor.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,102 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.apache.bval.jsr;
+
+import org.apache.bval.model.MetaBean;
+import org.apache.bval.model.Validation;
+
+import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.metadata.CrossParameterDescriptor;
+import javax.validation.metadata.ElementDescriptor;
+import javax.validation.metadata.ParameterDescriptor;
+import javax.validation.metadata.ReturnValueDescriptor;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+public class InvocableElementDescriptor extends ElementDescriptorImpl implements ProcedureDescriptor {
+    private static final CopyOnWriteArraySet<ConstraintValidation<?>> NO_CONSTRAINTS = new CopyOnWriteArraySet<ConstraintValidation<?>>();
+
+    private ReturnValueDescriptor returnValueDescriptor;
+    private CrossParameterDescriptor crossParameterDescriptor;
+    private final List<ParameterDescriptor> parameterDescriptors = new ArrayList<ParameterDescriptor>();
+
+    protected InvocableElementDescriptor(final MetaBean metaBean, final Class<?> elementClass, final Validation[] validations) {
+        super(metaBean, elementClass, validations);
+    }
+
+    protected InvocableElementDescriptor(final Class<?> elementClass, final Validation[] validations) {
+        super(elementClass, validations);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<ParameterDescriptor> getParameterDescriptors() {
+        // index aligned
+        return parameterDescriptors;
+    }
+
+    public void setReturnValueDescriptor(final ReturnValueDescriptor returnValueDescriptor) {
+        this.returnValueDescriptor = returnValueDescriptor;
+    }
+
+    public CrossParameterDescriptor getCrossParameterDescriptor() {
+        return crossParameterDescriptor;
+    }
+
+    public void setCrossParameterDescriptor(final CrossParameterDescriptor crossParameterDescriptor) {
+        this.crossParameterDescriptor = crossParameterDescriptor;
+    }
+
+    /**
+     * Add the specified validations to this {@link org.apache.bval.jsr.MethodDescriptorImpl}.
+     * @param validations
+     */
+    void addValidations(Collection<ConstraintValidation<?>> validations) {
+        getMutableConstraintDescriptors().addAll(validations);
+    }
+
+    protected boolean hasConstrainedParameters() {
+        for (final ParameterDescriptor pd : getParameterDescriptors()) {
+            if (pd.isCascaded() || !pd.getConstraintDescriptors().isEmpty()) {
+                return true;
+            }
+        }
+        return getCrossParameterDescriptor().hasConstraints();
+    }
+
+    public ReturnValueDescriptor getReturnValueDescriptor() {
+        return returnValueDescriptor;
+    }
+
+    protected boolean hasConstrainedReturnValue() {
+        return getReturnValueDescriptor().isCascaded() || !getReturnValueDescriptor().getConstraintDescriptors().isEmpty();
+    }
+
+    @Override
+    public ElementDescriptor.ConstraintFinder findConstraints() {
+        return new ConstraintFinderImpl(metaBean, NO_CONSTRAINTS);
+    }
+
+    @Override
+    public Set<ConstraintDescriptor<?>> getConstraintDescriptors() {
+        return Set.class.cast(NO_CONSTRAINTS);
+    }
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/JsrFeatures.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/JsrFeatures.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/JsrFeatures.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/JsrFeatures.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr;
+
+import org.apache.bval.model.Features;
+
+/**
+ * Description: Contains MetaBean feature keys of additional features used in the implementation
+ * of JSR303<br/>
+ *
+ * @see org.apache.bval.model.FeaturesCapable
+ * @see org.apache.bval.model.Features
+ */
+public interface JsrFeatures {
+    interface Method extends Features.Property {
+        String MethodDescriptor = "MethodDescriptor";
+    }
+
+    interface Constructor extends Features.Property {
+        String ConstructorDescriptor = "ConstructorDescriptor";
+    }
+
+    /**
+     * JSR303 Property features
+     */
+    interface Property extends Features.Property {
+        /** INFO: cached PropertyDescriptorImpl of the property */
+        String PropertyDescriptor = "PropertyDescriptor";
+        /**
+         * INFO: Class[] with the groups to validate a REF_CASCADE
+         */
+        String REF_GROUPS = "refGroups";
+
+        // Collection<Annotation>
+        String ANNOTATIONS_TO_PROCESS = "annotationToProcess";
+    }
+
+    /**
+     * JSR303 bean features
+     */
+    interface Bean extends Features.Bean {
+        /**
+         * INFO: List of Group(Class) for {@link javax.validation.GroupSequence#value()}
+         * (redefined default group)
+         **/
+        String GROUP_SEQUENCE = "GroupSequence";
+
+//        INFO: cached sorted Array with ValidationEntries 
+//        String VALIDATION_SEQUENCE = "ValidationSequence";
+
+        /**
+         * INFO: cached BeanDescriptorImpl of the bean
+         */
+        String BEAN_DESCRIPTOR = "BeanDescriptor";
+    }
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/JsrMetaBeanFactory.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/JsrMetaBeanFactory.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/JsrMetaBeanFactory.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/JsrMetaBeanFactory.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,331 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr;
+
+import org.apache.bval.MetaBeanFactory;
+import org.apache.bval.jsr.groups.Group;
+import org.apache.bval.jsr.util.ClassHelper;
+import org.apache.bval.jsr.xml.MetaConstraint;
+import org.apache.bval.model.Meta;
+import org.apache.bval.model.MetaBean;
+import org.apache.bval.model.MetaConstructor;
+import org.apache.bval.model.MetaMethod;
+import org.apache.bval.model.MetaParameter;
+import org.apache.bval.model.MetaProperty;
+import org.apache.bval.util.AccessStrategy;
+import org.apache.bval.util.FieldAccess;
+import org.apache.bval.util.MethodAccess;
+import org.apache.bval.util.reflection.Reflection;
+
+import javax.validation.ConstraintDeclarationException;
+import javax.validation.GroupDefinitionException;
+import javax.validation.GroupSequence;
+import javax.validation.groups.ConvertGroup;
+import javax.validation.groups.Default;
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Description: process the class annotations for JSR303 constraint validations to build the MetaBean with information
+ * from annotations and JSR303 constraint mappings (defined in xml)<br/>
+ */
+public class JsrMetaBeanFactory implements MetaBeanFactory {
+    /** Shared log instance */
+    // of dubious utility as it's static :/
+    protected static final Logger log = Logger.getLogger(JsrMetaBeanFactory.class.getName());
+
+    /** {@link ApacheFactoryContext} used */
+    protected final ApacheFactoryContext factoryContext;
+
+    /**
+     * {@link AnnotationProcessor} used.
+     */
+    protected AnnotationProcessor annotationProcessor;
+
+    /**
+     * Create a new Jsr303MetaBeanFactory instance.
+     * 
+     * @param factoryContext
+     */
+    public JsrMetaBeanFactory(ApacheFactoryContext factoryContext) {
+        this.factoryContext = factoryContext;
+        this.annotationProcessor = new AnnotationProcessor(factoryContext);
+    }
+
+    /**
+     * {@inheritDoc} Add the validation features to the metabean that come from JSR303 annotations in the beanClass.
+     */
+    public void buildMetaBean(MetaBean metabean) {
+        try {
+            final Class<?> beanClass = metabean.getBeanClass();
+            processGroupSequence(beanClass, metabean);
+
+            // process class, superclasses and interfaces
+            List<Class<?>> classSequence = new ArrayList<Class<?>>();
+            ClassHelper.fillFullClassHierarchyAsList(classSequence, beanClass);
+
+            // start with superclasses and go down the hierarchy so that
+            // the child classes are processed last to have the chance to
+            // overwrite some declarations
+            // of their superclasses and that they see what they inherit at the
+            // time of processing
+            for (int i = classSequence.size() - 1; i >= 0; i--) {
+                Class<?> eachClass = classSequence.get(i);
+                if (eachClass == Serializable.class || eachClass == Cloneable.class) {
+                    continue;
+                }
+
+                processClass(eachClass, metabean);
+                processGroupSequence(eachClass, metabean, "{GroupSequence:" + eachClass.getCanonicalName() + "}");
+            }
+
+        } catch (IllegalAccessException e) {
+            throw new IllegalArgumentException(e);
+        } catch (InvocationTargetException e) {
+            throw new IllegalArgumentException(e.getTargetException());
+        }
+    }
+
+    /**
+     * Process class annotations, field and method annotations.
+     * 
+     * @param beanClass
+     * @param metabean
+     * @throws IllegalAccessException
+     * @throws InvocationTargetException
+     */
+    private void processClass(Class<?> beanClass, MetaBean metabean) throws IllegalAccessException,
+        InvocationTargetException {
+
+        // if NOT ignore class level annotations
+        if (!factoryContext.getFactory().getAnnotationIgnores().isIgnoreAnnotations(beanClass)) {
+            annotationProcessor.processAnnotations(null, beanClass, beanClass, null, new AppendValidationToMeta(metabean));
+        }
+
+        final Collection<String> missingValid = new ArrayList<String>();
+
+        final Field[] fields = Reflection.INSTANCE.getDeclaredFields(beanClass);
+        for (final Field field : fields) {
+            MetaProperty metaProperty = metabean.getProperty(field.getName());
+            // create a property for those fields for which there is not yet a
+            // MetaProperty
+            if (!factoryContext.getFactory().getAnnotationIgnores().isIgnoreAnnotations(field)) {
+                AccessStrategy access = new FieldAccess(field);
+                boolean create = metaProperty == null;
+                if (create) {
+                    metaProperty = addMetaProperty(metabean, access);
+                }
+                if (!annotationProcessor.processAnnotations(metaProperty, beanClass, field, access,
+                    new AppendValidationToMeta(metaProperty)) && create) {
+                    metabean.putProperty(metaProperty.getName(), null);
+                }
+
+                if (field.getAnnotation(ConvertGroup.class) != null) {
+                    missingValid.add(field.getName());
+                }
+            }
+        }
+        final Method[] methods = Reflection.INSTANCE.getDeclaredMethods(beanClass);
+        for (final Method method : methods) {
+            String propName = null;
+            if (method.getParameterTypes().length == 0) {
+                propName = MethodAccess.getPropertyName(method);
+            }
+            if (propName != null) {
+                if (!factoryContext.getFactory().getAnnotationIgnores().isIgnoreAnnotations(method)) {
+                    AccessStrategy access = new MethodAccess(propName, method);
+                    MetaProperty metaProperty = metabean.getProperty(propName);
+                    boolean create = metaProperty == null;
+                    // create a property for those methods for which there is
+                    // not yet a MetaProperty
+                    if (create) {
+                        metaProperty = addMetaProperty(metabean, access);
+                    }
+                    if (!annotationProcessor.processAnnotations(metaProperty, beanClass, method, access,
+                        new AppendValidationToMeta(metaProperty)) && create) {
+                        metabean.putProperty(propName, null);
+                    }
+                }
+            }
+        }
+
+        addXmlConstraints(beanClass, metabean);
+
+        for (final String name : missingValid) {
+            final MetaProperty metaProperty = metabean.getProperty(name);
+            if (metaProperty != null && metaProperty.getFeature(JsrFeatures.Property.REF_CASCADE) == null) {
+                throw new ConstraintDeclarationException("@ConvertGroup needs @Valid");
+            }
+        }
+        missingValid.clear();
+    }
+
+    /**
+     * Add cascade validation and constraints from xml mappings
+     * 
+     * @param beanClass
+     * @param metabean
+     * @throws IllegalAccessException
+     * @throws InvocationTargetException
+     */
+    private void addXmlConstraints(Class<?> beanClass, MetaBean metabean) throws IllegalAccessException,
+        InvocationTargetException {
+        for (final MetaConstraint<?, ? extends Annotation> metaConstraint : factoryContext.getFactory().getMetaConstraints(beanClass)) {
+            Meta meta;
+            AccessStrategy access = metaConstraint.getAccessStrategy();
+            boolean create = false;
+            if (access == null) { // class level
+                meta = null;
+            } else if (access.getElementType() == ElementType.METHOD && !metaConstraint.getMember().getName().startsWith("get")) { // TODO: better getter test
+                final Method method = Method.class.cast(metaConstraint.getMember());
+                meta = metabean.getMethod(method);
+                final MetaMethod metaMethod;
+                if (meta == null) {
+                    meta = new MetaMethod(metabean, method);
+                    metaMethod = MetaMethod.class.cast(meta);
+                    metabean.addMethod(method, metaMethod);
+                } else {
+                    metaMethod = MetaMethod.class.cast(meta);
+                }
+                final Integer index = metaConstraint.getIndex();
+                if (index != null && index >= 0) {
+                    MetaParameter param = metaMethod.getParameter(index);
+                    if (param == null) {
+                        param = new MetaParameter(metaMethod, index);
+                        metaMethod.addParameter(index, param);
+                    }
+                    param.addAnnotation(metaConstraint.getAnnotation());
+                } else {
+                    metaMethod.addAnnotation(metaConstraint.getAnnotation());
+                }
+                continue;
+            } else if (access.getElementType() == ElementType.CONSTRUCTOR){
+                final Constructor<?> constructor = Constructor.class.cast(metaConstraint.getMember());
+                meta = metabean.getConstructor(constructor);
+                final MetaConstructor metaConstructor;
+                if (meta == null) {
+                    meta = new MetaConstructor(metabean, constructor);
+                    metaConstructor = MetaConstructor.class.cast(meta);
+                    metabean.addConstructor(constructor, metaConstructor);
+                } else {
+                    metaConstructor = MetaConstructor.class.cast(meta);
+                }
+                final Integer index = metaConstraint.getIndex();
+                if (index != null && index >= 0) {
+                    MetaParameter param = metaConstructor.getParameter(index);
+                    if (param == null) {
+                        param = new MetaParameter(metaConstructor, index);
+                        metaConstructor.addParameter(index, param);
+                    }
+                    param.addAnnotation(metaConstraint.getAnnotation());
+                } else {
+                    metaConstructor.addAnnotation(metaConstraint.getAnnotation());
+                }
+                continue;
+            } else { // property level
+                meta = metabean.getProperty(access.getPropertyName());
+                create = meta == null;
+                if (create) {
+                    meta = addMetaProperty(metabean, access);
+                }
+            }
+            if (!annotationProcessor.processAnnotation(metaConstraint.getAnnotation(), meta, beanClass,
+                metaConstraint.getAccessStrategy(), new AppendValidationToMeta(meta == null ? metabean : meta), false)
+                && create) {
+                metabean.putProperty(access.getPropertyName(), null);
+            }
+        }
+        for (final AccessStrategy access : factoryContext.getFactory().getValidAccesses(beanClass)) {
+            if (access.getElementType() == ElementType.PARAMETER) {
+                continue;
+            }
+
+            MetaProperty metaProperty = metabean.getProperty(access.getPropertyName());
+            boolean create = metaProperty == null;
+            if (create) {
+                metaProperty = addMetaProperty(metabean, access);
+            }
+            if (!annotationProcessor.addAccessStrategy(metaProperty, access) && create) {
+                metabean.putProperty(access.getPropertyName(), null);
+            }
+        }
+    }
+
+    private void processGroupSequence(Class<?> beanClass, MetaBean metabean) {
+        processGroupSequence(beanClass, metabean, JsrFeatures.Bean.GROUP_SEQUENCE);
+    }
+
+    private void processGroupSequence(Class<?> beanClass, MetaBean metabean, String key) {
+        GroupSequence annotation = beanClass.getAnnotation(GroupSequence.class);
+        List<Group> groupSeq = metabean.getFeature(key);
+        if (groupSeq == null) {
+            groupSeq = metabean.initFeature(key, new ArrayList<Group>(annotation == null ? 1 : annotation.value().length));
+        }
+        Class<?>[] groupClasses = factoryContext.getFactory().getDefaultSequence(beanClass);
+        if (groupClasses == null || groupClasses.length == 0) {
+            if (annotation == null) {
+                groupSeq.add(Group.DEFAULT);
+                return;
+            } else {
+                groupClasses = annotation.value();
+            }
+        }
+        boolean containsDefault = false;
+        for (final Class<?> groupClass : groupClasses) {
+            if (groupClass.getName().equals(beanClass.getName())) {
+                groupSeq.add(Group.DEFAULT);
+                containsDefault = true;
+            } else if (groupClass.getName().equals(Default.class.getName())) {
+                throw new GroupDefinitionException("'Default.class' must not appear in @GroupSequence! Use '"
+                    + beanClass.getSimpleName() + ".class' instead.");
+            } else {
+                groupSeq.add(new Group(groupClass));
+            }
+        }
+        if (!containsDefault) {
+            throw new GroupDefinitionException("Redefined default group sequence must contain " + beanClass.getName());
+        }
+        log.log(Level.FINEST, String.format("Default group sequence for bean %s is: %s", beanClass.getName(), groupSeq));
+    }
+
+    /**
+     * Add a {@link MetaProperty} to a {@link MetaBean}.
+     * @param parentMetaBean
+     * @param access
+     * @return the created {@link MetaProperty}
+     */
+    public static MetaProperty addMetaProperty(MetaBean parentMetaBean, AccessStrategy access) {
+        final MetaProperty result = new MetaProperty();
+        final String name = access.getPropertyName();
+        result.setName(name);
+        result.setType(access.getJavaType());
+        parentMetaBean.putProperty(name, result);
+        return result;
+    }
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/MethodDescriptor.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/MethodDescriptor.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/MethodDescriptor.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/MethodDescriptor.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.apache.bval.jsr;
+
+import javax.validation.metadata.ElementDescriptor;
+import javax.validation.metadata.ParameterDescriptor;
+import java.util.List;
+
+/**
+ * Description: This class will disappear when such
+ * functionality is part of the JSR303 specification.<br/>
+ */
+public interface MethodDescriptor extends ElementDescriptor {
+    /**
+     * Get the {@link javax.validation.metadata.ParameterDescriptor}s for this {@link org.apache.bval.jsr.MethodDescriptor}.
+     * @return {@link java.util.List} of {@link javax.validation.metadata.ParameterDescriptor}
+     */
+    List<ParameterDescriptor> getParameterDescriptors(); //index aligned
+
+    /**
+     * Learn whether the referenced method should be validated.
+     * @return boolean
+     */
+    boolean isCascaded();
+
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/MethodDescriptorImpl.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/MethodDescriptorImpl.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/MethodDescriptorImpl.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/MethodDescriptorImpl.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.apache.bval.jsr;
+
+import org.apache.bval.model.MetaBean;
+import org.apache.bval.model.MetaMethod;
+import org.apache.bval.model.Validation;
+
+import java.lang.reflect.Method;
+
+/**
+ * Description: {@link MethodDescriptor} implementation.<br/>
+ */
+public class MethodDescriptorImpl extends InvocableElementDescriptor implements javax.validation.metadata.MethodDescriptor, ProcedureDescriptor {
+    private static final Validation[] EMPTY_VALIDATION = new Validation[0];
+
+    private final String name;
+
+    protected MethodDescriptorImpl(final MetaBean metaBean, final Validation[] validations, final Method method) {
+        super(metaBean, method.getReturnType(), validations);
+        name = method.getName();
+    }
+
+    public MethodDescriptorImpl(final MetaBean bean, final MetaMethod metaMethod) {
+        super(bean, metaMethod.getMethod().getReturnType(), EMPTY_VALIDATION);
+        setCascaded(false);
+        this.name = metaMethod.getMethod().getName();
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public boolean hasConstrainedParameters() {
+        return super.hasConstrainedParameters();
+    }
+
+    public boolean hasConstrainedReturnValue() {
+        return super.hasConstrainedReturnValue();
+    }
+
+    @Override
+    public boolean hasConstraints() {
+        return false;
+    }
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/NodeBuilderCustomizableContextImpl.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/NodeBuilderCustomizableContextImpl.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/NodeBuilderCustomizableContextImpl.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/NodeBuilderCustomizableContextImpl.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr;
+
+import org.apache.bval.jsr.util.LeafNodeBuilderCustomizableContextImpl;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.jsr.util.PathImpl;
+
+import javax.validation.ConstraintValidatorContext;
+import javax.validation.ElementKind;
+
+public class NodeBuilderCustomizableContextImpl implements ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext {
+    private final PathImpl path;
+    private final ConstraintValidatorContextImpl context;
+    private final String template;
+
+    public NodeBuilderCustomizableContextImpl(final ConstraintValidatorContextImpl parent, final String messageTemplate, final PathImpl propertyPath) {
+        context = parent;
+        template = messageTemplate;
+        path = propertyPath;
+    }
+
+    public ConstraintValidatorContext.ConstraintViolationBuilder.NodeContextBuilder inIterable() {
+        path.getLeafNode().setInIterable(true);
+        return new NodeContextBuilderImpl(context, template, path);
+    }
+
+    public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addNode(String name) {
+        path.addNode(new NodeImpl(name));
+        return this;
+    }
+
+    public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addPropertyNode(String name) {
+        final NodeImpl node = new NodeImpl.PropertyNodeImpl(name);
+        node.setKind(ElementKind.PROPERTY);
+        path.addNode(node);
+        return this;
+    }
+
+    public ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext addBeanNode() {
+        final NodeImpl node = new NodeImpl.BeanNodeImpl();
+        node.setKind(ElementKind.BEAN);
+        path.addNode(node);
+        return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
+    }
+
+    public ConstraintValidatorContext addConstraintViolation() {
+        context.addError(template, path);
+        return context;
+    }
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/NodeContextBuilderImpl.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/NodeContextBuilderImpl.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/NodeContextBuilderImpl.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/NodeContextBuilderImpl.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.bval.jsr;
+
+import org.apache.bval.jsr.util.LeafNodeBuilderCustomizableContextImpl;
+import org.apache.bval.jsr.util.NodeBuilderDefinedContextImpl;
+import org.apache.bval.jsr.util.NodeImpl;
+import org.apache.bval.jsr.util.PathImpl;
+
+import javax.validation.ConstraintValidatorContext;
+import javax.validation.ElementKind;
+
+public class NodeContextBuilderImpl implements ConstraintValidatorContext.ConstraintViolationBuilder.NodeContextBuilder {
+    private final PathImpl path;
+    private final String template;
+    private final ConstraintValidatorContextImpl context;
+
+    public NodeContextBuilderImpl(final ConstraintValidatorContextImpl context, final String template, final PathImpl path) {
+        this.context = context;
+        this.template = template;
+        this.path = path;
+    }
+
+    public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext atKey(Object key) {
+        path.getLeafNode().setKey(key);
+        return new NodeBuilderDefinedContextImpl(context, template, path);
+    }
+
+    public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext atIndex(Integer index) {
+        path.getLeafNode().setIndex(index);
+        return new NodeBuilderDefinedContextImpl(context, template, path);
+    }
+
+    public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addNode(String name) {
+        return new NodeBuilderCustomizableContextImpl(context, template, path).addNode(name);
+    }
+
+    public ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext addPropertyNode(String name) {
+        return new NodeBuilderCustomizableContextImpl(context, template, path).addPropertyNode(name);
+    }
+
+    public ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext addBeanNode() {
+        final NodeImpl node = new NodeImpl.BeanNodeImpl();
+        node.setKind(ElementKind.BEAN);
+        path.addNode(node);
+        return new LeafNodeBuilderCustomizableContextImpl(context, template, path);
+    }
+
+    public ConstraintValidatorContext addConstraintViolation() {
+        context.addError(template, path);
+        return context;
+    }
+}