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