You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rm...@apache.org on 2014/10/06 09:26:04 UTC

svn commit: r1629582 - in /tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb: assembler/classic/ bval/

Author: rmannibucau
Date: Mon Oct  6 07:26:04 2014
New Revision: 1629582

URL: http://svn.apache.org/r1629582
Log:
TOMEE-1381 passing good ValidatorFactory property to JPA

Added:
    tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ComparableValidationConfig.java
    tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/LazyValidatorFactory.java
Modified:
    tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
    tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/EntityManagerFactoryCallable.java
    tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/LazyValidator.java
    tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/PersistenceBuilder.java
    tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ValidatorFactoryWrapper.java
    tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/bval/ValidatorUtil.java

Modified: tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
URL: http://svn.apache.org/viewvc/tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java?rev=1629582&r1=1629581&r2=1629582&view=diff
==============================================================================
--- tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java (original)
+++ tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java Mon Oct  6 07:26:04 2014
@@ -36,16 +36,13 @@ import org.apache.openejb.Injection;
 import org.apache.openejb.JndiConstants;
 import org.apache.openejb.MethodContext;
 import org.apache.openejb.NoSuchApplicationException;
-import org.apache.openejb.OpenEJB;
 import org.apache.openejb.OpenEJBException;
 import org.apache.openejb.OpenEJBRuntimeException;
 import org.apache.openejb.UndeployException;
-import org.apache.openejb.api.DestroyableResource;
 import org.apache.openejb.assembler.classic.event.AssemblerAfterApplicationCreated;
 import org.apache.openejb.assembler.classic.event.AssemblerBeforeApplicationDestroyed;
 import org.apache.openejb.assembler.classic.event.AssemblerCreated;
 import org.apache.openejb.assembler.classic.event.AssemblerDestroyed;
-import org.apache.openejb.assembler.classic.event.BeanContextsInitializedEvent;
 import org.apache.openejb.assembler.classic.event.ContainerSystemPostCreate;
 import org.apache.openejb.assembler.classic.event.ContainerSystemPreDestroy;
 import org.apache.openejb.assembler.monitoring.JMXContainer;
@@ -95,7 +92,6 @@ import org.apache.openejb.jpa.integratio
 import org.apache.openejb.loader.IO;
 import org.apache.openejb.loader.JarLocation;
 import org.apache.openejb.loader.Options;
-import org.apache.openejb.loader.ProvisioningUtil;
 import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.monitoring.DynamicMBeanWrapper;
 import org.apache.openejb.monitoring.LocalMBeanServer;
@@ -227,7 +223,8 @@ public class Assembler extends Assembler
     public static final String TIMER_STORE_CLASS = "timerStore.class";
     private static final ReentrantLock lock = new ReentrantLock(true);
     public static final String OPENEJB_TIMERS_ON = "openejb.timers.on";
-
+    public static final Class<?>[] VALIDATOR_FACTORY_INTERFACES = new Class<?>[]{ValidatorFactory.class};
+    public static final Class<?>[] VALIDATOR_INTERFACES = new Class<?>[]{Validator.class};
     private final boolean skipLoaderIfPossible;
 
     Messages messages = new Messages(Assembler.class.getPackage().getName());
@@ -325,8 +322,6 @@ public class Assembler extends Assembler
             final Collection<URL> urls = NewLoaderLogic.applyBuiltinExcludes(new UrlSet(Assembler.class.getClassLoader()).excludeJvm()).getUrls();
             Extensions.installExtensions(new ResourceFinder("META-INF", urls.toArray(new URL[urls.size()])));
             return;
-        } catch (final MalformedURLException e) {
-            // no-op
         } catch (final IOException e) {
             // no-op
         }
@@ -475,8 +470,9 @@ public class Assembler extends Assembler
      */
     @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
     public void buildContainerSystem(final OpenEjbConfiguration configInfo) throws Exception {
-        if (SystemInstance.get().getOptions().get(OPENEJB_JPA_DEPLOY_TIME_ENHANCEMENT_PROP, false)) {
-            SystemInstance.get().addObserver(new DeployTimeEnhancer());
+        final SystemInstance systemInstance = SystemInstance.get();
+        if (systemInstance.getOptions().get(OPENEJB_JPA_DEPLOY_TIME_ENHANCEMENT_PROP, false)) {
+            systemInstance.addObserver(new DeployTimeEnhancer());
         }
 
         for (final ServiceInfo serviceInfo : configInfo.facilities.services) {
@@ -517,14 +513,14 @@ public class Assembler extends Assembler
             } catch (final Throwable e) {
                 logger.error("appNotDeployed", e, appInfo.path);
 
-                final DeploymentExceptionManager exceptionManager = SystemInstance.get().getComponent(DeploymentExceptionManager.class);
+                final DeploymentExceptionManager exceptionManager = systemInstance.getComponent(DeploymentExceptionManager.class);
                 if (exceptionManager != null && e instanceof Exception) {
                     exceptionManager.saveDeploymentException(appInfo, (Exception) e);
                 }
             }
         }
 
-        SystemInstance.get().fireEvent(new ContainerSystemPostCreate());
+        systemInstance.fireEvent(new ContainerSystemPostCreate());
     }
 
     private void createJavaGlobal() {
@@ -535,10 +531,6 @@ public class Assembler extends Assembler
         }
     }
 
-    public boolean isDeployed(final String path) {
-        return deployedApplications.containsKey(ProvisioningUtil.realLocation(path));
-    }
-
     public Collection<AppInfo> getDeployedApplications() {
         return new ArrayList<AppInfo>(deployedApplications.values());
     }
@@ -623,7 +615,7 @@ public class Assembler extends Assembler
         return createApplication(appInfo, classLoader, true);
     }
 
-    public AppContext createApplication(final AppInfo appInfo, ClassLoader classLoader, final boolean start) throws OpenEJBException, IOException, NamingException {
+    private AppContext createApplication(final AppInfo appInfo, ClassLoader classLoader, final boolean start) throws OpenEJBException, IOException, NamingException {
         // The path is used in the UrlCache, command line deployer, JNDI name templates, tomcat integration and a few other places
         if (appInfo.appId == null) {
             throw new IllegalArgumentException("AppInfo.appId cannot be null");
@@ -636,13 +628,6 @@ public class Assembler extends Assembler
 
         logger.info("createApplication.start", appInfo.path);
 
-        //        try {
-        //            Thread.sleep(5000);
-        //        } catch (InterruptedException e) {
-        //            e.printStackTrace();
-        //            Thread.interrupted();
-        //        }
-
         // To start out, ensure we don't already have any beans deployed with duplicate IDs.  This
         // is a conflict we can't handle.
         final List<String> used = new ArrayList<String>();
@@ -698,23 +683,41 @@ public class Assembler extends Assembler
 
             final Context containerSystemContext = containerSystem.getJNDIContext();
 
-            if (!SystemInstance.get().hasProperty("openejb.geronimo")) {
+            final Map<String, LazyValidatorFactory> lazyValidatorFactories = new HashMap<String, LazyValidatorFactory>();
+            final Map<String, LazyValidator> lazyValidators = new HashMap<String, LazyValidator>();
+            final boolean isGeronimo = SystemInstance.get().hasProperty("openejb.geronimo");
+
+            // try to not create N times the same validator for a single app
+            final Map<ComparableValidationConfig, ValidatorFactory> validatorFactoriesByConfig = new HashMap<ComparableValidationConfig, ValidatorFactory>();
+            if (!isGeronimo) {
                 // Bean Validation
                 // ValidatorFactory needs to be put in the map sent to the entity manager factory
                 // so it has to be constructed before
                 final List<CommonInfoObject> vfs = listCommonInfoObjectsForAppInfo(appInfo);
-
                 final Map<String, ValidatorFactory> validatorFactories = new HashMap<String, ValidatorFactory>();
+
                 for (final CommonInfoObject info : vfs) {
-                    ValidatorFactory factory = null;
-                    try {
-                        factory = ValidatorBuilder.buildFactory(classLoader, info.validationInfo);
-                    } catch (final ValidationException ve) {
-                        logger.warning("can't build the validation factory for module " + info.uniqueId, ve);
-                    }
-                    if (factory != null) {
-                        validatorFactories.put(info.uniqueId, factory);
+                    final ComparableValidationConfig conf = new ComparableValidationConfig(
+                            info.validationInfo.providerClassName, info.validationInfo.messageInterpolatorClass,
+                            info.validationInfo.traversableResolverClass, info.validationInfo.constraintFactoryClass,
+                            info.validationInfo.propertyTypes, info.validationInfo.constraintMappings
+                    );
+                    ValidatorFactory factory = validatorFactoriesByConfig.get(conf);
+                    if (factory == null) {
+                        try { // lazy cause of CDI :(
+                            final LazyValidatorFactory handler = new LazyValidatorFactory(classLoader, info.validationInfo);
+                            factory = (ValidatorFactory) Proxy.newProxyInstance(
+                                    appContext.getClassLoader(), VALIDATOR_FACTORY_INTERFACES, handler);
+                            lazyValidatorFactories.put(info.uniqueId, handler);
+                        } catch (final ValidationException ve) {
+                            logger.warning("can't build the validation factory for module " + info.uniqueId, ve);
+                            continue;
+                        }
+                        validatorFactoriesByConfig.put(conf, factory);
+                    } else {
+                        lazyValidatorFactories.put(info.uniqueId, LazyValidatorFactory.class.cast(Proxy.getInvocationHandler(factory)));
                     }
+                    validatorFactories.put(info.uniqueId, factory);
                 }
 
                 // validators bindings
@@ -726,9 +729,12 @@ public class Assembler extends Assembler
 
                         Validator validator;
                         try {
-                            validator = factory.usingContext().getValidator();
+                            final LazyValidator lazyValidator = new LazyValidator(factory);
+                            validator = (Validator) Proxy.newProxyInstance(appContext.getClassLoader(), VALIDATOR_INTERFACES, lazyValidator);
+                            lazyValidators.put(id, lazyValidator);
                         } catch (final Exception e) {
-                            validator = (Validator) Proxy.newProxyInstance(appContext.getClassLoader(), new Class<?>[]{Validator.class}, new LazyValidator(factory));
+                            logger.error(e.getMessage(), e);
+                            continue;
                         }
 
                         containerSystemContext.bind(VALIDATOR_NAMING_CONTEXT + id, validator);
@@ -738,6 +744,8 @@ public class Assembler extends Assembler
                         throw new OpenEJBException(e);
                     }
                 }
+
+                validatorFactories.clear();
             }
 
             // JPA - Persistence Units MUST be processed first since they will add ClassFileTransformers
@@ -747,7 +755,7 @@ public class Assembler extends Assembler
             for (final PersistenceUnitInfo info : appInfo.persistenceUnits) {
                 final ReloadableEntityManagerFactory factory;
                 try {
-                    factory = persistenceBuilder.createEntityManagerFactory(info, classLoader);
+                    factory = persistenceBuilder.createEntityManagerFactory(info, classLoader, validatorFactoriesByConfig);
                     containerSystem.getJNDIContext().bind(PERSISTENCE_UNIT_NAMING_CONTEXT + info.id, factory);
                     units.put(info.name, PERSISTENCE_UNIT_NAMING_CONTEXT + info.id);
                 } catch (final NameAlreadyBoundException e) {
@@ -800,9 +808,31 @@ public class Assembler extends Assembler
                 appContext.getBindings().put("app/BeanManager", appContext.getBeanManager());
             }
 
-            // before starting everything, give the user the opportunity to hack on the AppContext/BeanContext
-            final SystemInstance systemInstance = SystemInstance.get();
-            systemInstance.fireEvent(new BeanContextsInitializedEvent(appInfo, appContext, allDeployments));
+            // now cdi is started we can try to bind real validator factory and validator
+            if (!isGeronimo) {
+                for (final Entry<String, LazyValidator> lazyValidator : lazyValidators.entrySet()) {
+                    final String id = lazyValidator.getKey();
+                    final ValidatorFactory factory = lazyValidatorFactories.get(lazyValidator.getKey()).getFactory();
+                    try {
+                        final String factoryName = VALIDATOR_FACTORY_NAMING_CONTEXT + id;
+                        containerSystemContext.unbind(factoryName);
+                        containerSystemContext.bind(factoryName, factory);
+
+                        final String validatoryName = VALIDATOR_NAMING_CONTEXT + id;
+                        try { // do it after factory cause of TCKs which expects validator to be created later
+                            final Validator val = lazyValidator.getValue().getValidator();
+                            containerSystemContext.unbind(validatoryName);
+                            containerSystemContext.bind(validatoryName, val);
+                        } catch (final Exception e) {
+                            logger.error(e.getMessage(), e);
+                        }
+                    } catch (final NameAlreadyBoundException e) {
+                        throw new OpenEJBException("ValidatorFactory already exists for module " + id, e);
+                    } catch (final Exception e) {
+                        throw new OpenEJBException(e);
+                    }
+                }
+            }
 
             startEjbs(start, allDeployments);
 
@@ -849,6 +879,7 @@ public class Assembler extends Assembler
             }
 
             // WebApp
+            final SystemInstance systemInstance = SystemInstance.get();
 
             final WebAppBuilder webAppBuilder = systemInstance.getComponent(WebAppBuilder.class);
             if (webAppBuilder != null) {
@@ -1245,7 +1276,7 @@ public class Assembler extends Assembler
         }else{
             if(null == appContext.getWebBeansContext()){
                 appContext.setWebBeansContext(webBeansContext);
-            }
+        }
 
             return;
         }
@@ -1272,9 +1303,9 @@ public class Assembler extends Assembler
             appContext.setCdiEnabled(false);
             OpenEJBTransactionService.class.cast(services.get(TransactionService.class)).setWebBeansContext(webBeansContext);
 
-            appContext.set(WebBeansContext.class, webBeansContext);
-            appContext.setWebBeansContext(webBeansContext);
-        }
+        appContext.set(WebBeansContext.class, webBeansContext);
+        appContext.setWebBeansContext(webBeansContext);
+    }
     }
 
     private TransactionPolicyFactory createTransactionPolicyFactory(final EjbJarInfo ejbJar, final ClassLoader classLoader) {
@@ -1494,12 +1525,6 @@ public class Assembler extends Assembler
             } catch (final Exception e) {
                 logger.debug("Not processing resource on destroy: " + className, e);
             }
-        } else if (DestroyableResource.class.isInstance(object)) {
-            try {
-                DestroyableResource.class.cast(object).destroyResource();
-            } catch (final RuntimeException e) {
-                logger.error(e.getMessage(), e);
-            }
         } else if (logger.isDebugEnabled() && !DataSource.class.isInstance(object)) {
             logger.debug("Not processing resource on destroy: " + className);
         }
@@ -1917,11 +1942,7 @@ public class Assembler extends Assembler
         jars.addAll(Arrays.asList(SystemInstance.get().getComponent(ClassLoaderEnricher.class).applicationEnrichment()));
 
         // Create the class loader
-        final ParentClassLoaderFinder parentFinder = SystemInstance.get().getComponent(ParentClassLoaderFinder.class);
-        ClassLoader parent = OpenEJB.class.getClassLoader();
-        if (parentFinder != null) {
-            parent = parentFinder.getParentClassLoader(parent);
-        }
+        final ClassLoader parent = ParentClassLoaderFinder.Helper.get();
 
         final String prefix;
         if (appInfo.webAppAlone) {
@@ -1943,7 +1964,11 @@ public class Assembler extends Assembler
         // try to get the app BM from the AppClassLoader having stored it in a map).
         // since we don't really need to create a classloader here when starting from classpath just let skip this step
         if (skipLoaderIfPossible) { // TODO: maybe use a boolean to know if all urls comes from the classpath to avoid this validation
-            final Collection<File> urls = new ArrayList<File>();
+            if ("classpath.ear".equals(appInfo.appId)) {
+                return parent;
+            }
+
+            final Collection<File> urls = new HashSet<File>();
             for (final URL url : ClassLoaders.findUrls(parent)) { // need to convert it to file since urls can be file:/xxx or jar:file:///xxx
                 try {
                     urls.add(URLs.toFile(url).getCanonicalFile());
@@ -1959,24 +1984,38 @@ public class Assembler extends Assembler
                 try {
                     if (!urls.contains(URLs.toFile(url).getCanonicalFile())) {
                         allIsIntheClasspath = false;
+                        if (logger.isDebugEnabled()) {
+                            logger.debug(url.toExternalForm() + " (" + URLs.toFile(url)
+                                + ") is not in the classloader so we'll create a dedicated classloader for this app");
+                        }
                         break;
                     }
                 } catch (final Exception ignored) {
                     allIsIntheClasspath = false;
+                    if (logger.isDebugEnabled()) {
+                        logger.debug(url.toExternalForm() + " (" + URLs.toFile(url) + ") is not in the classloader", ignored);
+                    }
                     break;
                 }
             }
 
             if (allIsIntheClasspath) {
+                logger.info("Not creating another application classloader for " + appInfo.appId);
                 return parent;
             } else if (logger.isDebugEnabled()) {
                 logger.debug("Logging all urls from the app since we don't skip the app classloader creation:");
                 for (final URL url : filtered) {
                     logger.debug(" -> " + url.toExternalForm());
                 }
+                logger.debug("Logging all urls from the classloader since we don't skip the app classloader creation:");
+                for (final File url : urls) {
+                    logger.debug(" -> " + url.getAbsolutePath());
+                }
             }
         }
 
+        logger.info("Creating dedicated application classloader for " + appInfo.appId);
+
         if (!appInfo.delegateFirst) {
             return ClassLoaderUtil.createClassLoader(appInfo.path, filtered, parent);
         }
@@ -2048,7 +2087,7 @@ public class Assembler extends Assembler
                 containerObjectNames.add(objectName);
             } catch (final Exception e) {
                 // no-op
-            } catch (final NoClassDefFoundError ncdfe) { // OSGi
+            } catch (final NoClassDefFoundError ncdfe) {
                 // no-op
             }
         }

Added: tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ComparableValidationConfig.java
URL: http://svn.apache.org/viewvc/tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ComparableValidationConfig.java?rev=1629582&view=auto
==============================================================================
--- tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ComparableValidationConfig.java (added)
+++ tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ComparableValidationConfig.java Mon Oct  6 07:26:04 2014
@@ -0,0 +1,81 @@
+/*
+ * 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.openejb.assembler.classic;
+
+import java.util.List;
+import java.util.Properties;
+
+public class ComparableValidationConfig {
+    private final String providerClassName;
+    private final String messageInterpolatorClass;
+    private final String traversableResolverClass;
+    private final String constraintFactoryClass;
+    private final Properties propertyTypes;
+    private final List<String> constraintMappings;
+
+    private final int hash;
+
+    public ComparableValidationConfig(final String providerClassName, final String messageInterpolatorClass,
+                                      final String traversableResolverClass, final String constraintFactoryClass,
+                                      final Properties propertyTypes, final List<String> constraintMappings) {
+        this.providerClassName = providerClassName;
+        this.messageInterpolatorClass = messageInterpolatorClass;
+        this.traversableResolverClass = traversableResolverClass;
+        this.constraintFactoryClass = constraintFactoryClass;
+        this.propertyTypes = propertyTypes;
+        this.constraintMappings = constraintMappings;
+
+        int result = providerClassName != null ? providerClassName.hashCode() : 0;
+        result = 31 * result + (messageInterpolatorClass != null ? messageInterpolatorClass.hashCode() : 0);
+        result = 31 * result + (traversableResolverClass != null ? traversableResolverClass.hashCode() : 0);
+        result = 31 * result + (constraintFactoryClass != null ? constraintFactoryClass.hashCode() : 0);
+        result = 31 * result + (propertyTypes != null ? propertyTypes.hashCode() : 0);
+        result = 31 * result + (constraintMappings != null ? constraintMappings.hashCode() : 0);
+        hash = result;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        final ComparableValidationConfig that = (ComparableValidationConfig) o;
+
+        if (constraintFactoryClass != null ? !constraintFactoryClass.equals(that.constraintFactoryClass) : that.constraintFactoryClass != null)
+            return false;
+        if (constraintMappings != null ? !constraintMappings.equals(that.constraintMappings) : that.constraintMappings != null)
+            return false;
+        if (messageInterpolatorClass != null ? !messageInterpolatorClass.equals(that.messageInterpolatorClass) : that.messageInterpolatorClass != null)
+            return false;
+        if (propertyTypes != null ? !propertyTypes.equals(that.propertyTypes) : that.propertyTypes != null)
+            return false;
+        if (providerClassName != null ? !providerClassName.equals(that.providerClassName) : that.providerClassName != null)
+            return false;
+        if (traversableResolverClass != null ? !traversableResolverClass.equals(that.traversableResolverClass) : that.traversableResolverClass != null)
+            return false;
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return hash;
+    }
+}

Modified: tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/EntityManagerFactoryCallable.java
URL: http://svn.apache.org/viewvc/tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/EntityManagerFactoryCallable.java?rev=1629582&r1=1629581&r2=1629582&view=diff
==============================================================================
--- tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/EntityManagerFactoryCallable.java (original)
+++ tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/EntityManagerFactoryCallable.java Mon Oct  6 07:26:04 2014
@@ -23,6 +23,7 @@ import org.apache.openejb.persistence.Pe
 import javax.persistence.EntityManagerFactory;
 import javax.persistence.ValidationMode;
 import javax.persistence.spi.PersistenceProvider;
+import javax.validation.ValidatorFactory;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.Callable;
@@ -33,12 +34,15 @@ public class EntityManagerFactoryCallabl
 
     private final String persistenceProviderClassName;
     private final PersistenceUnitInfoImpl unitInfo;
+    private final Map<ComparableValidationConfig, ValidatorFactory> potentialValidators;
     private ClassLoader appClassLoader;
 
-    public EntityManagerFactoryCallable(final String persistenceProviderClassName, final PersistenceUnitInfoImpl unitInfo, final ClassLoader cl) {
+    public EntityManagerFactoryCallable(final String persistenceProviderClassName, final PersistenceUnitInfoImpl unitInfo,
+                                        final ClassLoader cl, final Map<ComparableValidationConfig, ValidatorFactory> validators) {
         this.persistenceProviderClassName = persistenceProviderClassName;
         this.unitInfo = unitInfo;
         this.appClassLoader = cl;
+        this.potentialValidators = validators;
     }
 
     @Override
@@ -52,7 +56,7 @@ public class EntityManagerFactoryCallabl
             // Create entity manager factories with the validator factory
             final Map<String, Object> properties = new HashMap<String, Object>();
             if (!ValidationMode.NONE.equals(unitInfo.getValidationMode())) {
-                properties.put("javax.persistence.validator.ValidatorFactory", new ValidatorFactoryWrapper());
+                properties.put("javax.persistence.validation.factory", new ValidatorFactoryWrapper(potentialValidators));
             }
 
             customizeProperties(properties);
@@ -60,8 +64,8 @@ public class EntityManagerFactoryCallabl
             final EntityManagerFactory emf = persistenceProvider.createContainerEntityManagerFactory(unitInfo, properties);
 
             if (unitInfo.getProperties() != null
-                    && "true".equalsIgnoreCase(unitInfo.getProperties().getProperty(OPENEJB_JPA_INIT_ENTITYMANAGER))
-                    || SystemInstance.get().getOptions().get(OPENEJB_JPA_INIT_ENTITYMANAGER, false)) {
+                && "true".equalsIgnoreCase(unitInfo.getProperties().getProperty(OPENEJB_JPA_INIT_ENTITYMANAGER))
+                || SystemInstance.get().getOptions().get(OPENEJB_JPA_INIT_ENTITYMANAGER, false)) {
                 emf.createEntityManager().close();
             }
 
@@ -79,6 +83,7 @@ public class EntityManagerFactoryCallabl
         }
     }
 
+    // properties that have to be passed to properties parameters and not unit properties
     private void customizeProperties(final Map<String, Object> properties) {
         final String pool = SystemInstance.get().getProperty(OPENJPA_ENTITY_MANAGER_FACTORY_POOL);
         if (pool != null) {

Modified: tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/LazyValidator.java
URL: http://svn.apache.org/viewvc/tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/LazyValidator.java?rev=1629582&r1=1629581&r2=1629582&view=diff
==============================================================================
--- tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/LazyValidator.java (original)
+++ tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/LazyValidator.java Mon Oct  6 07:26:04 2014
@@ -20,6 +20,7 @@ package org.apache.openejb.assembler.cla
 import javax.validation.Validator;
 import javax.validation.ValidatorFactory;
 import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.concurrent.locks.ReentrantLock;
 
@@ -35,7 +36,15 @@ public class LazyValidator implements In
 
     @Override
     public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+        ensureDelegate();
+        try {
+            return method.invoke(validator, args);
+        } catch (final InvocationTargetException ite) {
+            throw ite.getCause();
+        }
+    }
 
+    private void ensureDelegate() {
         if (validator == null) {
 
             final ReentrantLock l = lock;
@@ -49,7 +58,10 @@ public class LazyValidator implements In
                 l.unlock();
             }
         }
+    }
 
-        return method.invoke(validator, args);
+    public Validator getValidator() {
+        ensureDelegate();
+        return validator;
     }
 }

Added: tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/LazyValidatorFactory.java
URL: http://svn.apache.org/viewvc/tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/LazyValidatorFactory.java?rev=1629582&view=auto
==============================================================================
--- tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/LazyValidatorFactory.java (added)
+++ tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/LazyValidatorFactory.java Mon Oct  6 07:26:04 2014
@@ -0,0 +1,65 @@
+/*
+ * 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.openejb.assembler.classic;
+
+import javax.validation.ValidatorFactory;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.concurrent.locks.ReentrantLock;
+
+// TODO: make it generic (LazyDelegate + Factory + refactor LazyValidator)
+public class LazyValidatorFactory implements InvocationHandler {
+    private final ReentrantLock lock = new ReentrantLock();
+    private final ClassLoader loader;
+    private final ValidationInfo info;
+    private volatile ValidatorFactory factory;
+
+    public LazyValidatorFactory(final ClassLoader classLoader, final ValidationInfo validationInfo) {
+        this.loader = classLoader;
+        this.info = validationInfo;
+    }
+
+    @Override
+    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
+        ensureDelegate();
+        try {
+            return method.invoke(factory, args);
+        } catch (final InvocationTargetException ite) {
+            throw ite.getCause();
+        }
+    }
+
+    private void ensureDelegate() {
+        if (factory == null) {
+            final ReentrantLock l = lock;
+            l.lock();
+            try {
+                if (factory == null) {
+                    factory = ValidatorBuilder.buildFactory(loader, info);
+                }
+            } finally {
+                l.unlock();
+            }
+        }
+    }
+
+    public ValidatorFactory getFactory() {
+        ensureDelegate();
+        return factory;
+    }
+}

Modified: tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/PersistenceBuilder.java
URL: http://svn.apache.org/viewvc/tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/PersistenceBuilder.java?rev=1629582&r1=1629581&r2=1629582&view=diff
==============================================================================
--- tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/PersistenceBuilder.java (original)
+++ tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/PersistenceBuilder.java Mon Oct  6 07:26:04 2014
@@ -32,6 +32,8 @@ import javax.persistence.SharedCacheMode
 import javax.persistence.ValidationMode;
 import javax.persistence.spi.PersistenceUnitTransactionType;
 import javax.sql.DataSource;
+import javax.validation.ValidatorFactory;
+import java.util.Map;
 
 public class PersistenceBuilder {
 
@@ -46,7 +48,8 @@ public class PersistenceBuilder {
         this.persistenceClassLoaderHandler = persistenceClassLoaderHandler;
     }
 
-    public ReloadableEntityManagerFactory createEntityManagerFactory(final PersistenceUnitInfo info, final ClassLoader classLoader) throws Exception {
+    public ReloadableEntityManagerFactory createEntityManagerFactory(final PersistenceUnitInfo info, final ClassLoader classLoader,
+                                                                     final Map<ComparableValidationConfig, ValidatorFactory> validators) throws Exception {
         final PersistenceUnitInfoImpl unitInfo = new PersistenceUnitInfoImpl(persistenceClassLoaderHandler);
 
         // Persistence Unit Id
@@ -147,7 +150,7 @@ public class PersistenceBuilder {
         final String persistenceProviderClassName = unitInfo.getPersistenceProviderClassName();
         unitInfo.setPersistenceProviderClassName(persistenceProviderClassName);
 
-        final EntityManagerFactoryCallable callable = new EntityManagerFactoryCallable(persistenceProviderClassName, unitInfo, classLoader);
+        final EntityManagerFactoryCallable callable = new EntityManagerFactoryCallable(persistenceProviderClassName, unitInfo, classLoader, validators);
         return new ReloadableEntityManagerFactory(classLoader, callable, unitInfo);
     }
 

Modified: tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ValidatorFactoryWrapper.java
URL: http://svn.apache.org/viewvc/tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ValidatorFactoryWrapper.java?rev=1629582&r1=1629581&r2=1629582&view=diff
==============================================================================
--- tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ValidatorFactoryWrapper.java (original)
+++ tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ValidatorFactoryWrapper.java Mon Oct  6 07:26:04 2014
@@ -21,6 +21,7 @@ import org.apache.openejb.bval.Validator
 import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
 
+import javax.naming.NamingException;
 import javax.validation.ConstraintValidatorFactory;
 import javax.validation.MessageInterpolator;
 import javax.validation.TraversableResolver;
@@ -28,12 +29,26 @@ import javax.validation.Validator;
 import javax.validation.ValidatorContext;
 import javax.validation.ValidatorFactory;
 import java.io.Serializable;
+import java.util.Map;
 
 public class ValidatorFactoryWrapper implements ValidatorFactory, Serializable {
     public static final Logger logger = Logger.getInstance(LogCategory.OPENEJB, ValidatorFactoryWrapper.class);
 
-    private static ValidatorFactory factory() {
-        return ValidatorUtil.validatorFactory();
+    private final Map<ComparableValidationConfig, ValidatorFactory> fallbackValidators;
+
+    private ValidatorFactory factory() {
+        try {
+            return ValidatorUtil.lookupFactory();
+        } catch (final NamingException e) { // in absolute we should sort them to get the closest one of the persistence-unit?
+            if (!fallbackValidators.isEmpty()) {
+                return fallbackValidators.values().iterator().next();
+            }
+            return ValidatorUtil.tryJndiLaterFactory();
+        }
+    }
+
+    public ValidatorFactoryWrapper(final Map<ComparableValidationConfig, ValidatorFactory> validators) {
+        fallbackValidators = validators;
     }
 
     @Override

Modified: tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/bval/ValidatorUtil.java
URL: http://svn.apache.org/viewvc/tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/bval/ValidatorUtil.java?rev=1629582&r1=1629581&r2=1629582&view=diff
==============================================================================
--- tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/bval/ValidatorUtil.java (original)
+++ tomee/tomee/branches/tomee-1.7.x/container/openejb-core/src/main/java/org/apache/openejb/bval/ValidatorUtil.java Mon Oct  6 07:26:04 2014
@@ -43,12 +43,20 @@ public final class ValidatorUtil {
 
     public static ValidatorFactory validatorFactory() {
         try {
-            return (ValidatorFactory) new InitialContext().lookup("java:comp/ValidatorFactory");
+            return lookupFactory();
         } catch (final NamingException e) {
-            return proxy(ValidatorFactory.class, "java:comp/ValidatorFactory");
+            return tryJndiLaterFactory();
         }
     }
 
+    public static ValidatorFactory lookupFactory() throws NamingException {
+        return (ValidatorFactory) new InitialContext().lookup("java:comp/ValidatorFactory");
+    }
+
+    public static ValidatorFactory tryJndiLaterFactory() {
+        return proxy(ValidatorFactory.class, "java:comp/ValidatorFactory");
+    }
+
     public static Validator validator() {
         try {
             return (Validator) new InitialContext().lookup("java:comp/Validator");
@@ -113,7 +121,9 @@ public final class ValidatorUtil {
                                     }
                                 }
                             }
-                            break;
+                            if (ClassLoader.getSystemClassLoader() != appContextClassLoader) {
+                                break;
+                            } // else we surely have a single AppContext so let's try WebContext
                         }
                         for (final WebContext web : appContext.getWebContexts()) {
                             final ClassLoader webClassLoader = web.getClassLoader();