// $Id: BootstrapTest.java 16987 2009-07-01 12:55:44Z hardy.ferentschik $
/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, 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 org.hibernate.jsr303.tck.tests.bootstrap.defaultprovider;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.annotation.ElementType;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import javax.validation.Configuration;
import javax.validation.ConstraintViolation;
import javax.validation.MessageInterpolator;
import javax.validation.Path;
import javax.validation.TraversableResolver;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.spi.ValidationProvider;
import org.jboss.test.audit.annotations.SpecAssertion;
import org.jboss.test.audit.annotations.SpecAssertions;
import org.jboss.testharness.AbstractTest;
import org.jboss.testharness.impl.packaging.Artifact;
import org.jboss.testharness.impl.packaging.ArtifactType;
import org.jboss.testharness.impl.packaging.Classes;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import org.testng.annotations.Test;
import org.hibernate.jsr303.tck.util.TestUtil;
import static org.hibernate.jsr303.tck.util.TestUtil.assertConstraintViolation;
import static org.hibernate.jsr303.tck.util.TestUtil.assertCorrectConstraintViolationMessages;
import static org.hibernate.jsr303.tck.util.TestUtil.assertCorrectNumberOfViolations;
import static org.hibernate.jsr303.tck.util.TestUtil.assertCorrectPropertyPaths;
/**
* @author Hardy Ferentschik
*/
@Artifact(artifactType = ArtifactType.JSR303)
@Classes({ TestUtil.class, TestUtil.PathImpl.class, TestUtil.NodeImpl.class })
public class BootstrapTest extends AbstractTest {
private static final String SERVICES_FILE = "META-INF/services/" + ValidationProvider.class.getName();
@Test
public void testGetDefaultValidator() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
assertNotNull( validator, "We should be able to get a validator." );
Person person = new Person();
person.setPersonalNumber( 12345678900l );
Set<ConstraintViolation<Person>> constraintViolations = validator.validate( person );
assertCorrectNumberOfViolations( constraintViolations, 3 );
assertCorrectPropertyPaths(
constraintViolations, "firstName", "lastName", "personalNumber"
);
person.setFirstName( "John" );
person.setLastName( "Doe" );
constraintViolations = validator.validate( person );
assertCorrectNumberOfViolations( constraintViolations, 1 );
assertConstraintViolation(
constraintViolations.iterator().next(), Person.class, 12345678900l, "personalNumber"
);
person.setPersonalNumber( 1234567890l );
constraintViolations = validator.validate( person );
assertCorrectNumberOfViolations( constraintViolations, 0 );
}
@Test
@SpecAssertion(section = "4.4.4.1", id = "c")
public void testServiceFileExists() {
List<ValidationProvider> providers = readBeanValidationServiceFile();
assertTrue( !providers.isEmpty(), "There should be at least one provider" );
}
@Test
@SpecAssertion(section = "4.3.2", id = "b")
public void testCustomMessageInterpolatorViaConfiguration() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.usingContext()
.messageInterpolator( new DummyMessageInterpolator() )
.getValidator();
assertCustomMessageInterpolatorUsed( validator );
}
@Test
@SpecAssertions({
@SpecAssertion(section = "4.4.2", id = "a"),
@SpecAssertion(section = "4.4.2", id = "b"),
@SpecAssertion(section = "4.3.2", id = "b")
})
public void testCustomMessageInterpolatorViaValidatorContext() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
DummyMessageInterpolator dummyMessageInterpolator = new DummyMessageInterpolator();
Validator validator = factory.usingContext().messageInterpolator( dummyMessageInterpolator ).getValidator();
assertCustomMessageInterpolatorUsed( validator );
assertFalse(
factory.getMessageInterpolator().equals( dummyMessageInterpolator ),
"getMessageInterpolator() should return the default message interpolator."
);
}
@Test
@SpecAssertion(section = "3.5.2", id = "b")
public void testCustomTraversableResolverViaConfiguration() {
// get a new factory using a custom configuration
Configuration<?> configuration = Validation.byDefaultProvider().configure();
configuration.traversableResolver( new DummyTraversableResolver() );
ValidatorFactory factory = configuration.buildValidatorFactory();
Validator validator = factory.getValidator();
assertCustomTrversableResolverUsed( validator );
}
@Test
@SpecAssertion(section = "3.5.2", id = "b")
public void testCustomTraversableResolverViaValidatorContext() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
DummyTraversableResolver DummyTraversableResolver = new DummyTraversableResolver();
Validator validator = factory.usingContext().traversableResolver( DummyTraversableResolver ).getValidator();
assertCustomTrversableResolverUsed( validator );
}
private void assertCustomTrversableResolverUsed(Validator validator) {
Person person = new Person();
Set<ConstraintViolation<Person>> constraintViolations = validator.validate( person );
assertCorrectNumberOfViolations( constraintViolations, 0 );
}
private List<ValidationProvider> readBeanValidationServiceFile() {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
if ( classloader == null ) {
classloader = BootstrapTest.class.getClassLoader();
}
List<ValidationProvider> providers = new ArrayList<ValidationProvider>();
try {
Enumeration<URL> providerDefinitions = classloader.getResources( SERVICES_FILE );
while ( providerDefinitions.hasMoreElements() ) {
URL url = providerDefinitions.nextElement();
addProviderToList( providers, url );
}
}
catch ( Exception e ) {
throw new RuntimeException( "Unable to load service file", e );
}
return providers;
}
private void assertCustomMessageInterpolatorUsed(Validator validator) {
Person person = new Person();
person.setFirstName( "John" );
person.setPersonalNumber( 1234567890l );
Set<ConstraintViolation<Person>> constraintViolations = validator.validate( person );
assertCorrectNumberOfViolations( constraintViolations, 1 );
assertCorrectConstraintViolationMessages( constraintViolations, "my custom message" );
}
private void addProviderToList(List<ValidationProvider> providers, URL url)
throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
InputStream stream = url.openStream();
try {
BufferedReader reader = new BufferedReader( new InputStreamReader( stream ), 100 );
String name = reader.readLine();
while ( name != null ) {
name = name.trim();
if ( !name.startsWith( "#" ) ) {
final Class<?> providerClass = loadClass(
name,
BootstrapTest.class
);
providers.add(
( ValidationProvider ) providerClass.newInstance()
);
}
name = reader.readLine();
}
}
finally {
stream.close();
}
}
private static Class<?> loadClass(String name, Class caller) throws ClassNotFoundException {
try {
//try context classloader, if fails try caller classloader
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if ( loader != null ) {
return loader.loadClass( name );
}
}
catch ( ClassNotFoundException e ) {
//trying caller classloader
if ( caller == null ) {
throw e;
}
}
return Class.forName( name, true, caller.getClassLoader() );
}
private static class DummyMessageInterpolator implements MessageInterpolator {
public String interpolate(String message, Context context) {
return "my custom message";
}
public String interpolate(String message, Context context, Locale locale) {
throw new UnsupportedOperationException( "No specific locale is possible" );
}
}
private static class DummyTraversableResolver implements TraversableResolver {
public boolean isReachable(Object traversableObject, Path.Node traversableProperty, Class<?> rootBeanType, Path pathToTraversableObject, ElementType elementType) {
return false;
}
public boolean isCascadable(Object traversableObject, Path.Node traversableProperty, Class<?> rootBeanType, Path pathToTraversableObject, ElementType elementType) {
return false;
}
}
}