Author: ffang
Date: Tue Oct 12 04:52:15 2010
New Revision: 1021629

URL: http://svn.apache.org/viewvc?rev=1021629&view=rev
Log:
[SMX4-605] jsr303 api bundle doesn't support find the ValidatorProvider in the 
OSGi out of box

Added:
    servicemix/smx4/specs/trunk/jsr303-api-1.0.0/src/
    servicemix/smx4/specs/trunk/jsr303-api-1.0.0/src/main/
    servicemix/smx4/specs/trunk/jsr303-api-1.0.0/src/main/java/
    servicemix/smx4/specs/trunk/jsr303-api-1.0.0/src/main/java/javax/
    servicemix/smx4/specs/trunk/jsr303-api-1.0.0/src/main/java/javax/validation/
    
servicemix/smx4/specs/trunk/jsr303-api-1.0.0/src/main/java/javax/validation/Validation.java

Added: 
servicemix/smx4/specs/trunk/jsr303-api-1.0.0/src/main/java/javax/validation/Validation.java
URL: 
http://svn.apache.org/viewvc/servicemix/smx4/specs/trunk/jsr303-api-1.0.0/src/main/java/javax/validation/Validation.java?rev=1021629&view=auto
==============================================================================
--- 
servicemix/smx4/specs/trunk/jsr303-api-1.0.0/src/main/java/javax/validation/Validation.java
 (added)
+++ 
servicemix/smx4/specs/trunk/jsr303-api-1.0.0/src/main/java/javax/validation/Validation.java
 Tue Oct 12 04:52:15 2010
@@ -0,0 +1,433 @@
+// $Id: Validation.java 17620 2009-10-04 19:19:28Z hardy.ferentschik $
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual 
contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package javax.validation;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+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;
+import java.util.Map;
+import java.util.WeakHashMap;
+import javax.validation.bootstrap.GenericBootstrap;
+import javax.validation.bootstrap.ProviderSpecificBootstrap;
+import javax.validation.spi.BootstrapState;
+import javax.validation.spi.ValidationProvider;
+
+/**
+ * This class is the entry point for Bean Validation. There are three ways
+ * to bootstrap it:
+ * <ul>
+ * <li>
+ * The easiest approach is to build the default <code>ValidatorFactory</code>.
+ * <pre>{...@code ValidatorFactory factory = 
Validation.buildDefaultValidatorFactory();}</pre>
+ * In this case, the default validation provider resolver
+ * will be used to locate available providers.
+ * The chosen provider is defined as followed:
+ * <ul>
+ * <li>if the XML configuration defines a provider, this provider is used</li>
+ * <li>if the XML configuration does not define a provider or if no XML 
configuration
+ * is present the first provider returned by the
+ * <code>ValidationProviderResolver</code> instance is used.</li>
+ * </ul>
+ * </li>
+ * <li>
+ * The second bootstrap approach allows to choose a custom
+ * <code>ValidationProviderResolver</code>. The chosen
+ * <code>ValidationProvider</code> is then determined in the same way
+ * as in the default bootstrapping case (see above).
+ * <pre>{...@code
+ * Configuration<?> configuration = Validation
+ *    .byDefaultProvider()
+ *    .providerResolver( new MyResolverStrategy() )
+ *    .configure();
+ * ValidatorFactory factory = configuration.buildValidatorFactory();}
+ * </pre>
+ * </li>
+ * <li>
+ * The third approach allows you to specify explicitly and in
+ * a type safe fashion the expected provider.
+ * <p/>
+ * Optionally you can choose a custom <code>ValidationProviderResolver</code>.
+ * <pre>{...@code
+ * ACMEConfiguration configuration = Validation
+ *    .byProvider(ACMEProvider.class)
+ *    .providerResolver( new MyResolverStrategy() )  // optionally set the 
provider resolver
+ *    .configure();
+ * ValidatorFactory factory = configuration.buildValidatorFactory();}
+ * </pre>
+ * </li>
+ * </ul>
+ * Note:<br/>
+ * <ul>
+ * <li>
+ * The <code>ValidatorFactory</code> object built by the bootstrap process 
should be cached
+ * and shared amongst <code>Validator</code> consumers.
+ * </li>
+ * <li>
+ * This class is thread-safe.
+ * </li>
+ * </ul>
+ *
+ * @author Emmanuel Bernard
+ * @author Hardy Ferentschik
+ */
+public class Validation {
+
+       /**
+        * Build and return a <code>ValidatorFactory</code> instance based on 
the
+        * default Bean Validation provider and following the XML configuration.
+        * <p/>
+        * The provider list is resolved using the default validation provider 
resolver
+        * logic.
+        * <p/> The code is semantically equivalent to
+        * 
<code>Validation.byDefaultProvider().configure().buildValidatorFactory()</code>
+        *
+        * @return <code>ValidatorFactory</code> instance.
+        *
+        * @throws ValidationException if the ValidatorFactory cannot be built
+        */
+       public static ValidatorFactory buildDefaultValidatorFactory() {
+               return byDefaultProvider().configure().buildValidatorFactory();
+       }
+
+       /**
+        * Build a <code>Configuration</code>. The provider list is resolved
+        * using the strategy provided to the bootstrap state.
+        * <pre>
+        * Configuration&lt?&gt; configuration = Validation
+        *    .byDefaultProvider()
+        *    .providerResolver( new MyResolverStrategy() )
+        *    .configure();
+        * ValidatorFactory factory = configuration.buildValidatorFactory();
+        * </pre>
+        * The provider can be specified in the XML configuration. If the XML
+        * configuration does not exsist or if no provider is specified,
+        * the first available provider will be returned.
+        *
+        * @return instance building a generic <code>Configuration</code>
+        *         compliant with the bootstrap state provided.
+        */
+       public static GenericBootstrap byDefaultProvider() {
+               return new GenericBootstrapImpl();
+       }
+
+       /**
+        * Build a <code>Configuration</code> for a particular provider 
implementation.
+        * Optionally overrides the provider resolution strategy used to 
determine the provider.
+        * <p/>
+        * Used by applications targeting a specific provider programmatically.
+        * <p/>
+        * <pre>
+        * ACMEConfiguration configuration =
+        *     Validation.byProvider(ACMEProvider.class)
+        *             .providerResolver( new MyResolverStrategy() )
+        *             .configure();
+        * </pre>,
+        * where <code>ACMEConfiguration</code> is the
+        * <code>Configuration</code> sub interface uniquely identifying the
+        * ACME Bean Validation provider. and <code>ACMEProvider</code> is the
+        * <code>ValidationProvider</code> implementation of the ACME provider.
+        *
+        * @param providerType the <code>ValidationProvider</code> 
implementation type
+        *
+        * @return instance building a provider specific 
<code>Configuration</code>
+        *         sub interface implementation.
+        */
+       public static <T extends Configuration<T>, U extends 
ValidationProvider<T>>
+       ProviderSpecificBootstrap<T> byProvider(Class<U> providerType) {
+               return new ProviderSpecificBootstrapImpl<T, U>( providerType );
+       }
+
+       //private class, not exposed
+       private static class ProviderSpecificBootstrapImpl<T extends 
Configuration<T>, U extends ValidationProvider<T>>
+                       implements ProviderSpecificBootstrap<T> {
+
+               private final Class<U> validationProviderClass;
+               private ValidationProviderResolver resolver;
+
+               public ProviderSpecificBootstrapImpl(Class<U> 
validationProviderClass) {
+                       this.validationProviderClass = validationProviderClass;
+               }
+
+               /**
+                * Optionally define the provider resolver implementation used.
+                * If not defined, use the default ValidationProviderResolver
+                *
+                * @param resolver ValidationProviderResolver implementation 
used
+                *
+                * @return self
+                */
+               public ProviderSpecificBootstrap<T> 
providerResolver(ValidationProviderResolver resolver) {
+                       this.resolver = resolver;
+                       return this;
+               }
+
+               /**
+                * Determine the provider implementation suitable for 
byProvider(Class)
+                * and delegate the creation of this specific Configuration 
subclass to the provider.
+                *
+                * @return a Configuration sub interface implementation
+                */
+               public T configure() {
+                       if ( validationProviderClass == null ) {
+                               throw new ValidationException(
+                                               "builder is mandatory. Use 
Validation.byDefaultProvider() to use the generic provider discovery mechanism"
+                               );
+                       }
+                       //used mostly as a BootstrapState
+                       GenericBootstrapImpl state = new GenericBootstrapImpl();
+                       if ( resolver == null ) {
+                               resolver = 
state.getDefaultValidationProviderResolver();
+                       }
+                       else {
+                               //stay null if no resolver is defined
+                               state.providerResolver( resolver );
+                       }
+
+                       List<ValidationProvider<?>> resolvers;
+                       try {
+                               resolvers = resolver.getValidationProviders();
+                       }
+                       catch ( RuntimeException re ) {
+                               throw new ValidationException( "Unable to get 
available provider resolvers.", re );
+                       }
+
+                       for ( ValidationProvider provider : resolvers ) {
+                               if ( validationProviderClass.isAssignableFrom( 
provider.getClass() ) ) {
+                                       ValidationProvider<T> specificProvider 
= validationProviderClass.cast( provider );
+                                       return 
specificProvider.createSpecializedConfiguration( state );
+
+                               }
+                       }
+                       throw new ValidationException( "Unable to find 
provider: " + validationProviderClass );
+               }
+       }
+
+       //private class, not exposed
+       private static class GenericBootstrapImpl implements GenericBootstrap, 
BootstrapState {
+
+               private ValidationProviderResolver resolver;
+               private ValidationProviderResolver defaultResolver;
+
+               public GenericBootstrap 
providerResolver(ValidationProviderResolver resolver) {
+                       this.resolver = resolver;
+                       return this;
+               }
+
+               public ValidationProviderResolver 
getValidationProviderResolver() {
+                       return resolver;
+               }
+
+               public ValidationProviderResolver 
getDefaultValidationProviderResolver() {
+                       if ( defaultResolver == null ) {
+                               defaultResolver = new 
DefaultValidationProviderResolver();
+                       }
+                       return defaultResolver;
+               }
+
+               public Configuration<?> configure() {
+                       ValidationProviderResolver resolver = this.resolver == 
null ?
+                                       getDefaultValidationProviderResolver() :
+                                       this.resolver;
+
+                       List<ValidationProvider<?>> resolvers;
+                       try {
+                               resolvers = resolver.getValidationProviders();
+                       }
+                       catch ( RuntimeException re ) {
+                               throw new ValidationException( "Unable to get 
available provider resolvers.", re );
+                       }
+
+                       if ( resolvers.size() == 0 ) {
+                               //FIXME looks like an assertion error almost
+                               throw new ValidationException( "Unable to find 
a default provider" );
+                       }
+
+                       Configuration<?> config;
+                       try {
+                               config = resolver.getValidationProviders().get( 
0 ).createGenericConfiguration( this );
+                       }
+                       catch ( RuntimeException re ) {
+                               throw new ValidationException( "Unable to 
instantiate Configuration.", re );
+                       }
+
+                       return config;
+               }
+       }
+
+       /**
+        * Find <code>ValidationProvider</code> according to the default 
<code>ValidationProviderResolver</code> defined in the
+        * Bean Validation specification. This implementation uses the current 
classloader or the classloader which has loaded
+        * the current class if the current class loader is unavailable. The 
classloader is used to retrieve the Service Provider files.
+        * <p>
+        * This class implements the Service Provider pattern described <a 
href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Service%20Provider";>here</a>.
+        * Since we cannot rely on Java 6 we have to reimplement the 
<code>Service</code> functionality.
+        * </p>
+        *
+        * @author Emmanuel Bernard
+        * @author Hardy Ferentschik
+        */
+       private static class DefaultValidationProviderResolver implements 
ValidationProviderResolver {
+
+               //cache per classloader for an appropriate discovery
+               //keep them in a weak hashmap to avoid memory leaks and allow 
proper hot redeployment
+               //TODO use a WeakConcurrentHashMap
+               //FIXME The List<VP> does keep a strong reference to the key 
ClassLoader, use the same model as JPA CachingPersistenceProviderResolver
+               private static final Map<ClassLoader, 
List<ValidationProvider<?>>> providersPerClassloader =
+                               new WeakHashMap<ClassLoader, 
List<ValidationProvider<?>>>();
+
+               private static final String SERVICES_FILE = 
"META-INF/services/" + ValidationProvider.class.getName();
+
+               public List<ValidationProvider<?>> getValidationProviders() {
+                       ClassLoader classloader = GetClassLoader.fromContext();
+                       if ( classloader == null ) {
+                               classloader = GetClassLoader.fromClass( 
DefaultValidationProviderResolver.class );
+                       }
+
+                       List<ValidationProvider<?>> providers;
+                       synchronized ( providersPerClassloader ) {
+                               providers = providersPerClassloader.get( 
classloader );
+                       }
+
+                       if ( providers == null ) {
+                               providers = new 
ArrayList<ValidationProvider<?>>();
+                               try {
+                                       // If we are deployed into an OSGi 
environment, leverage it
+                                       Class providerClass = 
org.apache.servicemix.specs.locator.OsgiLocator.locate(ValidationProvider.class.getName());
+                                       if (providerClass != null) {
+                                               providers.add(( 
ValidationProvider ) providerClass.newInstance());
+                                       }
+                               } catch (Throwable e) {
+                                       // Do nothing here
+                               } 
+                               String name = null;
+                               try {
+                                       Enumeration<URL> providerDefinitions = 
classloader.getResources( SERVICES_FILE );
+                                       while ( 
providerDefinitions.hasMoreElements() ) {
+                                               URL url = 
providerDefinitions.nextElement();
+                                               InputStream stream = 
url.openStream();
+                                               try {
+                                                       BufferedReader reader = 
new BufferedReader( new InputStreamReader( stream ), 100 );
+                                                       name = 
reader.readLine();
+                                                       while ( name != null ) {
+                                                               name = 
name.trim();
+                                                               if ( 
!name.startsWith( "#" ) ) {
+                                                                       final 
Class<?> providerClass = loadClass(
+                                                                               
        name,
+                                                                               
        DefaultValidationProviderResolver.class
+                                                                       );
+
+                                                                       
providers.add(
+                                                                               
        ( ValidationProvider ) providerClass.newInstance()
+                                                                       );
+                                                               }
+                                                               name = 
reader.readLine();
+                                                       }
+                                               }
+                                               finally {
+                                                       stream.close();
+                                               }
+                                       }
+                               }
+                               catch ( IOException e ) {
+                                       throw new ValidationException( "Unable 
to read " + SERVICES_FILE, e );
+                               }
+                               catch ( ClassNotFoundException e ) {
+                                       //TODO is it better to not fail the 
whole loading because of a black sheep?
+                                       throw new ValidationException( "Unable 
to load Bean Validation provider " + name, e );
+                               }
+                               catch ( IllegalAccessException e ) {
+                                       throw new ValidationException( "Unable 
to instanciate Bean Validation provider" + name, e );
+                               }
+                               catch ( InstantiationException e ) {
+                                       throw new ValidationException( "Unable 
to instanciate Bean Validation provider" + name, e );
+                               }
+
+                               synchronized ( providersPerClassloader ) {
+                                       providersPerClassloader.put( 
classloader, providers );
+                               }
+                       }
+
+                       return providers;
+               }
+
+               private static Class<?> loadClass(String name, Class<?> caller) 
throws ClassNotFoundException {
+                       try {
+                               //try context classloader, if fails try caller 
classloader
+                               ClassLoader loader = 
GetClassLoader.fromContext();
+                               if ( loader != null ) {
+                                       return loader.loadClass( name );
+                               }
+                       }
+                       catch ( ClassNotFoundException e ) {
+                               //trying caller classloader
+                               if ( caller == null ) {
+                                       throw e;
+                               }
+                       }
+                       return Class.forName( name, true, 
GetClassLoader.fromClass( caller ) );
+               }
+       }
+
+       private static class GetClassLoader implements 
PrivilegedAction<ClassLoader> {
+               private final Class<?> clazz;
+
+               public static ClassLoader fromContext() {
+                       final GetClassLoader action = new GetClassLoader( null 
);
+                       if ( System.getSecurityManager() != null ) {
+                               return AccessController.doPrivileged( action );
+                       }
+                       else {
+                               return action.run();
+                       }
+               }
+
+               public static ClassLoader fromClass(Class<?> clazz) {
+                       if ( clazz == null ) {
+                               throw new IllegalArgumentException( "Class is 
null" );
+                       }
+                       final GetClassLoader action = new GetClassLoader( clazz 
);
+                       if ( System.getSecurityManager() != null ) {
+                               return AccessController.doPrivileged( action );
+                       }
+                       else {
+                               return action.run();
+                       }
+               }
+
+               private GetClassLoader(Class<?> clazz) {
+                       this.clazz = clazz;
+               }
+
+               public ClassLoader run() {
+                       if ( clazz != null ) {
+                               return clazz.getClassLoader();
+                       }
+                       else {
+                               return 
Thread.currentThread().getContextClassLoader();
+                       }
+               }
+       }
+}
+


Reply via email to