diff --git a/impl-base/src/main/java/org/jboss/arquillian/impl/DynamicServiceLoader.java b/impl-base/src/main/java/org/jboss/arquillian/impl/DynamicServiceLoader.java index e77a84b1..2eed8aaf 100644 --- a/impl-base/src/main/java/org/jboss/arquillian/impl/DynamicServiceLoader.java +++ b/impl-base/src/main/java/org/jboss/arquillian/impl/DynamicServiceLoader.java @@ -17,6 +17,7 @@ package org.jboss.arquillian.impl; import java.util.Collection; +import java.util.logging.Logger; import org.jboss.arquillian.spi.ServiceLoader; import org.jboss.arquillian.spi.util.DefaultServiceLoader; @@ -29,24 +30,81 @@ */ public class DynamicServiceLoader implements ServiceLoader { + private static Logger logger = Logger.getLogger(DynamicServiceLoader.class.getName()); + /* (non-Javadoc) + * @see org.jboss.arquillian.spi.ServiceLoader#all(java.lang.Class) + */ public Collection all(Class serviceClass) { return DefaultServiceLoader.load(serviceClass).getProviders(); } + /* (non-Javadoc) + * @see org.jboss.arquillian.spi.ServiceLoader#onlyOne(java.lang.Class) + */ public T onlyOne(Class serviceClass) { Collection providers = DefaultServiceLoader.load(serviceClass).getProviders(); + verifyOnlyOneOrSameImplementation(serviceClass, providers); + + return providers.iterator().next(); + } + + private void verifyOnlyOneOrSameImplementation(Class serviceClass, Collection providers) + { if(providers == null || providers.size() == 0) { - throw new IllegalStateException("No implementation found for: " + serviceClass.getName() + ", check classpath"); + throw new IllegalStateException( + "No implementation found for " + + serviceClass.getName() + ", please check your classpath"); } if(providers.size() > 1) { - throw new IllegalStateException("Mutiple implementations found for: " + serviceClass.getName() + ", check classpath"); + // verify that they all point to the same implementation, if not throw exception + verifySameImplementation(serviceClass, providers); } - return providers.iterator().next(); } - + + private void verifySameImplementation(Class serviceClass, Collection providers) + { + boolean providersAreTheSame = false; + Class firstProvider = null; + for(Object provider : providers) + { + if(firstProvider == null) + { + // set the class to match + firstProvider = provider.getClass(); + continue; + } + if(firstProvider == provider.getClass()) + { + providersAreTheSame = true; + } + else + { + throw new IllegalStateException( + "More then one implementation found for " + + serviceClass.getName() + ", " + + "please check your classpath. The found implementations are " + toClassString(providers)); + } + } + if(providersAreTheSame) + { + logger.warning( + "More then one reference to the same implementation was found for " + + serviceClass.getName() + ", please verify you classpath"); + } + } + + private String toClassString(Collection providers) + { + StringBuilder sb = new StringBuilder(); + for(Object provider : providers) + { + sb.append(provider.getClass().getName()).append(", "); + } + return sb.subSequence(0, sb.length()-2).toString(); + } } diff --git a/impl-base/src/test/java/org/jboss/arquillian/impl/DynamicServiceLoaderTestCase.java b/impl-base/src/test/java/org/jboss/arquillian/impl/DynamicServiceLoaderTestCase.java new file mode 100644 index 00000000..6cd77cf6 --- /dev/null +++ b/impl-base/src/test/java/org/jboss/arquillian/impl/DynamicServiceLoaderTestCase.java @@ -0,0 +1,64 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2009, 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.jboss.arquillian.impl; + +import java.util.Collection; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Verify the behavior of the Dynamic Service Loader + * + * @author Aslak Knutsen + * @version $Revision: $ + */ +public class DynamicServiceLoaderTestCase +{ + + @Test(expected = IllegalStateException.class) + public void shouldFailIfMultipleProvidersFound() throws Exception + { + new DynamicServiceLoader().onlyOne(Service.class); + } + + @Test + public void shouldNotFailIfMultipleProvidersFoundPointingToSameImpl() throws Exception + { + Service2 service = new DynamicServiceLoader().onlyOne(Service2.class); + + Assert.assertTrue( + "verify that a instance of Service2Impl was loaded", + service.getClass() == Service2Impl.class); + } + + @Test + public void shouldLoadAllInstances() throws Exception { + Collection services = new DynamicServiceLoader().all(Service.class); + + Assert.assertEquals( + "verify that all services where found and loaded", + 2, services.size()); + } + + public interface Service {} + public static class ServiceImpl1 implements Service {} + public static class ServiceImpl2 implements Service {} + + public interface Service2 {} + public static class Service2Impl implements Service2 {} +} diff --git a/impl-base/src/test/resources/META-INF/services/org.jboss.arquillian.impl.DynamicServiceLoaderTestCase$Service b/impl-base/src/test/resources/META-INF/services/org.jboss.arquillian.impl.DynamicServiceLoaderTestCase$Service new file mode 100644 index 00000000..35453aa3 --- /dev/null +++ b/impl-base/src/test/resources/META-INF/services/org.jboss.arquillian.impl.DynamicServiceLoaderTestCase$Service @@ -0,0 +1,2 @@ +org.jboss.arquillian.impl.DynamicServiceLoaderTestCase$ServiceImpl1 +org.jboss.arquillian.impl.DynamicServiceLoaderTestCase$ServiceImpl2 \ No newline at end of file diff --git a/impl-base/src/test/resources/META-INF/services/org.jboss.arquillian.impl.DynamicServiceLoaderTestCase$Service2 b/impl-base/src/test/resources/META-INF/services/org.jboss.arquillian.impl.DynamicServiceLoaderTestCase$Service2 new file mode 100644 index 00000000..efee09c6 --- /dev/null +++ b/impl-base/src/test/resources/META-INF/services/org.jboss.arquillian.impl.DynamicServiceLoaderTestCase$Service2 @@ -0,0 +1,2 @@ +org.jboss.arquillian.impl.DynamicServiceLoaderTestCase$Service2Impl +org.jboss.arquillian.impl.DynamicServiceLoaderTestCase$Service2Impl \ No newline at end of file diff --git a/spi/src/main/java/org/jboss/arquillian/spi/util/DefaultServiceLoader.java b/spi/src/main/java/org/jboss/arquillian/spi/util/DefaultServiceLoader.java index 4c8a91af..f7b8a68b 100644 --- a/spi/src/main/java/org/jboss/arquillian/spi/util/DefaultServiceLoader.java +++ b/spi/src/main/java/org/jboss/arquillian/spi/util/DefaultServiceLoader.java @@ -197,7 +197,7 @@ public void reload() } catch (ClassCastException e) { - throw new IllegalStateException("Extension " + line + " does not implement Extension"); + throw new IllegalStateException(line + " does not implement " + expectedType); } Constructor constructor = serviceClass.getConstructor(); if(!constructor.isAccessible()) {