BVAL-143 caching should be hold by the factory or shouldnt be for performance reason + reactivating jboss repo since tck (1.0) modules are not on central

git-svn-id: https://svn.apache.org/repos/asf/bval/trunk@1721536 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bval-jsr/pom.xml b/bval-jsr/pom.xml
index ac5ad97..5a93460 100644
--- a/bval-jsr/pom.xml
+++ b/bval-jsr/pom.xml
@@ -297,10 +297,12 @@
                     </includes>
                 </configuration>
             </plugin>
+            <!-- TODO: activate but ATM it just doesnt build with it
             <plugin>
                 <groupId>org.apache.commons</groupId>
                 <artifactId>commons-weaver-maven-plugin</artifactId>
             </plugin>
+            -->
         </plugins>
     </build>
 </project>
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationConstraintBuilder.java b/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationConstraintBuilder.java
index ababfbd..d75bb31 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationConstraintBuilder.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationConstraintBuilder.java
@@ -18,6 +18,23 @@
  */
 package org.apache.bval.jsr;
 
+import org.apache.bval.jsr.groups.GroupsComputer;
+import org.apache.bval.jsr.xml.AnnotationProxyBuilder;
+import org.apache.bval.util.AccessStrategy;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.reflect.TypeUtils;
+import org.apache.commons.weaver.privilizer.Privileged;
+
+import javax.validation.Constraint;
+import javax.validation.ConstraintDeclarationException;
+import javax.validation.ConstraintDefinitionException;
+import javax.validation.ConstraintTarget;
+import javax.validation.ConstraintValidator;
+import javax.validation.OverridesAttribute;
+import javax.validation.Payload;
+import javax.validation.ReportAsSingleViolation;
+import javax.validation.constraintvalidation.SupportedValidationTarget;
+import javax.validation.constraintvalidation.ValidationTarget;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -32,25 +49,6 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import javax.validation.Constraint;
-import javax.validation.ConstraintDeclarationException;
-import javax.validation.ConstraintDefinitionException;
-import javax.validation.ConstraintTarget;
-import javax.validation.ConstraintValidator;
-import javax.validation.ConstraintValidatorFactory;
-import javax.validation.OverridesAttribute;
-import javax.validation.Payload;
-import javax.validation.ReportAsSingleViolation;
-import javax.validation.constraintvalidation.SupportedValidationTarget;
-import javax.validation.constraintvalidation.ValidationTarget;
-
-import org.apache.bval.jsr.groups.GroupsComputer;
-import org.apache.bval.jsr.xml.AnnotationProxyBuilder;
-import org.apache.bval.util.AccessStrategy;
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.commons.lang3.reflect.TypeUtils;
-import org.apache.commons.weaver.privilizer.Privileged;
-
 /**
  * Description: helper class that builds a {@link ConstraintValidation} or its
  * composite constraint validations by parsing the jsr-annotations and
@@ -64,19 +62,19 @@
 
     /**
      * Create a new AnnotationConstraintBuilder instance.
-     * 
+     *
      * @param validatorClasses
      * @param annotation
      * @param owner
      * @param access
      */
-    public AnnotationConstraintBuilder(ConstraintValidatorFactory factory,
-        Class<? extends ConstraintValidator<A, ?>>[] validatorClasses, A annotation, Class<?> owner,
-        AccessStrategy access, ConstraintTarget target) {
+    public AnnotationConstraintBuilder(
+            Class<? extends ConstraintValidator<A, ?>>[] validatorClasses, A annotation, Class<?> owner,
+            AccessStrategy access, ConstraintTarget target) {
         final boolean reportFromComposite =
             annotation != null && annotation.annotationType().isAnnotationPresent(ReportAsSingleViolation.class);
         constraintValidation =
-            new ConstraintValidation<A>(factory, validatorClasses, annotation, owner, access, reportFromComposite,
+            new ConstraintValidation<A>(validatorClasses, annotation, owner, access, reportFromComposite,
                 target);
         buildFromAnnotation();
     }
@@ -259,7 +257,7 @@
 
     /**
      * Get the configured {@link ConstraintValidation}.
-     * 
+     *
      * @return {@link ConstraintValidation}
      */
     public ConstraintValidation<?> getConstraintValidation() {
@@ -309,7 +307,7 @@
      * Calculates the index of the composite constraint. The index represents
      * the order in which it is added in reference to other constraints of the
      * same type.
-     * 
+     *
      * @param composite
      *            The composite constraint (not yet added).
      * @return An integer index always >= 0
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationProcessor.java b/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationProcessor.java
index a5332c0..7fcd4d7 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationProcessor.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/AnnotationProcessor.java
@@ -34,7 +34,6 @@
 import javax.validation.constraintvalidation.ValidationTarget;
 import javax.validation.groups.ConvertGroup;
 import javax.validation.groups.Default;
-
 import java.lang.annotation.Annotation;
 import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.InvocationTargetException;
@@ -50,15 +49,15 @@
 @Privilizing(@CallTo(Reflection.class))
 public final class AnnotationProcessor {
     /** {@link ApacheFactoryContext} used */
-    private final ApacheFactoryContext factoryContext;
+    private final ApacheValidatorFactory factory;
 
     /**
      * Create a new {@link AnnotationProcessor} instance.
      * 
-     * @param factoryContext
+     * @param factory the validator factory.
      */
-    public AnnotationProcessor(ApacheFactoryContext factoryContext) {
-        this.factoryContext = factoryContext;
+    public AnnotationProcessor(ApacheValidatorFactory factory) {
+        this.factory = factory;
     }
 
     /**
@@ -112,7 +111,7 @@
      * @throws InvocationTargetException
      */
     public <A extends Annotation> boolean processAnnotation(A annotation, Meta prop, Class<?> owner,
-        AccessStrategy access, AppendValidation appender, boolean reflection) throws IllegalAccessException,
+            AccessStrategy access, AppendValidation appender, boolean reflection) throws IllegalAccessException,
         InvocationTargetException {
         if (annotation instanceof Valid) {
             return addAccessStrategy(prop, access);
@@ -204,12 +203,11 @@
         }
         final Class<A> annotationType = (Class<A>) annotation.annotationType();
         Class<? extends ConstraintValidator<A, ?>>[] validatorClasses =
-            factoryContext.getFactory().getConstraintsCache().getConstraintValidators(annotationType);
+            factory.getConstraintsCache().getConstraintValidators(annotationType);
         if (validatorClasses == null) {
             validatorClasses = (Class<? extends ConstraintValidator<A, ?>>[]) vcAnno.validatedBy();
             if (validatorClasses.length == 0) {
-                validatorClasses =
-                    factoryContext.getFactory().getDefaultConstraints().getValidatorClasses(annotationType);
+                validatorClasses = factory.getDefaultConstraints().getValidatorClasses(annotationType);
             }
         }
         return validatorClasses;
@@ -234,7 +232,8 @@
      * @throws IllegalAccessException
      * @throws InvocationTargetException
      */
-    private <A extends Annotation> boolean applyConstraint(A annotation,
+    private <A extends Annotation> boolean applyConstraint(
+        A annotation,
         Class<? extends ConstraintValidator<A, ?>>[] rawConstraintClasses, Meta prop, Class<?> owner,
         AccessStrategy access, AppendValidation appender) throws IllegalAccessException, InvocationTargetException {
 
@@ -244,7 +243,8 @@
         }
 
         final AnnotationConstraintBuilder<A> builder =
-            new AnnotationConstraintBuilder<A>(factoryContext.getConstraintValidatorFactory(), constraintClasses,
+            new AnnotationConstraintBuilder<A>(
+                constraintClasses,
                 annotation, owner, access, null);
 
         // JSR-303 3.4.4: Add implicit groups
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java
index 05f6fa0..700c0a8 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheFactoryContext.java
@@ -18,33 +18,18 @@
  */
 package org.apache.bval.jsr;
 
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.List;
+import org.apache.bval.MetaBeanFinder;
+import org.apache.bval.util.reflection.Reflection;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
 
 import javax.validation.ConstraintValidatorFactory;
 import javax.validation.MessageInterpolator;
 import javax.validation.ParameterNameProvider;
 import javax.validation.TraversableResolver;
-import javax.validation.ValidationException;
 import javax.validation.Validator;
 import javax.validation.ValidatorContext;
 
-import org.apache.bval.IntrospectorMetaBeanFactory;
-import org.apache.bval.MetaBeanBuilder;
-import org.apache.bval.MetaBeanFactory;
-import org.apache.bval.MetaBeanFinder;
-import org.apache.bval.MetaBeanManager;
-import org.apache.bval.util.reflection.Reflection;
-import org.apache.bval.xml.XMLMetaBeanBuilder;
-import org.apache.bval.xml.XMLMetaBeanFactory;
-import org.apache.bval.xml.XMLMetaBeanManager;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.reflect.ConstructorUtils;
-import org.apache.commons.weaver.privilizer.Privileged;
-import org.apache.commons.weaver.privilizer.Privilizing;
-import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
-
 /**
  * Description: Represents the context that is used to create
  * <code>ClassValidator</code> instances.<br/>
@@ -52,7 +37,7 @@
 @Privilizing(@CallTo(Reflection.class))
 public class ApacheFactoryContext implements ValidatorContext {
     private final ApacheValidatorFactory factory;
-    private final MetaBeanFinder metaBeanFinder;
+    private volatile MetaBeanFinder metaBeanFinder;
 
     private MessageInterpolator messageInterpolator;
     private TraversableResolver traversableResolver;
@@ -63,19 +48,9 @@
      * Create a new ApacheFactoryContext instance.
      * 
      * @param factory validator factory
-     */
-    public ApacheFactoryContext(ApacheValidatorFactory factory) {
-        this.factory = factory;
-        this.metaBeanFinder = buildMetaBeanFinder();
-    }
-
-    /**
-     * Create a new ApacheFactoryContext instance.
-     * 
-     * @param factory validator factory
      * @param metaBeanFinder meta finder
      */
-    protected ApacheFactoryContext(ApacheValidatorFactory factory, MetaBeanFinder metaBeanFinder) {
+    public ApacheFactoryContext(ApacheValidatorFactory factory, MetaBeanFinder metaBeanFinder) {
         this.factory = factory;
         this.metaBeanFinder = metaBeanFinder;
     }
@@ -99,11 +74,16 @@
         return metaBeanFinder;
     }
 
+    private synchronized void resetMeta() { // ensure to ingnore the cache and rebuild constraint with new model
+        metaBeanFinder = factory.buildMetaBeanFinder();
+    }
+
     /**
      * {@inheritDoc}
      */
     public ValidatorContext messageInterpolator(MessageInterpolator messageInterpolator) {
         this.messageInterpolator = messageInterpolator;
+        resetMeta();
         return this;
     }
 
@@ -112,6 +92,7 @@
      */
     public ValidatorContext traversableResolver(TraversableResolver traversableResolver) {
         this.traversableResolver = traversableResolver;
+        resetMeta();
         return this;
     }
 
@@ -120,11 +101,13 @@
      */
     public ValidatorContext constraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory) {
         this.constraintValidatorFactory = constraintValidatorFactory;
+        resetMeta();
         return this;
     }
 
     public ValidatorContext parameterNameProvider(ParameterNameProvider parameterNameProvider) {
         this.parameterNameProvider = parameterNameProvider;
+        resetMeta();
         return this;
     }
 
@@ -171,126 +154,4 @@
         return Boolean.parseBoolean(factory.getProperties().get(
             ApacheValidatorConfiguration.Properties.TREAT_MAPS_LIKE_BEANS));
     }
-
-    /**
-     * Create MetaBeanManager that uses factories:
-     * <ol>
-     * <li>if enabled by
-     * {@link ApacheValidatorConfiguration.Properties#ENABLE_INTROSPECTOR}, an
-     * {@link IntrospectorMetaBeanFactory}</li>
-     * <li>{@link MetaBeanFactory} types (if any) specified by
-     * {@link ApacheValidatorConfiguration.Properties#METABEAN_FACTORY_CLASSNAMES}
-     * </li>
-     * <li>if no {@link JsrMetaBeanFactory} has yet been specified (this
-     * allows factory order customization), a {@link JsrMetaBeanFactory}
-     * which handles both JSR303-XML and JSR303-Annotations</li>
-     * <li>if enabled by
-     * {@link ApacheValidatorConfiguration.Properties#ENABLE_METABEANS_XML}, an
-     * {@link XMLMetaBeanFactory}</li>
-     * </ol>
-     * 
-     * @return a new instance of MetaBeanManager with adequate MetaBeanFactories
-     */
-    protected MetaBeanFinder buildMetaBeanFinder() {
-        final List<MetaBeanFactory> builders = new ArrayList<MetaBeanFactory>();
-        if (Boolean.parseBoolean(factory.getProperties().get(
-            ApacheValidatorConfiguration.Properties.ENABLE_INTROSPECTOR))) {
-            builders.add(new IntrospectorMetaBeanFactory());
-        }
-        final String[] factoryClassNames =
-            StringUtils.split(factory.getProperties().get(
-                ApacheValidatorConfiguration.Properties.METABEAN_FACTORY_CLASSNAMES));
-        if (factoryClassNames != null) {
-            for (String clsName : factoryClassNames) {
-                // cast, relying on #createMetaBeanFactory to throw the exception if incompatible:
-                @SuppressWarnings("unchecked")
-                final Class<? extends MetaBeanFactory> factoryClass = (Class<? extends MetaBeanFactory>) loadClass(clsName);
-                builders.add(createMetaBeanFactory(factoryClass));
-            }
-        }
-        boolean jsrFound = false;
-        for (MetaBeanFactory builder : builders) {
-            jsrFound |= builder instanceof JsrMetaBeanFactory;
-        }
-        if (!jsrFound) {
-            builders.add(new JsrMetaBeanFactory(this));
-        }
-        @SuppressWarnings("deprecation")
-        final boolean enableMetaBeansXml =
-            Boolean.parseBoolean(factory.getProperties().get(
-                ApacheValidatorConfiguration.Properties.ENABLE_METABEANS_XML));
-        if (enableMetaBeansXml) {
-            XMLMetaBeanManagerCreator.addFactory(builders);
-        }
-        return createMetaBeanManager(builders);
-    }
-
-    /**
-     * Create a {@link MetaBeanManager} using the specified builders.
-     * 
-     * @param builders
-     *            {@link MetaBeanFactory} {@link List}
-     * @return {@link MetaBeanManager}
-     */
-    @SuppressWarnings("deprecation")
-    protected MetaBeanFinder createMetaBeanManager(List<MetaBeanFactory> builders) {
-        // as long as we support both: jsr (in the builders list) and xstream-xml metabeans:
-        if (Boolean.parseBoolean(factory.getProperties().get(
-            ApacheValidatorConfiguration.Properties.ENABLE_METABEANS_XML))) {
-            return XMLMetaBeanManagerCreator.createXMLMetaBeanManager(builders);
-        }
-        return new MetaBeanManager(new MetaBeanBuilder(builders.toArray(new MetaBeanFactory[builders.size()])));
-    }
-
-    @Privileged
-    private <F extends MetaBeanFactory> F createMetaBeanFactory(final Class<F> cls) {
-        try {
-            Constructor<F> c = ConstructorUtils.getMatchingAccessibleConstructor(cls, ApacheFactoryContext.this.getClass());
-            if (c != null) {
-                return c.newInstance(ApacheFactoryContext.this);
-            }
-            c = ConstructorUtils.getMatchingAccessibleConstructor(cls, getFactory().getClass());
-            if (c != null) {
-                return c.newInstance(getFactory());
-            }
-            return cls.newInstance();
-        } catch (Exception e) {
-            throw new ValidationException(e);
-        }
-    }
-
-    /**
-     * separate class to prevent the classloader to immediately load optional
-     * classes: XMLMetaBeanManager, XMLMetaBeanFactory, XMLMetaBeanBuilder that
-     * might not be available in the classpath
-     */
-    private static class XMLMetaBeanManagerCreator {
-
-        static void addFactory(List<MetaBeanFactory> builders) {
-            builders.add(new XMLMetaBeanFactory());
-        }
-
-        /**
-         * Create the {@link MetaBeanManager} to process JSR303 XML. Requires
-         * bval-xstream at RT.
-         * 
-         * @param builders meta bean builders
-         * @return {@link MetaBeanManager}
-         */
-        // NOTE - We return MetaBeanManager instead of XMLMetaBeanManager to
-        // keep
-        // bval-xstream an optional module.
-        protected static MetaBeanManager createXMLMetaBeanManager(List<MetaBeanFactory> builders) {
-            return new XMLMetaBeanManager(
-                new XMLMetaBeanBuilder(builders.toArray(new MetaBeanFactory[builders.size()])));
-        }
-    }
-
-    private Class<?> loadClass(final String className) {
-        try {
-            return Class.forName(className, true, Reflection.getClassLoader(ApacheFactoryContext.class));
-        } catch (ClassNotFoundException ex) {
-            throw new ValidationException("Unable to load class: " + className, ex);
-        }
-    }
 }
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java
index 5fd313a..f9b2743 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ApacheValidatorFactory.java
@@ -18,13 +18,24 @@
  */
 package org.apache.bval.jsr;
 
+import org.apache.bval.IntrospectorMetaBeanFactory;
+import org.apache.bval.MetaBeanBuilder;
+import org.apache.bval.MetaBeanFactory;
+import org.apache.bval.MetaBeanFinder;
+import org.apache.bval.MetaBeanManager;
 import org.apache.bval.jsr.xml.AnnotationIgnores;
 import org.apache.bval.jsr.xml.MetaConstraint;
 import org.apache.bval.jsr.xml.ValidationMappingParser;
 import org.apache.bval.util.AccessStrategy;
 import org.apache.bval.util.reflection.Reflection;
+import org.apache.bval.xml.XMLMetaBeanBuilder;
+import org.apache.bval.xml.XMLMetaBeanFactory;
+import org.apache.bval.xml.XMLMetaBeanManager;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.ClassUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.reflect.ConstructorUtils;
+import org.apache.commons.weaver.privilizer.Privileged;
 import org.apache.commons.weaver.privilizer.Privilizing;
 import org.apache.commons.weaver.privilizer.Privilizing.CallTo;
 
@@ -37,9 +48,9 @@
 import javax.validation.Validator;
 import javax.validation.ValidatorFactory;
 import javax.validation.spi.ConfigurationState;
-
 import java.io.Closeable;
 import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -80,6 +91,60 @@
     private final ConcurrentMap<Class<?>, List<MetaConstraint<?, ? extends Annotation>>> constraintMap;
 
     private final Collection<Closeable> toClose = new ArrayList<Closeable>();
+    private final MetaBeanFinder defaultMetaBeanFinder;
+
+    /**
+     * Create MetaBeanManager that uses factories:
+     * <ol>
+     * <li>if enabled by
+     * {@link ApacheValidatorConfiguration.Properties#ENABLE_INTROSPECTOR}, an
+     * {@link IntrospectorMetaBeanFactory}</li>
+     * <li>{@link MetaBeanFactory} types (if any) specified by
+     * {@link ApacheValidatorConfiguration.Properties#METABEAN_FACTORY_CLASSNAMES}
+     * </li>
+     * <li>if no {@link JsrMetaBeanFactory} has yet been specified (this
+     * allows factory order customization), a {@link JsrMetaBeanFactory}
+     * which handles both JSR303-XML and JSR303-Annotations</li>
+     * <li>if enabled by
+     * {@link ApacheValidatorConfiguration.Properties#ENABLE_METABEANS_XML}, an
+     * {@link XMLMetaBeanFactory}</li>
+     * </ol>
+     *
+     * @return a new instance of MetaBeanManager with adequate MetaBeanFactories
+     */
+    protected MetaBeanFinder buildMetaBeanFinder() {
+        final List<MetaBeanFactory> builders = new ArrayList<MetaBeanFactory>();
+        if (Boolean.parseBoolean(getProperties().get(
+                ApacheValidatorConfiguration.Properties.ENABLE_INTROSPECTOR))) {
+            builders.add(new IntrospectorMetaBeanFactory());
+        }
+        final String[] factoryClassNames =
+                StringUtils.split(getProperties().get(
+                        ApacheValidatorConfiguration.Properties.METABEAN_FACTORY_CLASSNAMES));
+        if (factoryClassNames != null) {
+            for (String clsName : factoryClassNames) {
+                // cast, relying on #createMetaBeanFactory to throw the exception if incompatible:
+                @SuppressWarnings("unchecked")
+                final Class<? extends MetaBeanFactory> factoryClass = (Class<? extends MetaBeanFactory>) loadClass(clsName);
+                builders.add(createMetaBeanFactory(factoryClass));
+            }
+        }
+        boolean jsrFound = false;
+        for (MetaBeanFactory builder : builders) {
+            jsrFound |= builder instanceof JsrMetaBeanFactory;
+        }
+        if (!jsrFound) {
+            builders.add(new JsrMetaBeanFactory(this));
+        }
+        @SuppressWarnings("deprecation")
+        final boolean enableMetaBeansXml =
+                Boolean.parseBoolean(getProperties().get(
+                        ApacheValidatorConfiguration.Properties.ENABLE_METABEANS_XML));
+        if (enableMetaBeansXml) {
+            XMLMetaBeanManagerCreator.addFactory(builders);
+        }
+        return createMetaBeanManager(builders);
+    }
 
     /**
      * Convenience method to retrieve a default global ApacheValidatorFactory
@@ -110,22 +175,11 @@
     /**
      * Create a new ApacheValidatorFactory instance.
      */
-    public ApacheValidatorFactory(ConfigurationState configurationState) {
-        properties = new HashMap<String, String>();
+    public ApacheValidatorFactory(ConfigurationState configuration) {
+        properties = new HashMap<String, String>(configuration.getProperties());
         defaultSequences = new HashMap<Class<?>, Class<?>[]>();
         validAccesses = new ConcurrentHashMap<Class<?>, List<AccessStrategy>>();
         constraintMap = new ConcurrentHashMap<Class<?>, List<MetaConstraint<?, ? extends Annotation>>>();
-        configure(configurationState);
-    }
-
-    /**
-     * Configure this {@link ApacheValidatorFactory} from a
-     * {@link ConfigurationState}.
-     *
-     * @param configuration
-     */
-    protected void configure(final ConfigurationState configuration) {
-        getProperties().putAll(configuration.getProperties());
 
         parameterNameProvider = configuration.getParameterNameProvider();
         messageResolver = configuration.getMessageInterpolator();
@@ -138,6 +192,8 @@
         }
 
         new ValidationMappingParser(this).processMappingConfig(configuration.getMappingStreams());
+
+        defaultMetaBeanFinder = buildMetaBeanFinder();
     }
 
     /**
@@ -165,7 +221,7 @@
      * @return the validator factory's context
      */
     public ApacheFactoryContext usingContext() {
-        return new ApacheFactoryContext(this);
+        return new ApacheFactoryContext(this, defaultMetaBeanFinder);
     }
 
     /**
@@ -428,4 +484,73 @@
     private static Class<?>[] safeArray(Class<?>... array) {
         return ArrayUtils.isEmpty(array) ? ArrayUtils.EMPTY_CLASS_ARRAY : ArrayUtils.clone(array);
     }
+
+    /**
+     * Create a {@link MetaBeanManager} using the specified builders.
+     *
+     * @param builders
+     *            {@link MetaBeanFactory} {@link List}
+     * @return {@link MetaBeanManager}
+     */
+    @SuppressWarnings("deprecation")
+    protected MetaBeanFinder createMetaBeanManager(List<MetaBeanFactory> builders) {
+        // as long as we support both: jsr (in the builders list) and xstream-xml metabeans:
+        if (Boolean.parseBoolean(getProperties().get(
+                ApacheValidatorConfiguration.Properties.ENABLE_METABEANS_XML))) {
+            return XMLMetaBeanManagerCreator.createXMLMetaBeanManager(builders);
+        }
+        return new MetaBeanManager(new MetaBeanBuilder(builders.toArray(new MetaBeanFactory[builders.size()])));
+    }
+
+    @Privileged
+    private <F extends MetaBeanFactory> F createMetaBeanFactory(final Class<F> cls) {
+        try {
+            Constructor<F> c = ConstructorUtils.getMatchingAccessibleConstructor(cls, ApacheValidatorFactory.this.getClass());
+            if (c != null) {
+                return c.newInstance(this);
+            }
+            c = ConstructorUtils.getMatchingAccessibleConstructor(cls, getClass());
+            if (c != null) {
+                return c.newInstance(this);
+            }
+            return cls.newInstance();
+        } catch (Exception e) {
+            throw new ValidationException(e);
+        }
+    }
+
+    /**
+     * separate class to prevent the classloader to immediately load optional
+     * classes: XMLMetaBeanManager, XMLMetaBeanFactory, XMLMetaBeanBuilder that
+     * might not be available in the classpath
+     */
+    private static class XMLMetaBeanManagerCreator {
+
+        static void addFactory(List<MetaBeanFactory> builders) {
+            builders.add(new XMLMetaBeanFactory());
+        }
+
+        /**
+         * Create the {@link MetaBeanManager} to process JSR303 XML. Requires
+         * bval-xstream at RT.
+         *
+         * @param builders meta bean builders
+         * @return {@link MetaBeanManager}
+         */
+        // NOTE - We return MetaBeanManager instead of XMLMetaBeanManager to
+        // keep
+        // bval-xstream an optional module.
+        protected static MetaBeanManager createXMLMetaBeanManager(List<MetaBeanFactory> builders) {
+            return new XMLMetaBeanManager(
+                    new XMLMetaBeanBuilder(builders.toArray(new MetaBeanFactory[builders.size()])));
+        }
+    }
+
+    private Class<?> loadClass(final String className) {
+        try {
+            return Class.forName(className, true, Reflection.getClassLoader(ApacheValidatorFactory.class));
+        } catch (ClassNotFoundException ex) {
+            throw new ValidationException("Unable to load class: " + className, ex);
+        }
+    }
 }
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/BeanDescriptorImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/BeanDescriptorImpl.java
index df7f911..2b80d50 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/BeanDescriptorImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/BeanDescriptorImpl.java
@@ -51,7 +51,6 @@
 import javax.validation.metadata.ParameterDescriptor;
 import javax.validation.metadata.PropertyDescriptor;
 import javax.validation.metadata.ReturnValueDescriptor;
-
 import java.beans.Introspector;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.AccessibleObject;
@@ -329,7 +328,7 @@
         private ExecutableMeta(final ApacheFactoryContext factoryContext, final MetaBean metaBean1, final Collection<ConstraintDescriptor<?>> constraintDescriptors) {
             this.metaBean = metaBean1;
             this.factoryContext = factoryContext;
-            this.annotationProcessor = new AnnotationProcessor(factoryContext);
+            this.annotationProcessor = new AnnotationProcessor(factoryContext.getFactory());
 
             buildExecutableDescriptors();
 
@@ -840,7 +839,9 @@
                     }
                 }
             } else {
-                annotationProcessor.processAnnotation(annotation, null, ClassUtils.primitiveToWrapper((Class<?>) access.getJavaType()), access, validations, true);
+                annotationProcessor.processAnnotation(
+                        annotation, null, ClassUtils.primitiveToWrapper((Class<?>) access.getJavaType()),
+                        access, validations, true);
             }
         }
 
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ClassValidator.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ClassValidator.java
index 7ee0053..e1c1dd3 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ClassValidator.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ClassValidator.java
@@ -638,8 +638,9 @@
     protected <T> GroupValidationContext<T> createContext(MetaBean metaBean, T object, Class<T> objectClass, Class<?>... groups) {
         final ConstraintValidationListener<T> listener = new ConstraintValidationListener<T>(object, objectClass);
         final GroupValidationContextImpl<T> context =
-            new GroupValidationContextImpl<T>(listener, this.factoryContext.getMessageInterpolator(),
-                this.factoryContext.getTraversableResolver(), factoryContext.getParameterNameProvider(), metaBean);
+            new GroupValidationContextImpl<T>(listener, factoryContext.getMessageInterpolator(),
+                factoryContext.getTraversableResolver(), factoryContext.getParameterNameProvider(),
+                factoryContext.getConstraintValidatorFactory(), metaBean);
         context.setBean(object, metaBean);
         context.setGroups(groupsComputer.computeGroups(groups));
         return context;
@@ -648,8 +649,9 @@
     protected <T> GroupValidationContext<T> createInvocableContext(MetaBean metaBean, T object, Class<T> objectClass, Class<?>... groups) {
         final ConstraintValidationListener<T> listener = new ConstraintValidationListener<T>(object, objectClass);
         final GroupValidationContextImpl<T> context =
-                new GroupValidationContextImpl<T>(listener, this.factoryContext.getMessageInterpolator(),
-                        this.factoryContext.getTraversableResolver(), factoryContext.getParameterNameProvider(), metaBean);
+                new GroupValidationContextImpl<T>(listener, factoryContext.getMessageInterpolator(),
+                        factoryContext.getTraversableResolver(), factoryContext.getParameterNameProvider(),
+                        factoryContext.getConstraintValidatorFactory(), metaBean);
         context.setBean(object, metaBean);
         final Groups computedGroup = groupsComputer.computeGroups(groups);
         if (Collections.singletonList(Group.DEFAULT).equals(computedGroup.getGroups()) && metaBean.getFeature(JsrFeatures.Bean.GROUP_SEQUENCE) != null) {
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidation.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidation.java
index 2b58c12..0ce7248 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidation.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ConstraintValidation.java
@@ -39,7 +39,6 @@
 import javax.validation.constraintvalidation.SupportedValidationTarget;
 import javax.validation.constraintvalidation.ValidationTarget;
 import javax.validation.metadata.ConstraintDescriptor;
-
 import java.io.Serializable;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Array;
@@ -61,7 +60,6 @@
  * this instance is immutable!<br/>
  */
 public class ConstraintValidation<T extends Annotation> implements Validation, ConstraintDescriptor<T> {
-    private final ConstraintValidatorFactory factory;
     private final AccessStrategy access;
     private final boolean reportFromComposite;
     private final Map<String, Object> attributes;
@@ -82,11 +80,9 @@
     private Class<? extends ConstraintValidator<T, ?>>[] validatorClasses;
     private ConstraintTarget validationAppliesTo = null;
 
-    public ConstraintValidation(ConstraintValidatorFactory factory,
-                                Class<? extends ConstraintValidator<T, ?>>[] validatorClasses,
+    public ConstraintValidation(Class<? extends ConstraintValidator<T, ?>>[] validatorClasses,
                                 T annotation, Class<?> owner, AccessStrategy access,
                                 boolean reportFromComposite, ConstraintTarget target) {
-        this.factory = factory;
         this.attributes = new HashMap<String, Object>();
         this.validatorClasses = ArrayUtils.clone(validatorClasses);
         this.annotation = annotation;
@@ -158,7 +154,8 @@
             synchronized (this) {
                 if (validator == null) {
                     try {
-                        validator = getConstraintValidator(annotation, validatorClasses, owner, access);
+                        validator = getConstraintValidator(
+                                context.getConstraintValidatorFactory(), annotation, validatorClasses, owner, access);
                         if (validator != null) {
                             validator.initialize(annotation);
                         }
@@ -235,7 +232,8 @@
         }
     }
 
-    private <A extends Annotation> ConstraintValidator<A, ? super T> getConstraintValidator(A annotation,
+    private <A extends Annotation> ConstraintValidator<A, ? super T> getConstraintValidator(
+            ConstraintValidatorFactory factory, A annotation,
         Class<? extends ConstraintValidator<A, ?>>[] constraintClasses, Class<?> owner, AccessStrategy access) {
         if (ArrayUtils.isNotEmpty(constraintClasses)) {
             final Type type = determineTargetedType(owner, access);
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContext.java b/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContext.java
index f3a57a5..70a53f0 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContext.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContext.java
@@ -24,6 +24,7 @@
 import org.apache.bval.model.ValidationContext;
 
 import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorFactory;
 import javax.validation.ElementKind;
 import javax.validation.MessageInterpolator;
 import javax.validation.ParameterNameProvider;
@@ -107,6 +108,12 @@
     TraversableResolver getTraversableResolver();
 
     /**
+     * Get the {@link ConstraintValidatorFactory}.
+     * @return {@link ConstraintValidatorFactory}
+     */
+    ConstraintValidatorFactory getConstraintValidatorFactory();
+
+    /**
      * Accumulate a validated constraint.
      * @param constraint
      * @return true when the constraint for the object in this path was not
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContextImpl.java b/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContextImpl.java
index 778c5d2..2791a25 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContextImpl.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/GroupValidationContextImpl.java
@@ -27,6 +27,7 @@
 import org.apache.bval.util.AccessStrategy;
 
 import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorFactory;
 import javax.validation.ElementKind;
 import javax.validation.MessageInterpolator;
 import javax.validation.ParameterNameProvider;
@@ -70,6 +71,7 @@
 
     private ConstraintValidation<?> constraintValidation;
     private final TraversableResolver traversableResolver;
+    private final ConstraintValidatorFactory constraintValidatorFactory;
 
     private Object[] parameters;
     private Object returnValue;
@@ -86,11 +88,14 @@
      * @param rootMetaBean
      */
     public GroupValidationContextImpl(ConstraintValidationListener<T> listener, MessageInterpolator aMessageResolver,
-                                      TraversableResolver traversableResolver, ParameterNameProvider parameterNameProvider, MetaBean rootMetaBean) {
+                                      TraversableResolver traversableResolver, ParameterNameProvider parameterNameProvider,
+                                      ConstraintValidatorFactory constraintValidatorFactory,
+                                      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.constraintValidatorFactory = constraintValidatorFactory;
         this.traversableResolver = CachingTraversableResolver.cacheFor(traversableResolver);
         this.parameterNameProvider = parameterNameProvider;
         this.rootMetaBean = rootMetaBean;
@@ -313,6 +318,11 @@
         return traversableResolver;
     }
 
+    @Override
+    public ConstraintValidatorFactory getConstraintValidatorFactory() {
+        return constraintValidatorFactory;
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/JsrMetaBeanFactory.java b/bval-jsr/src/main/java/org/apache/bval/jsr/JsrMetaBeanFactory.java
index 68f9346..b86c8d8 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/JsrMetaBeanFactory.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/JsrMetaBeanFactory.java
@@ -63,8 +63,8 @@
     // 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 javax.validation.ValidatorFactory} used */
+    protected final ApacheValidatorFactory factory;
 
     /**
      * {@link AnnotationProcessor} used.
@@ -74,11 +74,11 @@
     /**
      * Create a new Jsr303MetaBeanFactory instance.
      * 
-     * @param factoryContext
+     * @param factory the validator factory.
      */
-    public JsrMetaBeanFactory(ApacheFactoryContext factoryContext) {
-        this.factoryContext = factoryContext;
-        this.annotationProcessor = new AnnotationProcessor(factoryContext);
+    public JsrMetaBeanFactory(ApacheValidatorFactory factory) {
+        this.factory = factory;
+        this.annotationProcessor = new AnnotationProcessor(factory);
     }
 
     /**
@@ -123,7 +123,7 @@
         InvocationTargetException {
 
         // if NOT ignore class level annotations
-        if (!factoryContext.getFactory().getAnnotationIgnores().isIgnoreAnnotations(beanClass)) {
+        if (!factory.getAnnotationIgnores().isIgnoreAnnotations(beanClass)) {
             annotationProcessor.processAnnotations(null, beanClass, beanClass, null, new AppendValidationToMeta(metabean));
         }
 
@@ -134,7 +134,7 @@
             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)) {
+            if (!factory.getAnnotationIgnores().isIgnoreAnnotations(field)) {
                 AccessStrategy access = new FieldAccess(field);
                 boolean create = metaProperty == null;
                 if (create) {
@@ -160,7 +160,7 @@
                 propName = MethodAccess.getPropertyName(method);
             }
             if (propName != null) {
-                if (!factoryContext.getFactory().getAnnotationIgnores().isIgnoreAnnotations(method)) {
+                if (!factory.getAnnotationIgnores().isIgnoreAnnotations(method)) {
                     AccessStrategy access = new MethodAccess(propName, method);
                     MetaProperty metaProperty = metabean.getProperty(propName);
                     boolean create = metaProperty == null;
@@ -198,7 +198,7 @@
      */
     private void addXmlConstraints(Class<?> beanClass, MetaBean metabean) throws IllegalAccessException,
         InvocationTargetException {
-        for (final MetaConstraint<?, ? extends Annotation> metaConstraint : factoryContext.getFactory().getMetaConstraints(beanClass)) {
+        for (final MetaConstraint<?, ? extends Annotation> metaConstraint : factory.getMetaConstraints(beanClass)) {
             Meta meta;
             AccessStrategy access = metaConstraint.getAccessStrategy();
             boolean create = false;
@@ -263,7 +263,7 @@
                 metabean.putProperty(access.getPropertyName(), null);
             }
         }
-        for (final AccessStrategy access : factoryContext.getFactory().getValidAccesses(beanClass)) {
+        for (final AccessStrategy access : factory.getValidAccesses(beanClass)) {
             if (access.getElementType() == ElementType.PARAMETER) {
                 continue;
             }
@@ -289,7 +289,7 @@
         if (groupSeq == null) {
             groupSeq = metabean.initFeature(key, new ArrayList<Group>(annotation == null ? 1 : annotation.value().length));
         }
-        Class<?>[] groupClasses = factoryContext.getFactory().getDefaultSequence(beanClass);
+        Class<?>[] groupClasses = factory.getDefaultSequence(beanClass);
         if (groupClasses == null || groupClasses.length == 0) {
             if (annotation == null) {
                 groupSeq.add(Group.DEFAULT);
diff --git a/bval-jsr/src/test/java/org/apache/bval/jsr/ValidationTest.java b/bval-jsr/src/test/java/org/apache/bval/jsr/ValidationTest.java
index b0fa685..0419d4a 100644
--- a/bval-jsr/src/test/java/org/apache/bval/jsr/ValidationTest.java
+++ b/bval-jsr/src/test/java/org/apache/bval/jsr/ValidationTest.java
@@ -89,6 +89,10 @@
         return factory.getValidator();
     }
 
+    public void testCache() {
+        factory.getValidator().getConstraintsForClass(AccessTestBusinessObject.class);
+        factory.getValidator().getConstraintsForClass(AccessTestBusinessObject.class);
+    }
     public void testAccessStrategies_field_method() {
         AccessTestBusinessObject o1 = new AccessTestBusinessObject("1");
         AccessTestBusinessObjectSub o2 = new AccessTestBusinessObjectSub("3");
diff --git a/bval-tck/pom.xml b/bval-tck/pom.xml
index 2521b04..249276b 100644
--- a/bval-tck/pom.xml
+++ b/bval-tck/pom.xml
@@ -169,6 +169,55 @@
                     <version>1.0.0</version>
                 </dependency>
             </dependencies>
+            <repositories>
+                <repository>
+                    <!-- override outdated URLs for jboss repo ids -->
+                    <id>repository.jboss.org</id>
+                    <name>JBoss Public Maven Repository Group</name>
+                    <url>https://repository.jboss.org/nexus/content/groups/public/</url>
+                    <layout>default</layout>
+                    <releases>
+                        <enabled>true</enabled>
+                        <updatePolicy>never</updatePolicy>
+                        <checksumPolicy>fail</checksumPolicy>
+                    </releases>
+                    <snapshots>
+                        <enabled>false</enabled>
+                        <updatePolicy>never</updatePolicy>
+                        <checksumPolicy>warn</checksumPolicy>
+                    </snapshots>
+                </repository>
+                <repository>
+                    <id>jboss</id>
+                    <name>JBoss Public Maven Repository Group (again)</name>
+                    <url>https://repository.jboss.org/nexus/content/groups/public/</url>
+                    <layout>default</layout>
+                    <releases>
+                        <enabled>true</enabled>
+                        <updatePolicy>never</updatePolicy>
+                        <checksumPolicy>fail</checksumPolicy>
+                    </releases>
+                    <snapshots>
+                        <enabled>false</enabled>
+                        <updatePolicy>never</updatePolicy>
+                        <checksumPolicy>warn</checksumPolicy>
+                    </snapshots>
+                </repository>
+                <repository>
+                    <id>snapshots.jboss.org</id>
+                    <url>https://repository.jboss.org/nexus/content/repositories/snapshots/</url>
+                    <snapshots>
+                        <enabled>true</enabled>
+                    </snapshots>
+                </repository>
+                <repository>
+                    <id>jboss-snapshots</id>
+                    <url>https://repository.jboss.org/nexus/content/repositories/snapshots/</url>
+                    <snapshots>
+                        <enabled>true</enabled>
+                    </snapshots>
+                </repository>
+            </repositories>
             <build>
                 <plugins>
                     <plugin>
diff --git a/pom.xml b/pom.xml
index fb4f2b7..d60115c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -571,6 +571,7 @@
                     <artifactId>commons-weaver-maven-plugin</artifactId>
                     <version>${commons.weaver.version}</version>
                     <configuration>
+                        <verbose>true</verbose>
                         <weaverConfig>
                             <privilizer.policy>DYNAMIC</privilizer.policy>
                         </weaverConfig>