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