br.com.anteros.validation.api.Validation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Anteros-Bean-Validation-Api Show documentation
Show all versions of Anteros-Bean-Validation-Api Show documentation
Anteros Bean Validation for Java.
// $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 br.com.anteros.validation.api;
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 br.com.anteros.validation.api.bootstrap.GenericBootstrap;
import br.com.anteros.validation.api.bootstrap.ProviderSpecificBootstrap;
import br.com.anteros.validation.api.spi.BootstrapState;
import br.com.anteros.validation.api.spi.ValidationProvider;
/**
* This class is the entry point for Bean Validation. There are three ways to
* bootstrap it:
*
* -
* The easiest approach is to build the default
ValidatorFactory
.
*
*
* {
* @code
* ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
* }
*
*
* In this case, the default validation provider resolver will be used to locate
* available providers. The chosen provider is defined as followed:
*
* - if the XML configuration defines a provider, this provider is used
* - if the XML configuration does not define a provider or if no XML
* configuration is present the first provider returned by the
*
ValidationProviderResolver
instance is used.
*
*
* -
* The second bootstrap approach allows to choose a custom
*
ValidationProviderResolver
. The chosen
* ValidationProvider
is then determined in the same way as in the
* default bootstrapping case (see above).
*
*
* {
* @code
* Configuration<?> configuration = Validation.byDefaultProvider().providerResolver(new MyResolverStrategy())
* .configure();
* ValidatorFactory factory = configuration.buildValidatorFactory();
* }
*
*
*
* -
* The third approach allows you to specify explicitly and in a type safe
* fashion the expected provider.
*
* Optionally you can choose a custom
ValidationProviderResolver
.
*
*
* {
* @code
* ACMEConfiguration configuration = Validation.byProvider(ACMEProvider.class)
* .providerResolver(new MyResolverStrategy()) // optionally set the
* // provider resolver
* .configure();
* ValidatorFactory factory = configuration.buildValidatorFactory();
* }
*
*
*
*
* Note:
*
* -
* The
ValidatorFactory
object built by the bootstrap process
* should be cached and shared amongst Validator
consumers.
* -
* This class is thread-safe.
*
*
* @author Emmanuel Bernard
* @author Hardy Ferentschik
*/
public class Validation {
/**
* Build and return a ValidatorFactory
instance based on the
* default Bean Validation provider and following the XML configuration.
*
* The provider list is resolved using the default validation provider
* resolver logic.
*
* The code is semantically equivalent to
* Validation.byDefaultProvider().configure().buildValidatorFactory()
*
* @return ValidatorFactory
instance.
*
* @throws ValidationException
* if the ValidatorFactory cannot be built
*/
public static ValidatorFactory buildDefaultValidatorFactory() {
return byDefaultProvider().configure().buildValidatorFactory();
}
/**
* Build a Configuration
. The provider list is resolved using
* the strategy provided to the bootstrap state.
*
*
* Configuration<?> configuration = Validation
* .byDefaultProvider()
* .providerResolver( new MyResolverStrategy() )
* .configure();
* ValidatorFactory factory = configuration.buildValidatorFactory();
*
*
* 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 Configuration
compliant
* with the bootstrap state provided.
*/
public static GenericBootstrap byDefaultProvider() {
return new GenericBootstrapImpl();
}
/**
* Build a Configuration
for a particular provider
* implementation. Optionally overrides the provider resolution strategy
* used to determine the provider.
*
* Used by applications targeting a specific provider programmatically.
*
*
*
* ACMEConfiguration configuration = Validation.byProvider(ACMEProvider.class).providerResolver(new MyResolverStrategy())
* .configure();
*
*
* , where ACMEConfiguration
is the Configuration
* sub interface uniquely identifying the ACME Bean Validation provider. and
* ACMEProvider
is the ValidationProvider
* implementation of the ACME provider.
*
* @param providerType
* the ValidationProvider
implementation type
*
* @return instance building a provider specific Configuration
* sub interface implementation.
*/
public static , U extends ValidationProvider> ProviderSpecificBootstrap byProvider(
Class providerType) {
return new ProviderSpecificBootstrapImpl(providerType);
}
// private class, not exposed
private static class ProviderSpecificBootstrapImpl, U extends ValidationProvider>
implements ProviderSpecificBootstrap {
private final Class validationProviderClass;
private ValidationProviderResolver resolver;
public ProviderSpecificBootstrapImpl(Class 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 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> 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 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> 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 ValidationProvider
according to the default
* ValidationProviderResolver
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.
*
* This class implements the Service Provider pattern described here. Since we cannot rely on Java 6 we have to reimplement the
* Service
functionality.
*
*
* @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 does keep a strong reference to the key
// ClassLoader, use the same model as JPA
// CachingPersistenceProviderResolver
private static final Map>> providersPerClassloader = new WeakHashMap>>();
private static final String SERVICES_FILE = "META-INF/services/" + ValidationProvider.class.getName();
private static final String SCANNER_CLASSES_ANDROID = "br.com.anteros.android.util.AndroidClassPathScanner";
@SuppressWarnings("unchecked")
public List> getValidationProviders() {
ClassLoader classloader = GetClassLoader.fromContext();
if (classloader == null) {
classloader = GetClassLoader.fromClass(DefaultValidationProviderResolver.class);
}
List> providers;
synchronized (providersPerClassloader) {
providers = providersPerClassloader.get(classloader);
}
if (providers == null) {
providers = new ArrayList>();
String name = null;
try {
Enumeration 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);
}
/*
* Tratamento especial para acrescentar compatibilidade com o
* Android.
*/
if (providers.size() == 0) {
try {
Class> clValidationProvider = (Class>) Class.forName("br.com.anteros.bean.validation.AnterosValidationProvider");
providers.add(clValidationProvider.newInstance());
} catch (Exception 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 {
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();
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy