You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicemix.apache.org by ff...@apache.org on 2010/10/12 06:52:15 UTC

svn commit: r1021629 - in /servicemix/smx4/specs/trunk/jsr303-api-1.0.0/src: ./ main/ main/java/ main/java/javax/ main/java/javax/validation/ main/java/javax/validation/Validation.java

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();
+			}
+		}
+	}
+}
+