commit 8610d6f0ec42cc8db9ff1eb7c1b83d00b1ea9be2 Author: fabio.simeoni Date: Wed Sep 5 09:50:08 2012 +0000 branch for 1.0.x releases (first created for gCube 2.10.0) git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/branches/common/common-scope/1.0@57622 82a268e6-3cf1-43bd-a215-b396298e98cf diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..0f53f3e --- /dev/null +++ b/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..5f34b0e --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + common-scope + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/distro/INSTALL b/distro/INSTALL new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/distro/INSTALL @@ -0,0 +1 @@ + diff --git a/distro/LICENSE b/distro/LICENSE new file mode 100644 index 0000000..630ba97 --- /dev/null +++ b/distro/LICENSE @@ -0,0 +1,6 @@ +gCube System - License +------------------------------------------------------------ + +The gCube/gCore software is licensed as Free Open Source software conveying to the EUPL (http://ec.europa.eu/idabc/eupl). +The software and documentation is provided by its authors/distributors "as is" and no expressed or +implied warranty is given for its use, quality or fitness for a particular case. diff --git a/distro/MAINTAINERS b/distro/MAINTAINERS new file mode 100644 index 0000000..5e8aa8f --- /dev/null +++ b/distro/MAINTAINERS @@ -0,0 +1 @@ +* Fabio Simeoni (fabio.simeoni@fao.org), FAO of the UN, Italy \ No newline at end of file diff --git a/distro/README b/distro/README new file mode 100644 index 0000000..38b5d4b --- /dev/null +++ b/distro/README @@ -0,0 +1,38 @@ +The gCube System - ${name} +---------------------- + +This work has been partially supported by the following European projects: DILIGENT (FP6-2003-IST-2), D4Science (FP7-INFRA-2007-1.2.2), +D4Science-II (FP7-INFRA-2008-1.2.2), iMarine (FP7-INFRASTRUCTURES-2011-2), and EUBrazilOpenBio (FP7-ICT-2011-EU-Brazil). + +Authors +------- + +* Fabio Simeoni (fabio.simeoni@fao.org), FAO of the UN, Italy. + +Version and Release Date +------------------------ +${version} + +Description +----------- +${description} + +Download information +-------------------- + +Source code is available from SVN: +${scm.url} + +Binaries can be downloaded from: + + +Documentation +------------- +Documentation is available on-line from the Projects Documentation Wiki: +https://gcube.wiki.gcube-system.org/gcube/index.php/Integration_and_Interoperability_Facilities_Framework:_Client_Libraries_Design_Model#Scope_Management + + +Licensing +--------- + +This software is licensed under the terms you may find in the file named "LICENSE" in this directory. diff --git a/distro/changelog.xml b/distro/changelog.xml new file mode 100644 index 0000000..bc6e67b --- /dev/null +++ b/distro/changelog.xml @@ -0,0 +1,5 @@ + + + First Release + + \ No newline at end of file diff --git a/distro/descriptor.xml b/distro/descriptor.xml new file mode 100644 index 0000000..52cb8a5 --- /dev/null +++ b/distro/descriptor.xml @@ -0,0 +1,42 @@ + + servicearchive + + tar.gz + + / + + + ${distroDirectory} + / + true + + README + LICENSE + INSTALL + MAINTAINERS + changelog.xml + + 755 + true + + + + + ${distroDirectory}/profile.xml + /etc + true + + + target/${build.finalName}.jar + /${artifactId} + + + ${distroDirectory}/svnpath.txt + /${artifactId} + true + + + \ No newline at end of file diff --git a/distro/profile.xml b/distro/profile.xml new file mode 100644 index 0000000..91c49e4 --- /dev/null +++ b/distro/profile.xml @@ -0,0 +1,26 @@ + + + + Service + + ${description} + Common + ${artifactId} + 1.0.0 + + + ${artifactId} + ${version} + + ${groupId} + ${artifactId} + ${version} + + + ${build.finalName}.jar + + + + + + diff --git a/distro/svnpath.txt b/distro/svnpath.txt new file mode 100644 index 0000000..f416f9d --- /dev/null +++ b/distro/svnpath.txt @@ -0,0 +1 @@ +${scm.url} diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..f5b33d3 --- /dev/null +++ b/pom.xml @@ -0,0 +1,113 @@ + + 4.0.0 + + + maven-parent + org.gcube.tools + 1.0.0 + + + + org.gcube.core + common-scope + 1.0.0-SNAPSHOT + Common Scope + Scope-related APIs + + + distro + + + + scm:svn:http://svn.d4science.research-infrastructures.eu/gcube/trunk/Common/${project.artifactId} + scm:svn:https://svn.d4science.research-infrastructures.eu/gcube/trunk/Common/${project.artifactId} + http://svn.d4science.research-infrastructures.eu/gcube/trunk/Common/${project.artifactId} + + + + + + org.reflections + reflections + 0.9.6 + + + + junit + junit + 4.10 + test + + + + org.slf4j + slf4j-api + 1.6.4 + compile + + + + org.slf4j + slf4j-simple + 1.6.4 + test + + + + + + + + + + + org.apache.maven.plugins + maven-resources-plugin + 2.5 + + + copy-profile + install + + copy-resources + + + target + + + ${distroDirectory} + true + + profile.xml + + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + ${distroDirectory}/descriptor.xml + + + + + servicearchive + install + + single + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/org/gcube/common/scope/api/DefaultScopeProvider.java b/src/main/java/org/gcube/common/scope/api/DefaultScopeProvider.java new file mode 100644 index 0000000..6d5d7ac --- /dev/null +++ b/src/main/java/org/gcube/common/scope/api/DefaultScopeProvider.java @@ -0,0 +1,21 @@ +package org.gcube.common.scope.api; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +/** + * Marks a {@link ScopeProvider} implementations to use in place of {@link DefaultScopeProvider} + * + * @author Fabio Simeoni + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@Inherited +@Documented +public @interface DefaultScopeProvider {} diff --git a/src/main/java/org/gcube/common/scope/api/ScopeProvider.java b/src/main/java/org/gcube/common/scope/api/ScopeProvider.java new file mode 100644 index 0000000..cdb9b84 --- /dev/null +++ b/src/main/java/org/gcube/common/scope/api/ScopeProvider.java @@ -0,0 +1,34 @@ +package org.gcube.common.scope.api; + +import org.gcube.common.scope.impl.ScopeProviderScanner; + +/** + * Provides a scope in the caller's context. + * + * @author Fabio Simeoni + * + */ +public interface ScopeProvider { + + /** + * Shared {@link ScopeProvider}. + */ + public static final ScopeProvider instance = ScopeProviderScanner.provider(); + + /** + * Returns the scope in the caller's context. + * @return the scope + */ + String get(); + + /** + * Sets the scope in the caller's context. + * @param scope the scope + */ + void set(String scope); + + /** + * Resets the scope in the caller's context. + */ + void reset(); +} diff --git a/src/main/java/org/gcube/common/scope/api/ServiceMap.java b/src/main/java/org/gcube/common/scope/api/ServiceMap.java new file mode 100644 index 0000000..536abf0 --- /dev/null +++ b/src/main/java/org/gcube/common/scope/api/ServiceMap.java @@ -0,0 +1,32 @@ +package org.gcube.common.scope.api; + +import java.util.List; + +import org.gcube.common.scope.impl.ScopedServiceMap; + +/** + * Resolves service endpoints statically configured for a given scope. + * + * @author Fabio Simeoni + * + */ +public interface ServiceMap { + + /** + * Shared {@link ServiceMap}. + */ + public static final ServiceMap instance = new ScopedServiceMap(); + + /** + * Returns the endpoints of a given service. + * @param service the service + * @return the endpoints, or null if the service is unknown. + */ + List endpoint(String service); + + /** + * Returns the associated scope. + * @return the scope + */ + String scope(); +} diff --git a/src/main/java/org/gcube/common/scope/impl/DefaultScopeProviderImpl.java b/src/main/java/org/gcube/common/scope/impl/DefaultScopeProviderImpl.java new file mode 100644 index 0000000..f58ceb2 --- /dev/null +++ b/src/main/java/org/gcube/common/scope/impl/DefaultScopeProviderImpl.java @@ -0,0 +1,51 @@ +package org.gcube.common.scope.impl; + +import org.gcube.common.scope.api.ScopeProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A {@link ScopeProvider} that uses threads as contexts. + *

+ * Relies an an internal {@link InheritableThreadLocal}. + * + * @author Fabio Simeoni + * @see ScopeProviderScanner + * + */ +public class DefaultScopeProviderImpl implements ScopeProvider { + + /** System property for scope */ + public static final String SCOPE_PROPERTY = "gcube.scope"; + + private static Logger log = LoggerFactory.getLogger(DefaultScopeProviderImpl.class); + + private InheritableThreadLocal scopes = new InheritableThreadLocal(); + + protected DefaultScopeProviderImpl() {}; + + @Override + public String get() { + String scope = scopes.get(); + if (scope==null) + scope = System.getProperty(SCOPE_PROPERTY); + return scope; + } + + @Override + public void set(String scope) { + if (scope!=null) + log.info("setting scope {} in thread {}",scope,Thread.currentThread().getId()); + scopes.set(scope); + + } + + @Override + public void reset() { + log.info("resetting scope in thread {}",Thread.currentThread().getId()); + scopes.remove(); + } + + + +} diff --git a/src/main/java/org/gcube/common/scope/impl/DefaultServiceMap.java b/src/main/java/org/gcube/common/scope/impl/DefaultServiceMap.java new file mode 100644 index 0000000..2128fd5 --- /dev/null +++ b/src/main/java/org/gcube/common/scope/impl/DefaultServiceMap.java @@ -0,0 +1,39 @@ +package org.gcube.common.scope.impl; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import org.gcube.common.scope.api.ServiceMap; + +/** + * A {@link ServiceMap} with a standard XML binding. + * + * @author Fabio Simeoni + * + */ +@XmlRootElement(name="service-map") +public class DefaultServiceMap implements ServiceMap { + + @XmlAttribute + private String scope; + + @XmlJavaTypeAdapter(ServiceMapAdapter.class) + Map> services = new LinkedHashMap>(); + + @Override + public String scope() { + return scope; + } + + @Override + public List endpoint(String service) { + return services.get(service); + } + + +} diff --git a/src/main/java/org/gcube/common/scope/impl/ScopeProviderScanner.java b/src/main/java/org/gcube/common/scope/impl/ScopeProviderScanner.java new file mode 100644 index 0000000..9aacacb --- /dev/null +++ b/src/main/java/org/gcube/common/scope/impl/ScopeProviderScanner.java @@ -0,0 +1,68 @@ +package org.gcube.common.scope.impl; + +import java.util.Set; + +import org.gcube.common.scope.api.DefaultScopeProvider; +import org.gcube.common.scope.api.ScopeProvider; +import org.reflections.Reflections; +import org.reflections.scanners.SubTypesScanner; +import org.reflections.util.ClasspathHelper; +import org.reflections.util.ConfigurationBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Scans the classpath for a {@link ScopeProvider} implementation. + *

+ * Returns a shared {@link DefaultScopeProvider} by default. + * + * @author Fabio Simeoni + * @see ScopeProvider + * @see ScopeProvider#instance + */ +public class ScopeProviderScanner { + + private static Logger log = LoggerFactory.getLogger(ScopeProviderScanner.class); + + /** + * Returns the configured provider. + * @return the provider + */ + public static ScopeProvider provider() { + try { + + // we include urls specified in manifest files, which is required + // when we run tests in surefire's forked-mode + ConfigurationBuilder builder = new ConfigurationBuilder().setUrls( + ClasspathHelper.forManifest(Utils.urlsToScan())).setScanners(new SubTypesScanner()); + + Reflections reflections = new Reflections(builder); + + Set> impls = + reflections.getSubTypesOf(ScopeProvider.class); + + ScopeProvider defaultProvider = null; + + for (Class impl : impls) + if (impl.isAnnotationPresent(DefaultScopeProvider.class)) + if (defaultProvider==null) + defaultProvider = impl.newInstance(); + else + throw new Exception("mis-configured environment: detected multiple deafult providers among "+impls); + + if (defaultProvider==null) { + log.info("using default scope provider"); + defaultProvider = new DefaultScopeProviderImpl(); + } + + return defaultProvider; + + + } catch (Exception e) { + throw new RuntimeException("could not configure scope provider", e); + } + } + + + +} diff --git a/src/main/java/org/gcube/common/scope/impl/ScopedServiceMap.java b/src/main/java/org/gcube/common/scope/impl/ScopedServiceMap.java new file mode 100644 index 0000000..36cb39b --- /dev/null +++ b/src/main/java/org/gcube/common/scope/impl/ScopedServiceMap.java @@ -0,0 +1,46 @@ +package org.gcube.common.scope.impl; + +import java.util.List; +import java.util.Map; + +import org.gcube.common.scope.api.ScopeProvider; +import org.gcube.common.scope.api.ServiceMap; + +/** + * A {@link ServiceMap} that forwards requests to {@link ServiceMap}s associated + * with the scope of callers. + *

+ * At construction time, it configures itself with all the service maps found + * the classpath (excluding URLs available to primordial and extension + * classloader). Recognises service maps as resources whose names match a + * {@link ServiceMapScanner#mapConfigPattern}. + * + * @author Fabio Simeoni + * + */ +public class ScopedServiceMap implements ServiceMap { + + private final Map maps; + + + public ScopedServiceMap() { + maps = ServiceMapScanner.maps(); + } + + @Override + public String scope() { + return ScopeProvider.instance.get(); + } + + @Override + public List endpoint(String service) { + + String currentScope = scope(); + + ServiceMap map = maps.get(currentScope); + + return map == null ? null : map.endpoint(service); + } + + +} diff --git a/src/main/java/org/gcube/common/scope/impl/ServiceMapAdapter.java b/src/main/java/org/gcube/common/scope/impl/ServiceMapAdapter.java new file mode 100644 index 0000000..3092e89 --- /dev/null +++ b/src/main/java/org/gcube/common/scope/impl/ServiceMapAdapter.java @@ -0,0 +1,57 @@ +package org.gcube.common.scope.impl; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.adapters.XmlAdapter; + + +/** + * Adapts the JAXB-binding for {@link DefaultServiceMap}. + * + * @author Fabio Simeoni + * + */ +public class ServiceMapAdapter extends XmlAdapter>> { + + @XmlRootElement(name="services") + static class ValueServiceMap { + + @XmlElement(name="service") + Set services; + + } + + static class ServiceEntry { + + @XmlAttribute + private String name; + + @XmlElement(name="endpoint") + private List endpoints; + } + + @Override + public Map> unmarshal(ValueServiceMap valueMap) throws Exception { + Map> map = new LinkedHashMap>(); + for (ServiceEntry service : valueMap.services) + map.put(service.name,service.endpoints); + return map; + } + + @Override + public ValueServiceMap marshal(Map> map) throws Exception { + ValueServiceMap valueMap = new ValueServiceMap(); + for (Map.Entry> e : map.entrySet()) { + ServiceEntry entry = new ServiceEntry(); + entry.name=e.getKey(); + entry.endpoints = e.getValue(); + } + return valueMap; + } +} diff --git a/src/main/java/org/gcube/common/scope/impl/ServiceMapScanner.java b/src/main/java/org/gcube/common/scope/impl/ServiceMapScanner.java new file mode 100644 index 0000000..9389e79 --- /dev/null +++ b/src/main/java/org/gcube/common/scope/impl/ServiceMapScanner.java @@ -0,0 +1,68 @@ +package org.gcube.common.scope.impl; + +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Unmarshaller; + +import org.gcube.common.scope.api.ServiceMap; +import org.reflections.Reflections; +import org.reflections.scanners.ResourcesScanner; +import org.reflections.util.ClasspathHelper; +import org.reflections.util.ConfigurationBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Scans the classpath for {@link ServiceMap}s. + * @author Fabio Simeoni + * + */ +class ServiceMapScanner { + + private static Logger log = LoggerFactory.getLogger(ServiceMapScanner.class); + + /** + * The path used to find service map configuration files. + */ + static final String mapConfigPattern = ".*\\.servicemap"; + + /** + * Scans the classpath for {@link ServiceMap}s. + */ + static Map maps() { + + Map maps = new HashMap(); + + try { + + JAXBContext context = JAXBContext + .newInstance(DefaultServiceMap.class); + Unmarshaller um = context.createUnmarshaller(); + + // we include urls specified in manifest files, which is required + // when we run tests in surefire's forked-mode + ConfigurationBuilder builder = new ConfigurationBuilder().setUrls( + ClasspathHelper.forManifest(Utils.urlsToScan())).setScanners( + new ResourcesScanner()); + + Reflections reflections = new Reflections(builder); + + for (String resource : reflections.getResources(Pattern + .compile(mapConfigPattern))) { + URL url = Thread.currentThread().getContextClassLoader() + .getResource(resource); + log.trace("loading {} ", url); + DefaultServiceMap map = (DefaultServiceMap) um.unmarshal(url); + maps.put(map.scope(), map); + } + } catch (Exception e) { + throw new RuntimeException("could not load service maps", e); + } + + return maps; + } +} diff --git a/src/main/java/org/gcube/common/scope/impl/Utils.java b/src/main/java/org/gcube/common/scope/impl/Utils.java new file mode 100644 index 0000000..2b088d7 --- /dev/null +++ b/src/main/java/org/gcube/common/scope/impl/Utils.java @@ -0,0 +1,41 @@ +package org.gcube.common.scope.impl; + +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Set; + +import com.google.common.collect.Sets; + +/** + * Classpath discovery utils. + * + * @author Fabio Simeoni + * + */ +public class Utils { + + // helper: we use reflections' code but exclude extension and primordial + // classloaders + // whose URLs we do not want to include. especially because these may have + // non-standard URLs + // that would need to be excluded individually from standard scanning, + // or reflections will show (but ignore) a horrible error in the logs. and + // we do no know how to predict what we will + // find on any given machine + static Set urlsToScan() { + final Set result = Sets.newHashSet(); + + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + while (classLoader != null && classLoader.getParent() != null) { + if (classLoader instanceof URLClassLoader) { + URL[] urls = ((URLClassLoader) classLoader).getURLs(); + if (urls != null) { + result.addAll(Sets. newHashSet(urls)); + } + } + classLoader = classLoader.getParent(); + } + + return result; + } +} diff --git a/src/test/java/org/gcube/common/scope/ConfigurationTest.java b/src/test/java/org/gcube/common/scope/ConfigurationTest.java new file mode 100644 index 0000000..c4b5f34 --- /dev/null +++ b/src/test/java/org/gcube/common/scope/ConfigurationTest.java @@ -0,0 +1,51 @@ +package org.gcube.common.scope; + +import static org.junit.Assert.*; + +import java.net.URL; +import java.net.URLClassLoader; + +import org.gcube.common.scope.api.ScopeProvider; +import org.junit.After; +import org.junit.Test; + +public class ConfigurationTest { + + private ClassLoader loader = Thread.currentThread().getContextClassLoader(); + + @Test + public void alternativeProvidersCanBeConfigured() { + + addJarToClasspath("alternativeprovider.jar"); + + assertEquals("AlternativeScopeProvider",ScopeProvider.instance.getClass().getSimpleName()); + } + + @Test + public void multipleAlternativeProvidersCannotBeConfigured() { + + try { + addJarToClasspath("multiplealternativeproviders.jar"); + ScopeProvider.instance.set("shouldfail"); + fail(); + } + catch(Error e) {} + + } + + private void addJarToClasspath(String jar) { + + URL jarURL = loader.getResource(jar); + + URLClassLoader urlClassLoader + = new URLClassLoader(new URL[]{jarURL},loader); + + Thread.currentThread().setContextClassLoader(urlClassLoader); + + } + + @After + public void teardown() { + Thread.currentThread().setContextClassLoader(loader); + } +} diff --git a/src/test/java/org/gcube/common/scope/ProviderTest.java b/src/test/java/org/gcube/common/scope/ProviderTest.java new file mode 100644 index 0000000..2cb5581 --- /dev/null +++ b/src/test/java/org/gcube/common/scope/ProviderTest.java @@ -0,0 +1,33 @@ +package org.gcube.common.scope; + +import static org.junit.Assert.*; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.gcube.common.scope.api.ScopeProvider; +import org.junit.Test; + +public class ProviderTest { + + @Test + public void scopesAreThreadInherited() throws Exception { + + final ScopeProvider provider = ScopeProvider.instance; + + provider.set("scope"); + + final CountDownLatch latch = new CountDownLatch(1); + + new Thread() { + public void run() { + assertNotNull(provider.get()); + latch.countDown(); + }; + }.start(); + + if (!latch.await(100, TimeUnit.MILLISECONDS)) + fail("scope was null in testing thread"); + } + +} diff --git a/src/test/java/org/gcube/common/scope/ServiceMapTest.java b/src/test/java/org/gcube/common/scope/ServiceMapTest.java new file mode 100644 index 0000000..78a3a5c --- /dev/null +++ b/src/test/java/org/gcube/common/scope/ServiceMapTest.java @@ -0,0 +1,59 @@ +package org.gcube.common.scope; + +import static org.junit.Assert.*; + +import java.io.StringReader; +import java.util.Arrays; +import java.util.List; + +import javax.xml.bind.JAXBContext; + +import org.gcube.common.scope.api.ScopeProvider; +import org.gcube.common.scope.api.ServiceMap; +import org.gcube.common.scope.impl.DefaultServiceMap; +import org.junit.After; +import org.junit.Test; + +public class ServiceMapTest { + + private static String map = "" + "" + + "" + + "http://acme.org:8000/service1" + + "http://acme2.org:8000/service1" + + "" + "" + + "http://acme3.org:8000/service2" + + "http://acme4.org:8000/service2" + + "" + "" + ""; + + @Test + public void serviceMapsBindCorrectly() throws Exception { + + JAXBContext context = JAXBContext.newInstance(DefaultServiceMap.class); + + DefaultServiceMap serviceMap = (DefaultServiceMap) context + .createUnmarshaller().unmarshal(new StringReader(map)); + + assertEquals("scope", serviceMap.scope()); + + List expected = Arrays.asList("http://acme.org:8000/service1","http://acme2.org:8000/service1"); + assertEquals(expected, serviceMap.endpoint("service1")); + + expected = Arrays.asList("http://acme3.org:8000/service2","http://acme4.org:8000/service2"); + assertEquals(expected, serviceMap.endpoint("service2")); + } + + @Test + public void serviceMapsDiscoveredCorrectly() throws Exception { + + ScopeProvider.instance.set("scope"); + + assertNotNull(ServiceMap.instance.endpoint("service1")); + + } + + @After + public void cleanup() { + ScopeProvider.instance.reset(); + } + +} diff --git a/src/test/resources/alternativeprovider.jar b/src/test/resources/alternativeprovider.jar new file mode 100644 index 0000000..4ca4cbc Binary files /dev/null and b/src/test/resources/alternativeprovider.jar differ diff --git a/src/test/resources/multiplealternativeproviders.jar b/src/test/resources/multiplealternativeproviders.jar new file mode 100644 index 0000000..9be5e0e Binary files /dev/null and b/src/test/resources/multiplealternativeproviders.jar differ diff --git a/src/test/resources/testmap.servicemap b/src/test/resources/testmap.servicemap new file mode 100644 index 0000000..8d3b384 --- /dev/null +++ b/src/test/resources/testmap.servicemap @@ -0,0 +1 @@ +http://acme.org:8000/service1http://acme2.org:8000/service1http://acme3.org:8000/service2http://acme4.org:8000/service2 \ No newline at end of file