6621843: Support service- and service-provider modules
authorbristor
Mon Jul 07 10:13:08 2008 -0700 (16 months ago)
changeset 396fe6ca591bf85
parent 395fcb8a2efae8c
child 397fd7a1cbf88a3
6621843: Support service- and service-provider modules
Summary: Provides ability to have services and providers be accessed via modules
Reviewed-by: stanleyh, mchung
make/java/java/FILES_java.gmk
src/share/classes/java/util/ServiceLoader.java
src/share/classes/sun/module/bootstrap/VirtualModuleDefinitions.java
src/share/classes/sun/module/core/ProxyModuleLoader.java
src/share/classes/sun/module/core/ServiceProcessor.java
src/share/classes/sun/module/repository/RepositoryConfig.java
test/java/module/modinit/mtest/service/InstalledLookup.mtest
test/java/module/modinit/mtest/service/NullPrintServiceLookup.mtest
test/java/module/modinit/mtest/service/PrintServiceLookup.mtest
test/java/module/modinit/mtest/service/SqlDriver.mtest
test/java/module/repository/RepositoryConfigTest.java
test/java/module/repository/Test6574851.java
test/java/module/service/CharsetServiceTest.java
test/java/module/service/ClasspathServiceTest.java
test/java/module/service/ClientServiceTest.java
test/java/module/service/DefaultServiceTest.java
test/java/module/service/ModuleServiceTest.java
test/java/module/service/README.txt
test/java/module/service/ReexportServiceTest.java
test/java/module/service/RepositoryServiceTest.java
test/java/module/service/ServiceTest.java
test/java/module/service/VersionServiceTest.java
test/java/module/service/src/charserv/client/Main.java
test/java/module/service/src/charserv/client/module_info.java
test/java/module/service/src/charserv/other/CharsetServiceProviderOnClasspath.java
test/java/module/service/src/charserv/provider/CharsetServiceProvider.java
test/java/module/service/src/charserv/provider/module_info.java
test/java/module/service/src/cliserv/client/Main.java
test/java/module/service/src/cliserv/client/MainCP.java
test/java/module/service/src/cliserv/client/module_info.java
test/java/module/service/src/cliserv/provider/BarService.java
test/java/module/service/src/cliserv/provider/BarServiceProvider.java
test/java/module/service/src/cliserv/provider/FooService2Provider.java
test/java/module/service/src/cliserv/provider/module_info.java
test/java/module/service/src/cliserv/service/FooService.java
test/java/module/service/src/cliserv/service/FooServiceDefaultProvider.java
test/java/module/service/src/cliserv/service/module_info.java
test/java/module/service/src/cpserv/client/Main.java
test/java/module/service/src/cpserv/client/module_info.java
test/java/module/service/src/cpserv/other/Mumble.java
test/java/module/service/src/cpserv/service/FooService.java
test/java/module/service/src/cpserv/service/FooServiceDefaultProvider.java
test/java/module/service/src/cpserv/service/module_info.java
test/java/module/service/src/defserv/client/Main.java
test/java/module/service/src/defserv/client/module_info.java
test/java/module/service/src/defserv/provider/BarService.java
test/java/module/service/src/defserv/provider/BarServiceDefaultProvider.java
test/java/module/service/src/defserv/provider/FooService2Provider.java
test/java/module/service/src/defserv/provider/module_info.java
test/java/module/service/src/defserv/service/FooService.java
test/java/module/service/src/defserv/service/FooServiceDefaultProvider.java
test/java/module/service/src/defserv/service/FooServiceDefaultProvider2.java
test/java/module/service/src/defserv/service/module_info.java
test/java/module/service/src/modserv/client/Main.java
test/java/module/service/src/modserv/client/module_info.java
test/java/module/service/src/modserv/provider1/AdvancedCodecs.java
test/java/module/service/src/modserv/provider1/StandardCodecs.java
test/java/module/service/src/modserv/provider1/module_info.java
test/java/module/service/src/modserv/provider2/AdvancedCodecs.java
test/java/module/service/src/modserv/provider2/module_info.java
test/java/module/service/src/modserv/provider3/ImplCodecs.java
test/java/module/service/src/modserv/provider3/module_info.java
test/java/module/service/src/modserv/service/CodecSet.java
test/java/module/service/src/modserv/service/Encoder.java
test/java/module/service/src/modserv/service/module_info.java
test/java/module/service/src/reposerv/client/Main.java
test/java/module/service/src/reposerv/client/module_info.java
test/java/module/service/src/reposerv/provider/BarService.java
test/java/module/service/src/reposerv/provider/BarServiceDefaultProvider.java
test/java/module/service/src/reposerv/provider/FooService2Provider.java
test/java/module/service/src/reposerv/provider/module_info.java
test/java/module/service/src/reposerv/service/FooService.java
test/java/module/service/src/reposerv/service/FooServiceDefaultProvider.java
test/java/module/service/src/reposerv/service/module_info.java
test/java/module/service/src/rxpserv/client/Main.java
test/java/module/service/src/rxpserv/client/module_info.java
test/java/module/service/src/rxpserv/extra/module_info.java
test/java/module/service/src/rxpserv/provider/FooServiceProvider.java
test/java/module/service/src/rxpserv/provider/module_info.java
test/java/module/service/src/rxpserv/service/FooService.java
test/java/module/service/src/rxpserv/service/module_info.java
test/java/module/service/src/rxpserv/transitive/module_info.java
test/java/module/service/src/verserv/client/Main.java
test/java/module/service/src/verserv/client/module_info.java
test/java/module/service/src/verserv/provider/BarService.java
test/java/module/service/src/verserv/provider/BarServiceDefaultProvider.java
test/java/module/service/src/verserv/provider/FooService2Provider.java
test/java/module/service/src/verserv/provider/module_info.java
test/java/module/service/src/verserv/service/FooService.java
test/java/module/service/src/verserv/service/FooServiceDefaultProvider.java
test/java/module/service/src/verserv/service/module_info.java
--- a/make/java/java/FILES_java.gmk Fri Jun 27 08:14:27 2008 -0700
+++ b/make/java/java/FILES_java.gmk Mon Jul 07 10:13:08 2008 -0700
@@ -1,5 +1,5 @@
#
-# Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved.
+# Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -250,6 +250,8 @@ JAVA_JAVA_java = \
java/util/EnumMap.java \
java/util/Arrays.java \
java/util/ConcurrentModificationException.java \
+ java/util/Service.java \
+ java/util/ServiceProvider.java \
java/util/ServiceLoader.java \
java/util/ServiceConfigurationError.java \
java/util/Timer.java \
--- a/src/share/classes/java/util/ServiceLoader.java Fri Jun 27 08:14:27 2008 -0700
+++ b/src/share/classes/java/util/ServiceLoader.java Mon Jul 07 10:13:08 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,12 +29,21 @@ import java.io.IOException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.module.ImportDependency;
+import java.module.Module;
+import java.module.ModuleDefinition;
+import java.module.ModuleInitializationException;
+import java.module.ModuleSystem;
+import java.module.Query;
+import java.module.Repository;
+import java.module.Version;
+import java.module.VersionConstraint;
+import java.module.annotation.ServiceProvider;
+import java.module.annotation.ServiceProviders;
+import java.module.annotation.Services;
import java.net.URL;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
+import sun.module.core.ModuleUtils;
+import sun.module.repository.RepositoryConfig;
/**
@@ -47,7 +56,8 @@ import java.util.NoSuchElementException;
* can be installed in an implementation of the Java platform in the form of
* extensions, that is, jar files placed into any of the usual extension
* directories. Providers can also be made available by adding them to the
- * application's class path or by some other platform-specific means.
+ * application's class path, by installing them as service-provider modules
+ * in repositories, or by some other platform-specific means.
*
* <p> For the purpose of loading, a service is represented by a single type,
* that is, a single interface or abstract class. (A concrete class can be
@@ -91,6 +101,46 @@ import java.util.NoSuchElementException;
* providers, adding each one to the cache in turn. The cache can be cleared
* via the {@link #reload reload} method.
*
+ * <p> Services and providers can be placed into service and service-provider
+ * modules, and installed into a repository. Service and service-provider
+ * modules can be versioned independently. A service module can have a number
+ * of default providers in the same module, thus being both a service module
+ * and a service-provider module.
+ *
+ * <p> Conceptually, when providers are loaded from repositories,
+ * the following strategy for locating service-provider modules is used:
+ *
+ * <ul>
+ * <li> Query the repository for all
+ * service-provider modules, ignoring those which do not provide for the
+ * requested {@code service}.</li>
+ *
+ * <li> Service-providers which have the same name as the {@code
+ * service}'s module, but have a different version, are ignored.</li>
+ *
+ * <li> Service-providers which have the same name and same version as the
+ * {@code service}'s module, but have a different module instance than the
+ * {@code service}'s module, are ignored.</li>
+ *
+ * <li> Service-providers which import directly (or transitively via module
+ * re-exports) a service module with the same name as the {@code service}'s
+ * module, but of a different version, are ignored.</li>
+ *
+ * <li> Service-providers which import directly (or transitively via module
+ * re-exports) a service module with the same name and version as the {@code
+ * service}'s module, but have a different module instance than the {@code
+ * service}'s module, are ignored.</li>
+ *
+ * <li> Of the remaining service-providers, for each service-provider module
+ * name, only the service-provider module with the highest version is
+ * retained.</li>
+ * </ul>
+ *
+ * <p> The provider classes are returned from an iterator in the following
+ * order: first, any default providers, in the order provided by the module to
+ * which they belong. Then, non-default providers, sorted alphabetically by
+ * module name.
+ *
* <p> Service loaders always execute in the security context of the caller.
* Trusted system code should typically invoke the methods in this class, and
* the methods of the iterators which they return, from within a privileged
@@ -101,7 +151,6 @@ import java.util.NoSuchElementException;
*
* <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
* method in this class will cause a {@link NullPointerException} to be thrown.
- *
*
* <p><span style="font-weight: bold; padding-right: 1em">Example</span>
* Suppose we have a service type <tt>com.example.CodecSet</tt> which is
@@ -184,17 +233,37 @@ public final class ServiceLoader<S>
private static final String PREFIX = "META-INF/services/";
+
+ // For locating service modules
+ private static final Query serviceQuery =
+ Query.annotation(Services.class);
+
+ // For locating service-provider modules
+ private static final Query serviceProviderQuery =
+ Query.annotation(ServiceProviders.class);
+
// The class or interface representing the service being loaded
- private Class<S> service;
-
- // The class loader used to locate, load, and instantiate providers
- private ClassLoader loader;
+ private final Class<S> service;
+
+ // The class loader used to locate, load, and instantiate providers. Used
+ // only when no repository is available for loading providers.
+ private final ClassLoader loader;
// Cached providers, in instantiation order
- private LinkedHashMap<String,S> providers = new LinkedHashMap<String,S>();
-
- // The current lazy-lookup iterator
- private LazyIterator lookupIterator;
+ private final LinkedHashMap<String,S> providers = new LinkedHashMap<String,S>();
+
+ // Module containing the service
+ private final Module serviceMod;
+
+ // The repository in which ModuleDefinitions are found.
+ private final Repository repository;
+
+ // The current service provider lookup iterator
+ private List<ServiceLoaderIterator> lookupIterators;
+
+ // True if iteration is over providers from a Repository and then a ClassLoader
+ private final boolean isCompound;
+
/**
* Clear this loader's provider cache so that all providers will be
@@ -209,12 +278,57 @@ public final class ServiceLoader<S>
*/
public void reload() {
providers.clear();
- lookupIterator = new LazyIterator(service, loader);
+ lookupIterators = new ArrayList<ServiceLoaderIterator>();
+ if (repository == null) {
+ lookupIterators.add(new LazyIterator(service, loader));
+ } else {
+ lookupIterators.add(new ModulesIterator(service, serviceMod));
+ if (isCompound) {
+ lookupIterators.add(new LazyIterator(service, loader));
+ }
+ }
}
private ServiceLoader(Class<S> svc, ClassLoader cl) {
service = svc;
loader = cl;
+ isCompound = false;
+
+ // If the both service and loader are from modules, use the loader's
+ // repository for provider lookups.
+ ClassLoader svcClassLoader = service.getClassLoader();
+ if (svcClassLoader != null && svcClassLoader.getModule() != null
+ && loader != null && loader.getModule() != null) {
+ repository =
+ loader.getModule().getModuleDefinition().getRepository();
+ serviceMod = svcClassLoader.getModule();
+ } else {
+ repository = null;
+ serviceMod = null;
+ }
+ reload();
+ }
+
+ private ServiceLoader(Class<S> svc, Repository repo) {
+ this(svc, repo, null, svc.getClassLoader().getModule(), false);
+ }
+
+ private ServiceLoader(Class<S> svc, Repository repo, Module mod) {
+ this(svc, repo, null, mod, false);
+ }
+
+ private ServiceLoader(Class<S> svc, Repository repo, ClassLoader cl,
+ Module mod) {
+ this(svc, repo, cl, mod, true);
+ }
+
+ private ServiceLoader(Class<S> svc, Repository repo, ClassLoader cl,
+ Module mod, boolean isCompound) {
+ this.service = svc;
+ this.repository = repo;
+ this.loader = cl;
+ this.serviceMod = mod;
+ this.isCompound = isCompound;
reload();
}
@@ -310,20 +424,35 @@ public final class ServiceLoader<S>
return names.iterator();
}
- // Private inner class implementing fully-lazy provider lookup
+ // Base class for iterators which access providers of services.
+ //
+ private abstract class ServiceLoaderIterator
+ implements Iterator<S>
+ {
+ final Class<S> service;
+
+ ServiceLoaderIterator(Class<S> service) {
+ this.service = service;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ // Private inner class implementing fully-lazy provider lookup from
+ // a ClassLoader.
//
private class LazyIterator
- implements Iterator<S>
+ extends ServiceLoaderIterator
{
-
- Class<S> service;
- ClassLoader loader;
+ final ClassLoader loader;
Enumeration<URL> configs = null;
Iterator<String> pending = null;
String nextName = null;
private LazyIterator(Class<S> service, ClassLoader loader) {
- this.service = service;
+ super(service);
this.loader = loader;
}
@@ -373,11 +502,307 @@ public final class ServiceLoader<S>
}
throw new Error(); // This cannot happen
}
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
+ }
+
+ // Private inner class implementing provider lookup from Modules
+ //
+ private class ModulesIterator
+ extends ServiceLoaderIterator
+ {
+ private final Module serviceMod;
+
+ // Potential candidates are still screened for compatibility.
+ private Iterator<ModuleProvider> candidates = null;
+
+ // The next ModuleProvider from which a service will be returned.
+ private ModuleProvider nextMP = null;
+
+ private ModulesIterator(Class<S> service, Module serviceMod) {
+ super(service);
+ this.serviceMod = serviceMod;
+ }
+
+ // In addition to usual hasNext - like behavior, sets nextMP to the
+ // next ModuleProvider from which a service provider is to be returned
+ // from next().
+ public boolean hasNext() {
+ if (candidates == null) {
+ candidates = getCandidates().iterator();
+ }
+ if (nextMP != null) { // Was set in prior call to hasNext
+ return true;
+ } else {
+ while (candidates.hasNext()) {
+ nextMP = candidates.next();
+ if (isCompatible(nextMP)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public S next() {
+ S rc = null;
+
+ // nextMP is null if hasNext() has not been called.
+ if (nextMP == null) {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ }
+
+ String cn = nextMP.getName();
+ try {
+ Object o = null;
+ Class<?> nextMPClass = nextMP.getProviderClass();
+ o = nextMPClass.newInstance();
+ rc = service.cast(o);
+ providers.put(cn, rc);
+ } catch (Throwable x) {
+ fail(service,
+ "Provider " + cn + " could not be instantiated: " + x,
+ x);
+ }
+ nextMP = null;
+ return rc;
+ }
+
+ /**
+ * Gets the candidates provider modules for a service. A candidate
+ * service provider module might not actually be acceptable; see next().
+ * <pre>
+ * Let S be the requested service
+ * Let SM be the service module to which S belongs
+ * Let SMD be the service module definition for SM
+ *
+ * For each module definition MD in the repository which has ServiceProviders
+ * For each service provider P of MD
+ * If P is a provider for S
+ * Let M be the module instance for MD
+ *
+ * If SMD's name matches MD's name
+ * P is a default provider
+ * If SM is the same as M
+ * Add P as a default provider for SM
+ * Continue to the next service provider
+ *
+ * If M imports SM (directly or transitively via reexports)
+ * Remove candidates with same name as M's but lower version
+ * Add M as a candidate
+ * Sort the list of candidates according to name
+ * Add all default providers to the head of the list of candidates
+ * Return the list of candidates
+ *
+ * Mapping between above terms and code below:
+ * S: service
+ * SM: serviceMod
+ * SMD: serviceModDef
+ * MD: providerModDef
+ * M: providerMod (see use in ModuleChecker)
+ * P: p (rougly; code based on ServiceProvider annotation)
+ * </pre>
+ * @return a list of {@code ModuleProvider} instances for the service
+ */
+ private List<ModuleProvider> getCandidates() {
+ List<ModuleProvider> rc = new ArrayList<ModuleProvider>();
+ List<ModuleProvider> defaultProviders = new ArrayList<ModuleProvider>();
+ if (serviceMod == null) {
+ return rc;
+ }
+ ModuleDefinition serviceModDef = serviceMod.getModuleDefinition();
+
+ // Keeps track of candiates per provider name.
+ Map<String, ModuleProvider> candidates = new HashMap<String, ModuleProvider>();
+
+ for (ModuleDefinition providerModDef : repository.find(serviceProviderQuery)) {
+ ServiceProviders sp = providerModDef.getAnnotation(ServiceProviders.class);
+ ModuleChecker checker = new ModuleChecker(serviceMod, providerModDef);
+
+ for (ServiceProvider p : sp.value()) {
+ if (!p.service().equals(service.getName())) {
+ continue;
+ }
+
+ // If providerModDef's name matches serviceModDef's name,
+ // providerMod is a default provider.
+ String providerName = providerModDef.getName();
+ if (serviceModDef.getName().equals(providerName)) {
+ // The provider is also a service module
+ if (serviceModDef.getVersion().equals(providerModDef.getVersion())) {
+ // If names and versions are the same, we still
+ // need to check the identity
+ if (checker.checkEquals()) {
+ defaultProviders.add(new ModuleProvider(providerModDef, p.providerClass()));
+ }
+ } else {
+ // If they are not the same versions, then the
+ // provider is not suitable for this version of
+ // the service, as it is a default for another
+ // version.
+ }
+ continue;
+ }
+
+ // To be a candidate, a provider module must import the service module
+ if (!checker.checkImports()) {
+ continue;
+ }
+
+ // For provider-modules with a given name, keep only the
+ // highest version.
+ ModuleProvider candidate = candidates.get(providerName);
+ if (candidate == null) {
+ candidates.put(providerName,
+ new ModuleProvider(
+ providerModDef, p.providerClass()));
+ } else if (providerModDef.getVersion().compareTo(candidate.getVersion()) > 0) {
+ candidates.put(providerName,
+ new ModuleProvider(
+ providerModDef, p.providerClass()));
+ }
+ }
+ }
+ rc.addAll(candidates.values());
+ Collections.sort(rc, ModuleProvider.comparator);
+ rc.addAll(0, defaultProviders);
+ return rc;
+ }
+
+ /**
+ * A candidate provider is compatible if
+ * (a) one of the interfaces it implements is the same as that
+ * of the given service, or
+ * (b) one of its superclasses is exactly the same as the
+ * given service.
+ * @return true if {@code mp} designates a compatible provider
+ */
+ private boolean isCompatible(ModuleProvider mp) {
+ String cn = mp.getName();
+ try {
+ Class<?> mpClass = mp.getProviderClass();
+
+ Class<?>[] interfaces = mpClass.getInterfaces();
+ if (Arrays.asList(interfaces).contains(service)) {
+ return true;
+ }
+
+ Class sup = mpClass.getSuperclass();
+ while (sup != null) {
+ if (sup == service) {
+ return true;
+ } else {
+ sup = sup.getSuperclass();
+ }
+ }
+ return false;
+
+ } catch (ClassNotFoundException x) {
+ fail(service,
+ "Provider " + cn + " not found");
+ } catch (Throwable x) {
+ fail(service,
+ "Provider " + cn + " could not be instantiated: " + x,
+ x);
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Represents a way to compare two modules, one of which is obtained from
+ * its given definition. If that attempt fails, a subsequent attempt is
+ * not repeated. If it succeeds, it is used in all examinations.
+ */
+ private static class ModuleChecker {
+ private final Module serviceMod;
+ private final ModuleDefinition providerModDef;
+
+ private Module providerMod;
+ private boolean accessAttempted = false;
+
+ ModuleChecker(Module serviceMod, ModuleDefinition providerModDef) {
+ this.serviceMod = serviceMod;
+ this.providerModDef = providerModDef;
+ }
+
+ /** @return true if serviceMod == the provider's module */
+ boolean checkEquals() {
+ getProviderModule();
+ return providerMod == null ? false : serviceMod == providerMod;
+ }
+
+ /**
+ * @return true if the provider module imports the service module,
+ * directly or via reexports of imported modules (transitively).
+ */
+ boolean checkImports() {
+ getProviderModule();
+ boolean rc = false;
+ if (providerMod != null) {
+ List<Module> reexports = new ArrayList<Module>();
+ ModuleUtils.expandReexports(providerMod, reexports, true);
+ rc = reexports.contains(serviceMod);
+ }
+ return rc;
+ }
+
+ // Make only one attempt at getting the provider's module
+ private void getProviderModule() {
+ if (!accessAttempted) {
+ try {
+ providerMod = providerModDef.getModuleInstance();
+ } catch (ModuleInitializationException ex) {
+ // ignore
+ } finally {
+ accessAttempted = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Represents a service that can be provided from a module
+ */
+ private static class ModuleProvider {
+ private final ModuleDefinition modDef;
+ private final String name;
+
+ // Comparison is based on name only.
+ private static final Comparator<ModuleProvider> comparator =
+ new Comparator<ModuleProvider>() {
+ public int compare(ModuleProvider m1, ModuleProvider m2) {
+ return m1.modDef.getName().compareTo(m2.modDef.getName());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return this == o;
+ }
+ };
+
+ ModuleProvider(ModuleDefinition modDef, String name) {
+ this.modDef = modDef;
+ this.name = name;
+ }
+
+ String getName() {
+ return name;
+ }
+
+ Version getVersion() {
+ return modDef.getVersion();
+ }
+
+ ModuleDefinition getModuleDefinition() {
+ return modDef;
+ }
+
+ Class<?> getProviderClass() throws ClassNotFoundException, ModuleInitializationException {
+ final Module m = modDef.getModuleInstance();
+ ClassLoader cl = m.getClassLoader();
+ return Class.forName(name, true, cl);
+ }
}
/**
@@ -426,43 +851,158 @@ public final class ServiceLoader<S>
Iterator<Map.Entry<String,S>> knownProviders
= providers.entrySet().iterator();
+ Iterator<ServiceLoaderIterator> lookups = lookupIterators.iterator();
+ ServiceLoaderIterator currentLookup = null;
+
+ Error lastError = null;
+
public boolean hasNext() {
if (knownProviders.hasNext())
return true;
- return lookupIterator.hasNext();
+
+ initLookups();
+ boolean rc = false;
+
+ if (currentLookup.hasNext()) {
+ rc = true;
+ } else {
+ while (lookups.hasNext()) {
+ currentLookup = lookups.next();
+ if (currentLookup.hasNext()) {
+ rc = true;
+ break;
+ }
+ }
+ }
+ return rc;
}
public S next() {
if (knownProviders.hasNext())
return knownProviders.next().getValue();
- return lookupIterator.next();
+
+ initLookups();
+ S rc = null;
+
+ if (currentLookup.hasNext()) {
+ try {
+ rc = currentLookup.next();
+ } catch (ServiceConfigurationError e) {
+ // XXX This could be a real error, or it could be that
+ // a virtual module does not export this service.
+ lastError = e;
+ }
+ }
+
+ if (rc == null) {
+ while (lookups.hasNext()) {
+ currentLookup = lookups.next();
+ if (currentLookup.hasNext()) {
+ try {
+ rc = currentLookup.next();
+ break;
+ } catch (ServiceConfigurationError e) {
+ // XXX This could be a real error, or it could be that
+ // a virtual module does not export this
+ // service.
+ lastError = e;
+ }
+ }
+ }
+ }
+
+ if (rc == null) {
+ if (lastError != null) {
+ throw lastError;
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+ return rc;
}
public void remove() {
throw new UnsupportedOperationException();
}
+ private void initLookups() {
+ if (currentLookup == null && lookups.hasNext()) {
+ lastError = null;
+ currentLookup = lookups.next();
+ }
+ }
};
+ }
+
+ /**
+ * Tries to find a service module in the bootstrap repository for the
+ * given {@code service}.
+ *
+ * @return a ModuleDefinition for {@code service} if one exists in the
+ * bootstrap repository, else null.
+ */
+ private static <S> Module findBootstrapModule(Class<S> service) {
+ Module rc = null;
+ String serviceName = service.getName();
+
+ for (ModuleDefinition md : Repository.getBootstrapRepository().find(serviceQuery)) {
+ Services ss = md.getAnnotation(Services.class);
+ for (String sName : ss.value()) {
+ if (serviceName.equals(sName)) {
+ try {
+ rc = md.getModuleInstance();
+ break;
+ } catch (ModuleInitializationException ex) {
+ // ignore
+ }
+ }
+ }
+ }
+ return rc;
}
/**
* Creates a new service loader for the given service type and class
- * loader.
+ * loader. If both the service and loader are in modules, the loader's
+ * module's repository will be used to lookup provider-configuration files
+ * and provider classes.
*
* @param service
* The interface or abstract class representing the service
*
- * @param loader
- * The class loader to be used to load provider-configuration files
- * and provider classes, or <tt>null</tt> if the system class
- * loader (or, failing that, the bootstrap class loader) is to be
- * used
+ * @param loader
+ * The class loader used to determine the location from which
+ * provider-configuration files and provider classes are loaded.
+ * If <tt>null</tt> the system class loader (or, failing that, the
+ * bootstrap class loader) is used.
*
* @return A new service loader
*/
public static <S> ServiceLoader<S> load(Class<S> service,
ClassLoader loader)
{
+ ClassLoader cl = service.getClassLoader();
+ if (cl == null) {
+ Module m = findBootstrapModule(service);
+ if (m != null) {
+ if (loader == null) {
+ // Use bootstrap repo instead of bootstrap loader
+ return new ServiceLoader<S>(
+ service, Repository.getBootstrapRepository(), m);
+
+ } else if (loader == ClassLoader.getSystemClassLoader()) {
+ // Use system repository and system class loader
+ return new ServiceLoader<S>(
+ service, Repository.getSystemRepository(), loader, m);
+
+ } else if (loader.getModule() != null) {
+ // Use loader's respository
+ return new ServiceLoader<S>(
+ service, loader.getModule().getModuleDefinition().getRepository(), m);
+ }
+ }
+ }
+ // Fall back to pre-modules behavior
return new ServiceLoader<S>(service, loader);
}
@@ -494,7 +1034,53 @@ public final class ServiceLoader<S>
/**
* Creates a new service loader for the given service type, using the
- * extension class loader.
+ * given {@link java.module.Repository} to locate providers.
+ *
+ * @param repository
+ * The repository from which service provider modules will be
+ * obtained
+ *
+ * @param service
+ * The interface or abstract class representing the service
+ *
+ * @return A new service loader
+ *
+ * @throws IllegalArgumentException
+ * if the {@code service} is not in a service module
+ *
+ * @since 1.7
+ */
+ public static <S> ServiceLoader<S> load(Repository repository,
+ Class<S> service)
+ {
+ if (repository == null) {
+ throw new NullPointerException(
+ "repository cannot be null");
+ }
+ ClassLoader cl = service.getClassLoader();
+ if (cl == null) {
+ Module m = findBootstrapModule(service);
+ if (m != null) {
+ return new ServiceLoader<S>(service, repository, m);
+ } else {
+ throw new IllegalArgumentException(
+ "service is not in a service module");
+ }
+ } else if (cl.getModule() == null) {
+ throw new IllegalArgumentException(
+ "service is not in a service module");
+ }
+ return new ServiceLoader<S>(service, repository);
+ }
+
+ /**
+ * Creates a new service loader for the given service type, using the
+ * extension class loader or system repository.
+ *
+ * <ul>
+ * <li>If the service type is in a module, use the system repository.</li>
+ * <li>Otherwise, use the extension class loader.</li>
+ * </ul>
*
* <p> This convenience method simply locates the extension class loader,
* call it <tt><i>extClassLoader</i></tt>, and then returns
@@ -517,13 +1103,27 @@ public final class ServiceLoader<S>
* @return A new service loader
*/
public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
- ClassLoader cl = ClassLoader.getSystemClassLoader();
- ClassLoader prev = null;
- while (cl != null) {
- prev = cl;
- cl = cl.getParent();
- }
- return ServiceLoader.load(service, prev);
+ ClassLoader cl = service.getClassLoader();
+ if (cl != null && cl.getModule() != null) {
+ return ServiceLoader.load(
+ RepositoryConfig.getLastRepository(), service);
+ } else {
+ // If the class is in the bootstrap module, it might represent a
+ // service defined in that module.
+ Module m = findBootstrapModule(service);
+ if (m != null) {
+ return new ServiceLoader<S>(service, Repository.getBootstrapRepository(), m);
+ } else {
+ // Fall back to pre-modules behavior
+ cl = ClassLoader.getSystemClassLoader();
+ ClassLoader prev = null;
+ while (cl != null) {
+ prev = cl;
+ cl = cl.getParent();
+ }
+ return ServiceLoader.load(service, prev);
+ }
+ }
}
/**
@@ -534,5 +1134,4 @@ public final class ServiceLoader<S>
public String toString() {
return "java.util.ServiceLoader[" + service.getName() + "]";
}
-
}
--- a/src/share/classes/sun/module/bootstrap/VirtualModuleDefinitions.java Fri Jun 27 08:14:27 2008 -0700
+++ b/src/share/classes/sun/module/bootstrap/VirtualModuleDefinitions.java Mon Jul 07 10:13:08 2008 -0700
@@ -36,6 +36,9 @@ import java.module.ModuleContent;
import java.module.ModuleContent;
import java.module.annotation.ImportModule;
import java.module.annotation.ImportModules;
+import java.module.annotation.ServiceProvider;
+import java.module.annotation.ServiceProviders;
+import java.module.annotation.Services;
import java.module.annotation.Version;
import java.security.CodeSigner;
import java.util.ArrayList;
@@ -71,6 +74,44 @@ public final class VirtualModuleDefiniti
*/
@Version(PLATFORM_VERSION)
@ModuleName("java.se.core")
+ @Services({
+ "java.nio.channels.spi.SelectorProvider",
+ "java.nio.charset.spi.CharsetProvider",
+ "java.rmi.server.RMIClassLoaderSpi",
+ "java.sql.Driver",
+ "javax.imageio.spi.ImageReader",
+ "javax.imageio.spi.ImageWriter",
+ "javax.imageio.spi.ImageTranscoder",
+ "javax.imageio.spi.ImageInputStream",
+ "javax.imageio.spi.ImageOutputStream",
+ "javax.management.remote.JMXConnectorProvider",
+ "javax.management.remote.JMXConnectorServerProvider",
+ "javax.naming.ldap.StartTlsResponse",
+ "javax.print.PrintServiceLookup",
+ "javax.print.StreamPrintServiceFactory",
+ "com.sun.tools.attach.spi.AttachProvider",
+ "com.sun.jdi.connect.Connector",
+ "com.sun.jdi.connect.Transport"
+ })
+ // XXX Note that some providers are platform-specific: For now they are
+ // added here but it seems we need platform-specific virtual modules.
+ @ServiceProviders({
+ @ServiceProvider(service="com.sun.mirror.apt.AnnotationProcessorFactory",
+ providerClass="com.sun.istack.internal.ws.AnnotationProcessorFactoryImpl"),
+
+ // XXX Need to handle platform-specific providers
+ //@ServiceProvider(service="com.sun.tools.attach.spi.AttachProvider", // Solaris
+ // providerClass="sun.tools.attach.SolarisAttachProvider"),
+ //@ServiceProvider(service="com.sun.tools.attach.spi.AttachProvider", // Windows
+ // providerClass="sun.tools.attach.WindowsAttachProvider"),
+ //@ServiceProvider(service="com.sun.tools.attach.spi.AttachProvider", // Linux
+ // providerClass="sun.tools.attach.LinuxAttachProvider"),
+ //@ServiceProvider(service="javax.print.PrintServiceLookup",
+ // providerClass="sun.print.UnixPrintServiceLookup"),
+
+ @ServiceProvider(service="javax.print.StreamPrintServiceFactory",
+ providerClass="sun.print.PSStreamPrinterFactory")
+ })
@ExportPackages({
"java",
"javax.accessibility",
--- a/src/share/classes/sun/module/core/ProxyModuleLoader.java Fri Jun 27 08:14:27 2008 -0700
+++ b/src/share/classes/sun/module/core/ProxyModuleLoader.java Mon Jul 07 10:13:08 2008 -0700
@@ -26,9 +26,9 @@ package sun.module.core;
package sun.module.core;
import java.io.*;
+import java.net.URL;
+import java.security.SecureClassLoader;
import java.util.*;
-import java.security.SecureClassLoader;
-import java.net.URL;
/**
* This class acts a ModuleLoader proxy, ie. it breaks the catch-22
@@ -100,4 +100,13 @@ public class ProxyModuleLoader extends S
? super.getResourceAsStream(name)
: primaryModuleLoader.getResourceAsStream(name);
}
+
+ @Override
+ public java.module.Module getModule() {
+ if (primaryModuleLoader == null) {
+ return null;
+ } else {
+ return primaryModuleLoader.getModule();
+ }
+ }
}
--- a/src/share/classes/sun/module/repository/RepositoryConfig.java Fri Jun 27 08:14:27 2008 -0700
+++ b/src/share/classes/sun/module/repository/RepositoryConfig.java Mon Jul 07 10:13:08 2008 -0700
@@ -52,29 +52,14 @@ import sun.security.util.PropertyExpande
* Establishes the configuration of a set of repositories in a running JVM. A
* configuration specifies a list of repositories, one of which is a child of
* the bootstrap repository and the others are successive children.
- * Repositories can be configured automatically via configuration files, by
- * setting a system property to the name of a configuration file, or directly
- * by providing them in a {@code java.util.Properties} object.
+ * Repositories can be configured automatically via configuration files, or by
+ * setting a system property to the name of a configuration file.
* <p>
- * An example use use case is:
- * <pre>
- * Repository repo = Modules.newLocalRepository(
- * RepositoryConfig.getSystemRepository(),
- * "application",
- * appDir.getCanonicalFile());
- * ...
- * RepositoryConfig.setSystemRepository(repo);
- * </pre>
* The initial call to {@code getSystemRepository} causes repositories to be
- * configured via configuration files, with the system repository set to the
+ * configured via a configuration file, with the system repository set to the
* configured repository that is most distant (in the parent-child distance of
- * repository instances). Thus {@code repo} uses that most distant repository
- * as its parent, then {@code repo} is set to be the system repository.
- * <p>
- * Note that {@code RepositoryConfig} can be initialized explicitly, instead
- * of relying on the default behavior described above; see {@link
- * LocalRepository#initialize(Map)} and {@link URLRepository#initialize(Map)}.
- *
+ * repository instances).
+
* @since 1.7
*/
public final class RepositoryConfig {
@@ -114,6 +99,9 @@ public final class RepositoryConfig {
/** True once configRepositories has completed. */
private static boolean configDone = false;
+ /** Last repository in the configuration. */
+ private static Repository lastRepository;
+
/** Attribute which designates the parent of a repository. */
private static final String parentAttr = "parent";
@@ -152,6 +140,9 @@ public final class RepositoryConfig {
* repository.
* @throws IllegalArgumentException if the system repository has already
* been set via this method.
+ * @throws SecurityException if a security manager exists and its
+ * {@code checkPermission} method denies access to set the system
+ * repository.
*/
public static void setSystemRepository(Repository r) throws IllegalArgumentException {
SecurityManager sm = System.getSecurityManager();
@@ -176,6 +167,18 @@ public final class RepositoryConfig {
systemRepository = configRepositories();
}
return systemRepository;
+ }
+
+ /**
+ * Returns the repository specified by the repository configuration which
+ * has the largest number of repositories between itself and the bootstrap
+ * repository.
+ * @return the repository configured to be farthest from the bootstrap
+ * repository.
+ */
+ public static synchronized Repository getLastRepository() {
+ getSystemRepository(); // Force initialization
+ return lastRepository;
}
/**
@@ -206,7 +209,7 @@ public final class RepositoryConfig {
}
} else {
throw new RuntimeException(
- "Cannot load repository properties from file " + f);
+ "Cannot load repository properties from file " + f.getAbsolutePath());
}
} catch (PropertyExpander.ExpandException ex) {
throw new RuntimeException(ex);
@@ -225,29 +228,35 @@ public final class RepositoryConfig {
* </pre>
* For each named repository, there can be several attribute/value pairs.
* One and only one named repository must have the attribute
- * "PARENT" with the value "BOOTSTRAP": this indicates which repository
+ * "parent" with the value "bootstrap": this indicates which repository
* is to be created as the immediate child of the bootstrap repository.
- * Each other named repository must have a PARENT, and these must describe
+ * Each other named repository must have a parent, and these must describe
* a list of repositories.
* <p>
- * Each repository must provide a attribute "SOURCE" which
+ * Each repository must provide a attribute "source" which
* indicates the source location of the repository.
* <p>
- * Each repository can optionally provide a "CLASS" attribute, with a
- * corresponding value that indicates the class of the repository.
- * <p>
- * If a CLASS is given, then an instance of that class will be created.
- * The repository class must have a constructor which has a signature like
- * this:
+ * Each repository can optionally provide a "classname" attribute, with a
+ * corresponding value that indicates the name of the Class of the
+ * repository, or a "factoryname" attribute, which indicates the name of
+ * a Class that can create a Repository.
+ * <p>
+ * If classname is given, then an instance of that named class will be
+ * created. The repository class must have a constructor which has a
+ * signature like this:
* <pre>
* FooRepository(Repository parent, String name,
URL source, Map&lt;String, String&gt; config) throws IOException;
* </pre>
- * (<em>Note: Support for CLASS is not yet implemented.</em>)
- * <p>
- * If no CLASS is given, then if the SOURCE value is a URL, a
- * URLRepository will be created; else if the SOURCE is an existing,
- * readable file, a LocalRepository will be created.
+ * <p>
+ * If factoryname is given, an instance of that will be created (but only
+ * once per JVM) and its {@code create} method used to create a repository
+ * instance. See {@link RepositoryFactory}.
+ * <p>
+ * If neither classname nor factoryname is given, an appropriate
+ * repository will be created based on the source. If source
+ * is a file-based URL or a filename, a LocalRepository will be created.
+ * If it is a non-file-based URL, a URLRepository will be created.
* <p>
* Other attributes are allowed, and are particular to the class of
* repository that is created. They are passed to the repository's
@@ -255,20 +264,21 @@ public final class RepositoryConfig {
* @param configProps Properties that configure a list of repositories
* @return The repository in the configuration that is furthest in the
* list from the bootstrap repository.
- */
- public static Repository configRepositories(Properties configProps) {
+ * @throws IllegalStateException if repositories have already been
+ * configured.
+ */
+ private static Repository configRepositories(Properties configProps) {
if (configDone) {
throw new IllegalStateException("Repositories have already been configured.");
}
- Repository rc = null;
if (!configProps.isEmpty()) {
LinkedHashMap<String, Map<String, String>> orderedConfig =
getConfigFromProps(configProps);
- rc = createRepositories(orderedConfig);
+ lastRepository = createRepositories(orderedConfig);
configDone = true;
}
- return rc;
+ return lastRepository;
}
@@ -461,6 +471,8 @@ public final class RepositoryConfig {
* keys are presumed to be ordered such that the first entry describes the
* repository to create as a child of the bootstrap repository, the next
* to create as a child of that, and so on.
+ * @return The repository in the configuration that is furthest in the
+ * list from the bootstrap repository.
*/
private synchronized static Repository createRepositories(
LinkedHashMap<String, Map<String, String>> orderedConfig) {
--- a/test/java/module/repository/RepositoryConfigTest.java Fri Jun 27 08:14:27 2008 -0700
+++ b/test/java/module/repository/RepositoryConfigTest.java Mon Jul 07 10:13:08 2008 -0700
@@ -37,158 +37,163 @@ import sun.module.repository.RepositoryC
* @compile -XDignore.symbol.file RepositoryConfigTest.java
*/
public class RepositoryConfigTest {
+ static File testDir;
+ static File workDir;
+ static File repoDir;
+ static File propsFile;
+
public static void realMain(String[] args) throws Throwable {
- File repoDir = new File(System.getProperty("test.scratch", "."), "RepositoryConfigTestDir");
- File propsFile = null;
-
- try {
- JamUtils.recursiveDelete(repoDir);
-
- // A list of repositories:
- // bootstrap/
- // extension/
- // global/
- // user/
- // ide/
- // remote
- // "remote" is later set as the system repository
- // Note that the parent of repository "ide" is not specifed right
- // here; see checks below.
-
- Properties p = new Properties();
- p.put("extension.parent", "bootstrap");
- p.put("extension.source", getDir(repoDir, "ext").toURI().toURL().toExternalForm());
- p.put("extension.classname", "sun.module.repository.LocalRepository");
- p.put("global.parent", "extension");
- p.put("global.source", getDir(repoDir, "global").toString());
- p.put("user.parent", "global");
- p.put("user.source", getDir(repoDir, "user").toString());
- // XXX To test URLRepository config, need to create a URLRepo
- //p.put("ide.source", getDir(repoDir, "ide").toURI().toURL().toExternalForm());
- p.put("ide.source", getDir(repoDir, "ide").toString());
- p.put("ide.optionOne", "a value");
- p.put("ide.optionToo", "some other value");
- p.put("remote.parent", "ide");
- p.put("remote.source", getDir(repoDir, "remote").toString());
-
- // xxx Need test: Verify if multiple furthest repositories => exception
-
- Repository repo;
-
- // Verify: specify properties file via system property. This will
- // work, but expect an exception because repository 'ide' doesn't
- // specify a parent.
- try {
- propsFile = new File("RepoConfigTest.properties");
- FileOutputStream fos = new FileOutputStream(propsFile);
- p.store(fos, "For RepositoryConfigTest");
- fos.close();
- Properties sysProps = System.getProperties();
- sysProps.put(
- ModuleSystemConfig.REPOSITORY_PROPERTIES_FILE,
- propsFile.getCanonicalPath());
- repo = RepositoryConfig.getSystemRepository();
- fail();
- } catch (RuntimeException ex) {
- expected(ex);
- } catch (Throwable t) {
- unexpected(t);
- }
-
- // Verify: if parent not specified => exception
- try {
- repo = RepositoryConfig.configRepositories(p);
- fail();
- } catch (RuntimeException ex) {
- expected(ex);
- } catch (Throwable t) {
- unexpected(t);
- }
-
- // Verify if parent is not found => exception
- try {
- p.put("ide.parent", "NoParent");
- repo = RepositoryConfig.configRepositories(p);
- fail();
- } catch (RuntimeException ex) {
- expected(ex);
- } catch (Throwable t) {
- unexpected(t);
- }
- p.remove("ide.parent");
-
- // Verify if invalid system property syntax => exception
+ testDir = new File(System.getProperty("test.scratch", "."));
+ workDir = new File(testDir, "RepoConfigTest");
+ repoDir = new File(workDir, "RepoConfigTestRepo");
+
+ // If no args are given, set up a test and separate JVM on this same
+ // class with an argument. When launched with an arg, invoke the
+ // correspondingly named test.
+ if (args.length == 0) {
+ JamUtils.recursiveDelete(workDir);
+ check(repoDir.mkdirs());
+ propsFile = new File(workDir, "RepoConfigTest.properties");
+
+ Properties p = initProperties();
+
+ // Verify: The initial set of properties is such that ide has no
+ // parent
+ launch("noParentSpecified", false);
+
+ // Verify: syntax errors are detected
/* Disabled, since PropertyExpander does not recognize the below
* as a problem.
- try {
- p.put("ide.parent", "${user.home");
- repo = RepositoryConfig.configRepositories(p);
- fail();
- } catch (IllegalArgumentException ex) {
- expected(ex);
- } catch (Throwable t) {
- unexpected(t);
- }
- p.remove("ide.parent");
+ updateProperties(p, "ide.parent", "${user.home");
+ launch("propertyException", false);
*/
- // Make the configuration OK for remaining tests.
- p.put("ide.parent", "user");
-
- // Verify: if classname not fond => exception
- try {
- p.put("ide.classname", "foo.bar.RepositoryImpl");
- repo = RepositoryConfig.configRepositories(p);
- fail();
- } catch (IllegalArgumentException ex) {
- expected(ex);
- } catch (Throwable t) {
- unexpected(t);
- }
- p.remove("ide.classname");
-
- // Verify if dangling repository that is not under main repository chain => exception
- try {
- p.put("dangling.parent", "missing");
- p.put("dangling.source", getDir(repoDir, "dangling").toString());
- repo = RepositoryConfig.configRepositories(p);
- fail();
- } catch (RuntimeException ex) {
- expected(ex);
- p.remove("dangling.parent");
- p.remove("dangling.source");
- } catch (Throwable t) {
- unexpected(t);
- }
-
- // Verify that if correct parent, etc. => ok
- p.put("ide.parent", "user");
- repo = RepositoryConfig.configRepositories(p);
-
- check(repo != null);
- RepositoryConfig.setSystemRepository(repo);
-
- int count = 0;
- String[] repoNames = new String[] {
- "remote", "ide", "user", "global", "extension",
- Repository.getBootstrapRepository().getName()
- };
- for (Repository r = Repository.getSystemRepository();
- r != null;
- r = r.getParent()) {
- if (!check(repoNames[count].equals(r.getName()))) {
- System.out.println("expected " + repoNames[count] + ", got " + r.getName());
- }
- count++;
- }
- check(count == 6);
-
- } finally {
+ // Make the properties OK for remaining tests
+ updateProperties(p, "ide.parent", "user");
+
+ // Verify: last repo is system Repository
+ launch("lastRepoIsSystem", true);
+
+ // Verify: added repo is not last repo
+ launch("addedIsNotLast", true);
+
+ // Verify: expected repositories exist
+ launch("expectedRepositories", true);
+
+ // Verify "dangling" repository causes exception (dangling meaning
+ // repository specified with non-existent parent)
+ p.put("dangling.parent", "missing");
+ updateProperties(p, "dangling.source",
+ getDir(repoDir, "dangling").toString());
+ launch("dangling", false);
+
+
if (failed == 0) {
- JamUtils.recursiveDelete(repoDir);
- if (propsFile != null) propsFile.delete();
- }
- }
+ JamUtils.recursiveDelete(workDir);
+ }
+
+ } else {
+ String testName = args[0];
+ if (testName.equals("lastRepoIsSystem")) {
+ lastRepoIsSystem();
+ } else if (testName.equals("addedIsNotLast")) {
+ addedIsNotLast();
+ } else if (testName.equals("expectedRepositories")) {
+ expectedRepositories();
+ }
+ }
+ }
+
+ static void lastRepoIsSystem() {
+ Repository r = RepositoryConfig.getLastRepository();
+ check(r.equals(Repository.getSystemRepository()));
+ }
+
+ static void addedIsNotLast() throws Throwable {
+ Repository r = Modules.newLocalRepository("foo", new File(repoDir, "bar"));
+ check(r != RepositoryConfig.getLastRepository());
+ check(r != Repository.getSystemRepository());
+ }
+
+ static void expectedRepositories() {
+ int count = 0;
+ String[] repoNames = new String[] {
+ "remote", "ide", "user", "global", "extension",
+ Repository.getBootstrapRepository().getName()
+ };
+ for (Repository r = Repository.getSystemRepository();
+ r != null;
+ r = r.getParent()) {
+ if (!check(repoNames[count].equals(r.getName()))) {
+ System.out.println("expected " + repoNames[count] + ", got " + r.getName());
+ }
+ count++;
+ }
+ check(count == 6);
+ }
+
+ // Creates repository properties. Note that as provided they are invalid;
+ // this is expected.
+ static Properties initProperties() throws Throwable {
+ JamUtils.recursiveDelete(repoDir);
+
+ // A list of repositories:
+ // bootstrap/
+ // extension/
+ // global/
+ // user/
+ // ide/
+ // remote
+ // "remote" is later set as the system repository
+ // Note that the parent of repository "ide" is not specifed right
+ // here; see checks below.
+
+ Properties p = new Properties();
+ p.put("extension.parent", "bootstrap");
+ p.put("extension.source", getDir(repoDir, "ext").toURI().toURL().toExternalForm());
+ p.put("extension.classname", "sun.module.repository.LocalRepository");
+ p.put("global.parent", "extension");
+ p.put("global.source", getDir(repoDir, "global").toString());
+ p.put("user.parent", "global");
+ p.put("user.source", getDir(repoDir, "user").toString());
+ // XXX To test URLRepository config, need to create a URLRepo
+ //p.put("ide.source", getDir(repoDir, "ide").toURI().toURL().toExternalForm());
+ p.put("ide.source", getDir(repoDir, "ide").toString());
+ p.put("ide.optionOne", "a value");
+ p.put("ide.optionToo", "some other value");
+ p.put("remote.parent", "ide");
+ p.put("remote.source", getDir(repoDir, "remote").toString());
+
+ writeProps(p);
+ return p;
+ }
+
+ static void updateProperties(Properties p, String key, String value) throws Throwable {
+ p.put(key, value);
+ writeProps(p);
+ }
+
+ static void writeProps(Properties p) throws Throwable {
+ FileOutputStream fos = new FileOutputStream(propsFile);
+ p.store(fos, "For RepositoryConfigTest");
+ fos.close();
+ }
+
+ static void launch(String testName, boolean positive) throws Throwable {
+ String home = System.getProperty("java.home");
+ String java = home + File.separator + "bin" + File.separator + "java";
+ if (System.getProperty("os.platform").equals("windows")) {
+ java += ".exe";
+ }
+ ProcessBuilder pb = new ProcessBuilder(
+ java,
+ "-Djava.module.repository.properties.file=RepoConfigTest/RepoConfigTest.properties",
+ "RepositoryConfigTest",
+ testName);
+ pb.directory(testDir);
+ Process p = pb.start();
+ int rc = p.waitFor();
+ check(positive ? rc == 0 : rc != 0);
}
private static File getDir(File parent, String s) throws Throwable {
--- a/test/java/module/repository/Test6574851.java Fri Jun 27 08:14:27 2008 -0700
+++ b/test/java/module/repository/Test6574851.java Mon Jul 07 10:13:08 2008 -0700
@@ -24,6 +24,8 @@ import java.io.*;
import java.io.*;
import java.module.Modules;
import java.module.Repository;
+import java.util.HashMap;
+import java.util.Map;
import sun.module.repository.RepositoryConfig;
/**
@@ -34,14 +36,19 @@ import sun.module.repository.RepositoryC
*/
public class Test6574851 {
public static void realMain(String args[]) throws Throwable {
+ try {
+ Map<String, String> config = new HashMap<String, String>();
+ config.put(
+ "sun.module.repository.URLRepository.sourceLocationMustExist",
+ "true");
Repository repo = Modules.newURLRepository(
RepositoryConfig.getSystemRepository(),
"test",
new File(
System.getProperty("test.scratch", "."),
- "Test6574851-DoesNotExist").getCanonicalFile().toURI().toURL());
- try {
- repo.initialize();
+ "Test6574851-DoesNotExist").getCanonicalFile().toURI().toURL(),
+ config);
+ fail();
} catch (IOException ex) {
pass();
} catch (Throwable t) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/module/core/ServiceProcessor.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.module.core;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Service;
+import java.util.ServiceProvider;
+import java.util.Set;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Messager;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+import javax.tools.FileObject;
+import javax.tools.StandardLocation;
+
+/**
+ * An annotation processor for Service and ServiceProvider annotations. It
+ * generates corresponding files under META-INF in the destination directory.
+ *
+ * @since 1.7
+ */
+// XXX Increment to RELEASE_7 when that's in place.
+@SupportedSourceVersion(SourceVersion.RELEASE_6)
+@SupportedAnnotationTypes({"java.util.Service", "java.util.ServiceProvider"})
+public class ServiceProcessor extends AbstractProcessor {
+ /**
+ * Set of classes with the @Service annotation that were discovered
+ * during this compilation.
+ */
+ private final Set<TypeElement> services = new HashSet<TypeElement>();
+
+ /**
+ * Mirrors of classes with the @ServiceProvider annotation that were
+ * discovered during this compilation.
+ */
+ private final Set<TypeElement> providers = new HashSet<TypeElement>();
+
+ /** For error reporting. */
+ private Messager msg;
+
+ /** Set of types supported. */
+ private static Set<String> supportedTypes;
+
+ public ServiceProcessor() {
+ }
+
+ @Override
+ public void init(ProcessingEnvironment pe) {
+ super.init(pe);
+ this.msg = pe.getMessager();
+ }
+
+ /**
+ * Collect classes that have the Service or ServiceProcessor
+ * annotations. When processing is over, write out the corresponding
+ * files under the META-INF directory.
+ */
+ public boolean process(
+ Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (!roundEnv.processingOver()) {
+ if (annotations.isEmpty()) {
+ return true;
+ }
+ for (Element e : roundEnv.getElementsAnnotatedWith(Service.class)) {
+ if (e instanceof TypeElement) {
+ services.add((TypeElement) e);
+ } else {
+ error("Element " + e + " is not a TypeElement");
+ }
+ }
+ for (Element e : roundEnv.getElementsAnnotatedWith(ServiceProvider.class)) {
+ if (e instanceof TypeElement) {
+ providers.add((TypeElement) e);
+ } else {
+ error("Element " + e + " is not a TypeElement");
+ }
+ }
+ } else {
+ createServiceIndex();
+ createServices();
+ }
+ return true;
+ }
+
+ /**
+ * Creates or updates the META-INF/service-index file. Classes with the
+ * Service annotation found in this compilation are added to the existing
+ * file.
+ */
+ private void createServiceIndex() {
+ if (services.size() == 0) {
+ return;
+ }
+
+ FileHelper fh = null;
+ try {
+ fh = new FileHelper("META-INF/service-index", processingEnv);
+
+ // Get existing services, merge in new ones
+ Set<String> classnames = fh.getExistingEntries();
+ for (TypeElement s : services) {
+ classnames.add(s.asType().toString());
+ }
+
+ PrintWriter pw = fh.getPrintWriter();
+ pw.println("# AUTO GENERATED - SERVICE CLASS");
+ for (String name : classnames) {
+ pw.println(name);
+ }
+ pw.close();
+ if (pw.checkError()) {
+ error(
+ "Unspecified error occured while writing service-index file: "
+ + fh.getFilename());
+ }
+ } catch (IOException ex) {
+ error(
+ "Error accessing the service-index file: " + fh.getFilename()
+ + ": " + ex.getMessage());
+ }
+ }
+
+ /**
+ * Creates a META-INF/services/x.y.z for each ServiceProvider class found
+ * in this compilation. <em>Note:</em> The relationship between services
+ * and service providers is based on subtyping.
+ */
+ private void createServices() {
+ if (providers.size() == 0) {
+ return;
+ }
+
+ // For each service provider, find the service it implements, and make a
+ // map from services to service providers.
+ Map<Name, Set<TypeElement>> providedServices =
+ new HashMap<Name, Set<TypeElement>>();
+ Types types = processingEnv.getTypeUtils();
+
+ for (TypeElement p : providers) {
+ List<? extends TypeMirror> supers = p.getInterfaces();
+ for (TypeMirror tm : supers) {
+ TypeElement clazz = (TypeElement) types.asElement(tm);
+ addIfService(clazz, p, providedServices);
+ }
+ TypeMirror superclass = p.getSuperclass();
+ while (superclass.getKind() != TypeKind.NONE) {
+ TypeElement clazz = (TypeElement) types.asElement(superclass);
+ addIfService(clazz, p, providedServices);
+ superclass = clazz.getSuperclass();
+ }
+ }
+
+ // For each service, create the corresponding META-INF/services file.
+ for (Name s : providedServices.keySet()) {
+ FileHelper fh = null;
+ try {
+ fh = new FileHelper("META-INF/services", s.toString(), processingEnv);
+
+ // Get existing service providers, merge in new ones
+ Set<String> classnames = fh.getExistingEntries();
+ for (TypeElement p : providedServices.get(s)) {
+ classnames.add(p.toString());
+ }
+
+ PrintWriter pw = fh.getPrintWriter();
+ pw.println("# AUTO GENERATED - SERVICES PROVIDERS");
+ for (TypeElement p : providedServices.get(s)) {
+ pw.println(p.toString());
+ }
+ pw.close();
+ if (pw.checkError()) {
+ error(
+ "Unspecified error occurred while writing services file for " + s);
+ }
+ } catch (IOException ex) {
+ error(
+ "Error accessing the services file for " + fh.getFilename()
+ + ": " + ex.getMessage());
+ }
+ }
+ }
+
+ /**
+ * If e has a Service annotation, add as one of its providers in the given
+ * set.
+ * @param e {@code TypeElement} that might be a
+ * @param p {@code TypeElement} that is a {@ @ServiceProvider}
+ * @param providedServices map from Service names to set of ServiceProviders
+ */
+ private void addIfService(TypeElement e, TypeElement p,
+ Map<Name, Set<TypeElement>> providedServices) {
+ if (e.getAnnotation(Service.class) != null) {
+ Name serviceName = e.getQualifiedName();
+ Set<TypeElement> ps = providedServices.get(serviceName);
+ if (ps == null) {
+ ps = new HashSet<TypeElement>();
+ providedServices.put(serviceName, ps);
+ }
+ ps.add(p);
+ }
+ }
+
+ /**
+ * Helps in using FileObjects
+ * @see #createServiceIndex
+ * @see #createServices
+ */
+ private static class FileHelper {
+ private final String prefix;
+ private final String suffix;
+ private final ProcessingEnvironment pe;
+
+ private String filename;
+
+ FileHelper(String path, ProcessingEnvironment pe) {
+ this(path, null, pe);
+ }
+
+ FileHelper(String prefix, String suffix, ProcessingEnvironment pe) {
+ this.prefix = prefix;
+ this.suffix = suffix;
+ this.pe = pe;
+ }
+
+ String getFilename() {
+ return filename;
+ }
+
+ /**
+ * @return set of entries from the FileObject corresponding to the
+ * {@code prefix} and {@suffix} with which this {@code FileHelper} was
+ * created.
+ */
+ Set<String> getExistingEntries() throws IOException {
+ Set<String> rc = new HashSet<String>();
+ FileObject input = pe.getFiler().getResource(
+ StandardLocation.CLASS_OUTPUT,
+ "", prefix + (suffix == null ? "" : "/" + suffix));
+ filename = input.toUri().getPath();
+ File sFile = new File(filename);
+ if (sFile.exists()) {
+ BufferedReader r = null;
+ try {
+ r = new BufferedReader(input.openReader(true));
+ String s;
+ while ((s = r.readLine()) != null) {
+ s = s.trim();
+ if (!s.startsWith("#")) {
+ rc.add(s);
+ }
+ }
+ } finally {
+ if (r != null) {
+ r.close();
+ }
+ }
+ }
+ return rc;
+ }
+
+ /**
+ * @return a {@code PrintWriter} for writing to the FileObject
+ * corresponding to the {@code prefix} and {@suffix} with which this
+ * {@code FileHelper} was created.
+ */
+ PrintWriter getPrintWriter() throws IOException {
+ new File(filename).getParentFile().mkdirs();
+ FileObject output = pe.getFiler().createResource(
+ StandardLocation.CLASS_OUTPUT,
+ "", prefix + (suffix == null ? "" : "/" + suffix),
+ (TypeElement) null);
+ return new PrintWriter(output.openWriter());
+ }
+ }
+
+ void error(String s) {
+ msg.printMessage(Diagnostic.Kind.ERROR, "ServiceProcessor: " + s);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/modinit/mtest/service/InstalledLookup.mtest Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,36 @@
+# This tests that service providers can be loaded when both they and their
+# service are in the java.se.core service module
+#
+# This is similar to PrintServiceLookup.mtest except for the call to
+# ServiceLoader.loadInstalled()
+#
+# Defines InstalledLookupClient, which looks up a PrintService.
+>>> begin module InstalledLookupClient
+> annotations
+@MainClass("InstalledLookupClient.Main")
+@ImportModules({
+ @ImportModule(name="java.se.core")
+})
+>> begin class InstalledLookupClient.Main
+ Iterator<javax.print.StreamPrintServiceFactory> loader =
+ ServiceLoader.loadInstalled(javax.print.StreamPrintServiceFactory.class).iterator();
+ javax.print.StreamPrintServiceFactory provider = loader.next();
+ String providerName = provider.getClass().getName();
+ if (!providerName.equals("sun.print.PSStreamPrinterFactory")) {
+ throw new Exception("got unexpected provider name: " + providerName);
+ }
+ try {
+ if (loader.hasNext()) {
+ System.err.println("FAILED: loader.hasNext() == true");
+ System.exit(1);
+ }
+ loader.next();
+ // fail
+ } catch (NoSuchElementException ex) {
+ // pass
+ }
+>> end class
+>>> end module
+>>> begin test InstalledLookupClient
+return
+>>> end test
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/modinit/mtest/service/NullPrintServiceLookup.mtest Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,37 @@
+# This tests that service providers can be loaded when both they and their
+# service are in the java.se.core service module
+#
+# This similar to PrintServiceLookup.mtest except for the call to
+# ServiceLoader.load()
+#
+# Defines PrintLookupClient, which looks up a PrintService.
+>>> begin module PrintLookupClient
+> annotations
+@MainClass("PrintLookupClient.Main")
+@ImportModules({
+ @ImportModule(name="java.se.core")
+})
+>> begin class PrintLookupClient.Main
+ Iterator<javax.print.StreamPrintServiceFactory> loader =
+ ServiceLoader.load(javax.print.StreamPrintServiceFactory.class,
+ (ClassLoader) null).iterator();
+ javax.print.StreamPrintServiceFactory provider = loader.next();
+ String providerName = provider.getClass().getName();
+ if (!providerName.equals("sun.print.PSStreamPrinterFactory")) {
+ throw new Exception("got unexpected provider name: " + providerName);
+ }
+ try {
+ if (loader.hasNext()) {
+ System.err.println("FAILED: loader.hasNext() == true");
+ System.exit(1);
+ }
+ loader.next();
+ // fail
+ } catch (NoSuchElementException ex) {
+ // pass
+ }
+>> end class
+>>> end module
+>>> begin test PrintLookupClient
+return
+>>> end test
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/modinit/mtest/service/PrintServiceLookup.mtest Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,33 @@
+# This tests that service providers can be loaded when both they and their
+# service are in the java.se.core service module
+#
+# Defines PrintLookupClient, which looks up a PrintService.
+>>> begin module PrintLookupClient
+> annotations
+@MainClass("PrintLookupClient.Main")
+@ImportModules({
+ @ImportModule(name="java.se.core")
+})
+>> begin class PrintLookupClient.Main
+ Iterator<javax.print.StreamPrintServiceFactory> loader =
+ ServiceLoader.load(javax.print.StreamPrintServiceFactory.class).iterator();
+ javax.print.StreamPrintServiceFactory provider = loader.next();
+ String providerName = provider.getClass().getName();
+ if (!providerName.equals("sun.print.PSStreamPrinterFactory")) {
+ throw new Exception("got unexpected provider name: " + providerName);
+ }
+ try {
+ if (loader.hasNext()) {
+ System.err.println("FAILED: loader.hasNext() == true");
+ System.exit(1);
+ }
+ loader.next();
+ // fail
+ } catch (NoSuchElementException ex) {
+ // pass
+ }
+>> end class
+>>> end module
+>>> begin test PrintLookupClient
+return
+>>> end test
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/modinit/mtest/service/SqlDriver.mtest Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,59 @@
+# This tests that service-provider modules can be loaded when their
+# corresponding service-module is java.se.core service module
+#
+# Defines Provider, SqlDriverClient
+# Provider is a @ServiceProvider for java.sql.Driver
+# SqlDriverClient is a client
+>>> begin module Provider
+> annotations
+@ServiceProviders({
+ @ServiceProvider(service="java.sql.Driver", providerClass="Provider.TestDriver")
+})
+@ImportModules({
+ @ImportModule(name="java.se.core")
+})
+> export
+Provider.TestDriver
+>> begin class Provider.TestDriver
+> import
+import java.sql.*;
+> super
+implements java.sql.Driver
+> body
+ public boolean acceptsURL(String url) { return true; }
+ public Connection connect(String url, Properties info) { return null; }
+ public int getMajorVersion() { return 1; }
+ public int getMinorVersion() { return 1; }
+ public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) { return null; }
+ public boolean jdbcCompliant() { return true; }
+>> end class
+>>> end module
+>>> begin module SqlDriverClient
+> annotations
+@MainClass("SqlDriverClient.Main")
+@ImportModules({
+ @ImportModule(name="java.se.core")
+})
+>> begin class SqlDriverClient.Main
+ Iterator<java.sql.Driver> loader =
+ ServiceLoader.load(repository, java.sql.Driver.class).iterator();
+ java.sql.Driver provider = loader.next();
+ String providerName = provider.getClass().getName();
+ if (!providerName.equals("Provider.TestDriver")) {
+ throw new Exception("got unexpected provider name: " + providerName);
+ }
+ try {
+ if (loader.hasNext()) {
+ System.err.println("FAILED: loader.hasNext() == true");
+ System.exit(1);
+ }
+ loader.next();
+ // fail
+ } catch (NoSuchElementException ex) {
+ // pass
+ }
+>> end class
+>>> end module
+>>> begin test SqlDriverClient
+return
+>>> end test
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/CharsetServiceTest.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.module.ModuleArchiveInfo;
+import java.module.ModuleDefinition;
+import java.module.Modules;
+import java.module.Repository;
+import java.util.*;
+import javax.tools.*;
+import sun.module.JamUtils;
+import sun.module.tools.JRepo;
+
+/**
+ * @test CharsetServiceTest.java
+ * @summary Test that a service-provider module can be accessed via a service
+ * that is in java.se.core.
+ * @compile -XDignore.symbol.file ServiceTest.java CharsetServiceTest.java
+ * @run main CharsetServiceTest
+ */
+public class CharsetServiceTest extends ServiceTest {
+ String getScratchDirName() {
+ return "CharServTest";
+ }
+
+ String getPkgName() {
+ return "charserv";
+ }
+
+ public static void realMain(String args[]) throws Throwable {
+ new CharsetServiceTest().run(args);
+ }
+
+ /**
+ * Creates a service-provider module and a client. The client verifies
+ * that it can access the service provider in the service-provider
+ * module.
+ */
+ void run(String args[]) throws Throwable {
+ File classesDir = new File(scratchDir, "classes");
+ compileSources(srcDir, classesDir);
+
+ File providerJam = createJam(pkgName, "provider", scratchDir, "provider.jam");
+ File clientJam = createJam(pkgName, "client", scratchDir);
+
+ // Create a JAR file containing a provider and put it on the classpath
+ File services = new File(scratchDir, "classes/META-INF/services");
+ services.mkdirs();
+ services = new File(services, "java.nio.charset.spi.CharsetProvider");
+ PrintWriter pw = new PrintWriter(services);
+ pw.println("charserv.other.CharsetServiceProviderOnClasspath");
+ pw.close();
+ check(!pw.checkError());
+ File providerJar = createJar(pkgName, "other", scratchDir,
+ "other/CharsetServiceProviderOnClasspath.class");
+
+ repo.install(providerJam.toURI().toURL());
+ ModuleArchiveInfo client = repo.install(clientJam.toURI().toURL());
+
+ // Check JAM files in repository
+ check(repo.findAll().size() > 0);
+ check(repo.list().size() > 0);
+
+ dump(repo);
+
+ String jamName = JamUtils.getJamFilename(
+ client.getName(), client.getVersion(), null, null) + ".jam";
+ runJavaCmd("client",
+ "-classpath",
+ providerJar.getCanonicalPath(),
+ "-jam",
+ new File(repoDir, jamName).getCanonicalPath());
+ }
+
+ File createJar(String pkgName, String srcDir, File destDir, String contentPath) throws Exception {
+ File rc = new File(destDir, srcDir + ".jar");
+ String classesDir = destDir + "/classes";
+ String cmd = "cf ";
+ cmd += rc.getCanonicalPath() + " ";
+ if (new File(classesDir, "META-INF").exists()) {
+ cmd += "-C " + classesDir + " META-INF ";
+ }
+ cmd += "-C ";
+ cmd += classesDir + " ";
+ cmd += pkgName + "/" + contentPath;
+
+ debug("jar: " + cmd);
+ sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jam");
+ if (!jarTool.run(cmd.split(" "))) {
+ throw new Exception("jar failed for " + srcDir);
+ }
+ return rc;
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/ClasspathServiceTest.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.module.ModuleArchiveInfo;
+import java.module.ModuleDefinition;
+import java.module.Modules;
+import java.module.Repository;
+import java.util.*;
+import javax.tools.*;
+import sun.module.JamUtils;
+import sun.module.tools.JRepo;
+
+/**
+ * @test ClasspathServiceTest.java
+ * @summary Test that a service-provider module can access code that is on the
+ * classpath.
+ * @compile -XDignore.symbol.file ServiceTest.java ClasspathServiceTest.java
+ * @run main ClasspathServiceTest
+ */
+public class ClasspathServiceTest extends ServiceTest {
+ String getScratchDirName() {
+ return "CpServTest";
+ }
+
+ String getPkgName() {
+ return "cpserv";
+ }
+
+ public static void realMain(String args[]) throws Throwable {
+ new ClasspathServiceTest().run(args);
+ }
+
+ /**
+ * Creates a service-provider module and a client. The client verifies
+ * that it can access the service provider in the service-provider
+ * module.
+ */
+ void run(String args[]) throws Throwable {
+ File classesDir = new File(scratchDir, "classes");
+ compileSources(srcDir, classesDir);
+
+ File clientJam = createJam(pkgName, "client", scratchDir);
+ File serviceJam = createJam(pkgName, "service", scratchDir);
+
+ repo.install(serviceJam.toURI().toURL());
+ ModuleArchiveInfo client = repo.install(clientJam.toURI().toURL());
+
+ // Check JAM files in repository
+ check(repo.findAll().size() > 0);
+ check(repo.list().size() > 0);
+
+ dump(repo);
+
+ String jamName = JamUtils.getJamFilename(
+ client.getName(), client.getVersion(), null, null) + ".jam";
+ runJavaCmd("client",
+ "-classpath",
+ classesDir.getCanonicalPath(),
+ "-jam",
+ new File(repoDir, jamName).getCanonicalPath());
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/ClientServiceTest.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.module.ModuleArchiveInfo;
+import java.module.ModuleDefinition;
+import java.module.Modules;
+import java.module.Repository;
+import java.util.*;
+import javax.tools.*;
+import sun.module.JamUtils;
+import sun.module.tools.JRepo;
+
+/**
+ * @test ClientServiceTest.java
+ * @summary Test a service provider module can be directly accessed from
+ * client code, as opposed to from a service module.
+ * @compile -XDignore.symbol.file ServiceTest.java ClientServiceTest.java
+ * @run main ClientServiceTest
+ */
+public class ClientServiceTest extends ServiceTest {
+ String getScratchDirName() {
+ return "CliServTest";
+ }
+
+ String getPkgName() {
+ return "cliserv";
+ }
+
+ public static void realMain(String args[]) throws Throwable {
+ new ClientServiceTest().run(args);
+ }
+
+ /**
+ * Creates a service module, provider module and a client. The client
+ * uses the ServiceLoader API directly to access the service. Contrast
+ * this with the "usual/expected" case, in which the client is expected to
+ * access a service module which in turn accesses the service provider
+ * module(s).
+ */
+ void run(String args[]) throws Throwable {
+ File classesDir = new File(scratchDir, "classes");
+ compileSources(srcDir, classesDir);
+
+ File serviceJam = createJam(
+ pkgName, "service", scratchDir, "service.jam");
+ File providerJam = createJam(
+ pkgName, "provider", scratchDir, "provider.jam");
+ File clientJam = createJam(pkgName, "client", scratchDir);
+
+ repo.install(serviceJam.toURI().toURL());
+ repo.install(providerJam.toURI().toURL());
+ ModuleArchiveInfo client = repo.install(clientJam.toURI().toURL());
+
+ // Check JAM files in repository
+ check(repo.findAll().size() > 0);
+ check(repo.list().size() > 0);
+
+ dump(repo);
+
+ // The client imports the service and invokes ServiceLoader.load()
+ // itself, instead of the more usual case in which
+ // ServiceLoader.load() is invoked from within the service.
+
+ String jamName = JamUtils.getJamFilename(
+ client.getName(), client.getVersion(), null, null) + ".jam";
+
+ // Here the client is in a module
+ runJavaCmd("client",
+ false,
+ "-jam",
+ new File(repoDir, jamName).getCanonicalPath());
+
+ // Here the client is on the classpath instead of in a module
+ runJavaCmd("clientClass",
+ "-classpath",
+ classesDir.getCanonicalPath(),
+ "cliserv.client.MainCP");
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/DefaultServiceTest.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.module.ModuleArchiveInfo;
+import java.module.ModuleDefinition;
+import java.module.Modules;
+import java.module.Repository;
+import java.util.ArrayList;
+import java.util.List;
+import javax.tools.*;
+import sun.module.JamUtils;
+import sun.module.tools.JRepo;
+
+/**
+ * @test DefaultServiceTest.java
+ * @summary Tests default service providers in modules.
+ * @compile -XDignore.symbol.file ServiceTest.java DefaultServiceTest.java
+ * @run main DefaultServiceTest
+ */
+public class DefaultServiceTest extends ServiceTest {
+ String getScratchDirName() {
+ return "DefServTest";
+ }
+
+ String getPkgName() {
+ return "defserv";
+ }
+
+ public static void realMain(String args[]) throws Throwable {
+ new DefaultServiceTest().run(args);
+ }
+
+ void run(String args[]) throws Throwable {
+ compileSources(srcDir, new File(scratchDir, "classes"));
+
+ File serviceJam = createJam(pkgName, "service", scratchDir);
+ File providerJam = createJam(pkgName, "provider", scratchDir);
+ File clientJam = createJam(pkgName, "client", scratchDir);
+
+ repo.install(serviceJam.toURI().toURL());
+ repo.install(providerJam.toURI().toURL());
+ ModuleArchiveInfo client = repo.install(clientJam.toURI().toURL());
+
+ // Check JAM files in repository
+ check(repo.findAll().size() > 0);
+ check(repo.list().size() > 0);
+
+ dump(repo);
+
+ String jamName = JamUtils.getJamFilename(
+ client.getName(), client.getVersion(), null, null) + ".jam";
+ runJavaCmd("client",
+ "-jam",
+ new File(repoDir, jamName).getCanonicalPath());
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/ModuleServiceTest.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.module.*;
+import java.module.annotation.MainClass;
+import java.util.*;
+import sun.module.JamUtils;
+import sun.module.tools.JRepo;
+
+/**
+ * @test ModuleServiceTest.java
+ * @summary Test the ServiceProcessor annotation processor.
+ * @compile -XDignore.symbol.file ServiceTest.java ModuleServiceTest.java
+ * @run main ModuleServiceTest
+ */
+public class ModuleServiceTest extends ServiceTest {
+ String getScratchDirName() {
+ return "ModServTest";
+ }
+
+ String getPkgName() {
+ return "modserv";
+ }
+
+ public static void realMain(String args[]) throws Throwable {
+ new ModuleServiceTest().run(args);
+ }
+
+ void run(String args[]) throws Throwable {
+ compileSources(srcDir, new File(scratchDir, "classes"));
+
+ /*
+ * Check that annotations are present
+ */
+ TestLoader tl = new TestLoader("service", scratchDirName);
+ Class<?> clazz = tl.findClass("modserv.service.CodecSet");
+ Service serviceAnno = clazz.getAnnotation(Service.class);
+ debug("Service annotation=" + serviceAnno);
+ check(serviceAnno != null);
+ BufferedReader br = new BufferedReader(
+ new InputStreamReader(tl.getResourceAsStream("META-INF/service-index")));
+ String s = br.readLine(); // skip header/comment
+ s = br.readLine();
+ check(s.equals("modserv.service.CodecSet"));
+
+ tl = new TestLoader("provider1", scratchDirName);
+ clazz = tl.findClass("modserv.provider1.StandardCodecs");
+ ServiceProvider providerAnno = clazz.getAnnotation(ServiceProvider.class);
+ debug("ServiceProvider annotation=" + providerAnno);
+ check(providerAnno != null);
+ br = new BufferedReader(
+ new InputStreamReader(tl.getResourceAsStream("META-INF/services/modserv.service.CodecSet")));
+ s = br.readLine(); // skip header/comment
+ int count = 0;
+
+ tl = new TestLoader("provider3", scratchDirName);
+ clazz = tl.findClass("modserv.provider3.ImplCodecs");
+ providerAnno = clazz.getAnnotation(ServiceProvider.class);
+ debug("ServiceProvider annotation=" + providerAnno);
+ check(providerAnno != null);
+ br = new BufferedReader(
+ new InputStreamReader(tl.getResourceAsStream("META-INF/services/modserv.service.CodecSet")));
+ s = br.readLine(); // skip header/comment
+
+ // Create JAM files
+ File serviceJam = createJam(pkgName, "service", scratchDir);
+ File provider1Jam = createJam(pkgName, "provider1", scratchDir);
+ File provider2Jam = createJam(pkgName, "provider2", scratchDir);
+ File clientJam = createJam(pkgName, "client", scratchDir);
+ File provider3Jam = createJam(pkgName, "provider3", scratchDir);
+
+ // Check JAM files
+ repo.install(serviceJam.toURI().toURL());
+ repo.install(provider1Jam.toURI().toURL());
+ repo.install(provider2Jam.toURI().toURL());
+ ModuleArchiveInfo client = repo.install(clientJam.toURI().toURL());
+ repo.install(provider3Jam.toURI().toURL());
+
+ dump(repo);
+
+ /*
+ * Check that the user has provided annotations on the super package
+ * corresponding to those in the source files of the services and
+ * providers.
+ */
+ ModuleDefinition md = repo.find("modserv.service");
+ java.module.annotation.Services servicesAnno =
+ md.getAnnotation(java.module.annotation.Services.class);
+ check(servicesAnno.value().length == 1);
+ check(servicesAnno.value()[0].equals("modserv.service.CodecSet"));
+
+ ModuleDefinition mdP = repo.find("modserv.provider1");
+ java.module.annotation.ServiceProviders provider1Anno =
+ mdP.getAnnotation(java.module.annotation.ServiceProviders.class);
+ java.module.annotation.ServiceProvider[] providerAnnos = provider1Anno.value();
+ check(providerAnnos.length == 2);
+ for (int i = 0; i < providerAnnos.length; i++) {
+ check(providerAnnos[i].service().equals("modserv.service.CodecSet"));
+ }
+
+ ModuleDefinition mdA = repo.find("modserv.provider2");
+ java.module.annotation.ServiceProviders provider2Anno =
+ mdA.getAnnotation(java.module.annotation.ServiceProviders.class);
+ java.module.annotation.ServiceProvider[] provider2Annos = provider2Anno.value();
+ check(provider2Annos.length == 1);
+ // Skip check on specifics of provider annotations as that will be
+ // checked by "provider1" above and since this one includes a version,
+ // it is tougher to check.
+
+ // Check that provider's version is less than provider2's version
+ check(mdP.getVersion().compareTo(mdA.getVersion()) < 0);
+ String jamName = JamUtils.getJamFilename(
+ client.getName(), client.getVersion(), null, null) + ".jam";
+ runJavaCmd("client",
+ "-jam",
+ new File(repoDir, jamName).getCanonicalPath());
+ }
+
+ /**
+ * A ClassLoader which provides access to classes compiled in this test.
+ */
+ static class TestLoader extends ClassLoader {
+ private final String classDir;
+
+ TestLoader(String dirName, String scratchDirName) {
+ classDir = scratchDirName + "/classes/";
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ Class<?> rc = null;
+ try {
+ byte[] b = readFile(
+ new File(classDir, name.replaceAll("\\.", "/") + ".class"));
+ rc = defineClass(name, b, 0, b.length);
+ } catch (IOException ex) {
+ unexpected(ex);
+ }
+ return rc;
+ }
+
+ @Override
+ public InputStream getResourceAsStream(String name) {
+ InputStream rc = null;
+ try {
+ rc = new FileInputStream(new File(classDir, name));
+ } catch (IOException ex) {
+ unexpected(ex);
+ }
+ return rc;
+ }
+
+ private static byte[] readFile(File file) throws IOException {
+ if (file.isFile() == false) {
+ throw new IOException("Not a regular file: " + file);
+ }
+ long llen = file.length();
+ if (llen > 64 * 1024 * 1024) { // 64 MB
+ throw new IOException("File too large: " + file);
+ }
+ InputStream in = new FileInputStream(file);
+ int len = (int)llen;
+ byte[] data = new byte[len];
+ int ofs = 0;
+ while (len > 0) {
+ int n = in.read(data, ofs, len);
+ if (n < 0) {
+ break;
+ }
+ len -= n;
+ ofs += n;
+ }
+ in.close();
+ if (len != 0) {
+ throw new IOException("Could not read file");
+ }
+ return data;
+ }
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/README.txt Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,93 @@
+There are two sets of ServiceLoader - related tests:
+
+* Those in test/java/module/service (this directory)
+* Those in test/java/module/modinit/mtest/service
+
+test/java/module/service
+------------------------
+
+ServiceTest is a base class for the actual testcases. Each testcase has some
+supporting files under the src directory, related as follows:
+
+ClasspathServiceTest.java src/cpserv
+CharsetServiceTest.java src/charserv
+ClientServiceTest.java src/cliserv
+DefaultServiceTest.java src/defserv
+ModuleServiceTest.java src/modserv
+ReexportServiceTest.java src/rxpserv
+RepositoryServiceTest.java src/reposerv
+VersionServiceTest.java src/verserv
+
+In general, each test creates some jam files, installs them into a repository,
+and then launches another JVM that accesses them. For each test there is a
+client, e.g. src/defserv/client/Main.java, which does the actual testing.
+Testing is limited to ensuring that the correct providers are loaded at the
+in the correct order.
+
+The process of creating JAMs for each test involves compiling corresponding
+code under src. The client and service classes use @Service and
+@ServiceProvider annotations. The code which runs javac to compile these is
+in ServiceTest, and invocation of javac includes a -processor directive to
+cause use of sun.module.core.ServiceProcessor.
+
+Below is a brief description of each test. There is more information in each
+testcase. In general, looking at a *Test.java and it's corresponding
+src/*/client/Main.java will give a good idea of what the test is doing.
+
+* ClasspathServiceTest: Ensures that a service-provider module can access code
+that is on the classpath if the client imports the java.classpath module.
+
+* CharsetServiceTest: Ensures that a service-provider module can be accessed
+via a service that is in java.se.core.
+
+* ClientServiceTest: Ensures that a service-provider can be accessed when the
+client directly calls ServiceLoader.load. Contrast this with the expected
+case (embodied in other testcases) in which it is the service class itself
+which calls ServiceLoader.load.
+
+* DefaultServiceTest: Ensures that default service-providers are available as
+expected.
+
+* ModuleServiceTest: This test differs from the others, in that much of it is
+devoted to ensuring that sun.module.service.ServiceProcessor is working
+correctly. It expects certain files to have been put into the JAMs with
+certain contents (e.g. META-INF/service-index).
+
+* ReexportServiceTest: Ensures that service-providers can be obtained from
+modules that are reexported from one to another.
+
+* RepositoryServiceTest: Ensures that services and providers can be in
+different repositories; exercises ServiceLoader.load(Class<S>, Repository).
+
+* VersionServiceTest: Ensures that the correct version of a service-provider
+is obtained in the presence of multiple versions.
+
+
+test/java/module/modinit/mtest/service
+--------------------------------------
+
+These tests use the RunMTest driver (in test/java/module/modinit); the source
+for each test is a single ".mtest" file. There is a description in each file;
+here is a summary:
+
+* SqlDriver: Ensures that a java.se.core can act as a service-module with
+service providers in separate service-provider modules.
+
+* PrintServiceLookup: Ensures that java.se.core can act as both a
+service-module and a service-provider module when appropriate.
+
+* NullPrintServiceLookup: Same as PrintServiceLookup except invokes a
+different call to ServiceLoader.load().
+
+* InstalledLookup: Same as PrintServiceLookup except invokes
+ServiceLoader.loadInstalled().
+
+
+Annotation Processing
+---------------------
+
+Several of the tests' super_package.java files use the
+java.module.annotation.Services and java.module.annotation.ServiceProcessor
+annotations. These are processed by sun.moule.core.ServiceProcessor.
+Javac compilation does not (currently) include that processor by default. It
+is enabled in ServiceTest.compileSources.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/ReexportServiceTest.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.module.ModuleArchiveInfo;
+import java.module.ModuleDefinition;
+import java.module.Modules;
+import java.module.Repository;
+import java.util.*;
+import javax.tools.*;
+import sun.module.JamUtils;
+import sun.module.tools.JRepo;
+
+/**
+ * @test ReexportServiceTest.java
+ * @summary Test a service provider module correctly accesses services that
+ * are indirectly imported.
+ * @compile -XDignore.symbol.file ServiceTest.java ReexportServiceTest.java
+ * @run main ReexportServiceTest
+ */
+public class ReexportServiceTest extends ServiceTest {
+ String getScratchDirName() {
+ return "RxpServTest";
+ }
+
+ String getPkgName() {
+ return "rxpserv";
+ }
+
+ public static void realMain(String args[]) throws Throwable {
+ new ReexportServiceTest().run(args);
+ }
+
+ /**
+ * Creates a service module, provider module and a client. The client
+ * uses the ServiceLoader API directly to access the service. Contrast
+ * this with the "usual/expected" case, in which the client is expected to
+ * access a service module which in turn accesses the service provider
+ * module(s).
+ */
+ void run(String args[]) throws Throwable {
+ /* The modules in this test are arranged thus:
+ * Let IMP be Import
+ * Let IMPT be Import Transitively
+ * Let IMPRT be Import and Reexport Transitively
+ *
+ * ServiceLoader IMP IMP IMP
+ * Caller -------------> Provider V1 ---> Extra --> Provider V2 ---> Service V2
+ * | |
+ * | | IMPRT
+ * V V
+ * Service V1 Service V1
+ *
+ * The import from Provider V1 to Service V1 is through the module
+ * named "transitive". The import from Provider V2 to Service V2 is
+ * through the module named "extra".
+ */
+
+ File classesDir = new File(scratchDir, "classes");
+ compileSources(srcDir, classesDir);
+
+ File serviceV1Jam = createJam(pkgName, "service", scratchDir, "serviceV1.jam");
+ File providerV1Jam = createJam(pkgName, "provider", scratchDir, "providerV1.jam");
+ File transitiveJam = createJam(pkgName, "transitive", scratchDir);
+ File extraJam = createJam(pkgName, "extra", scratchDir);
+ File clientJam = createJam(pkgName, "client", scratchDir);
+
+ Map<String, String> annotations = new HashMap<String, String>();
+
+ annotations.put("@Version(", "@Version(\"2.0\")");
+ redefineAnnotations(annotations, "service");
+ compileSources(scratchDir, classesDir);
+ File serviceV2Jam = createJam(pkgName, "service", scratchDir, "serviceV2.jam");
+
+ annotations.clear();
+ annotations.put("@Version(", "@Version(\"2.0\")");
+ annotations.put("@ImportModules(",
+ "@ImportModules({\n"
+ + " @ImportModule(name=\"rxpserv.service\", version=\"2.0\")\n"
+ + "})");
+ redefineAnnotations(annotations, "provider");
+ compileSources(scratchDir, classesDir);
+ File providerV2Jam = createJam(pkgName, "provider", scratchDir, "providerV2.jam");
+
+ repo.install(serviceV1Jam.toURI().toURL());
+ repo.install(serviceV2Jam.toURI().toURL());
+ repo.install(providerV1Jam.toURI().toURL());
+ repo.install(providerV2Jam.toURI().toURL());
+ repo.install(transitiveJam.toURI().toURL());
+ repo.install(extraJam.toURI().toURL());
+ ModuleArchiveInfo client = repo.install(clientJam.toURI().toURL());
+
+ // Check JAM files in repository
+ check(repo.findAll().size() > 0);
+ check(repo.list().size() > 0);
+
+ dump(repo);
+
+ String jamName = JamUtils.getJamFilename(
+ client.getName(), client.getVersion(), null, null) + ".jam";
+ runJavaCmd("client",
+ "-jam",
+ new File(repoDir, jamName).getCanonicalPath());
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/RepositoryServiceTest.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.module.ModuleArchiveInfo;
+import java.module.ModuleDefinition;
+import java.module.Modules;
+import java.module.Repository;
+import java.util.*;
+import javax.tools.*;
+import sun.module.JamUtils;
+import sun.module.tools.JRepo;
+
+/**
+ * @test RepositoryServiceTest.java
+ * @summary Tests that services and providers load correctly from different
+ * repositories.
+ * @compile -XDignore.symbol.file ServiceTest.java RepositoryServiceTest.java
+ * @run main RepositoryServiceTest
+ */
+public class RepositoryServiceTest extends ServiceTest {
+ String getScratchDirName() {
+ return "RepoServTest";
+ }
+
+ String getPkgName() {
+ return "reposerv";
+ }
+
+ public static void realMain(String args[]) throws Throwable {
+ new RepositoryServiceTest().run(args);
+ }
+
+ /**
+ * Creates modules in two repositories. Launches java, providing a JAM in
+ * one of the repositories, which invokes ServiceLoader. Verifies that
+ * service providers can be loaded from the application repository as well
+ * as one specified by the service. In src/reposerv, see
+ * service/FooService.java and client/Main.java.
+ */
+ void run(String args[]) throws Throwable {
+ File classesDir = new File(scratchDir, "classes");
+ compileSources(srcDir, classesDir);
+
+ File serviceJam_10 = createJam(
+ pkgName, "service", scratchDir, "service-1.0.jam");
+ File providerJam_10 = createJam(
+ pkgName, "provider", scratchDir, "provider-1.0.jam");
+ File clientJam = createJam(pkgName, "client", scratchDir);
+
+ JamUtils.recursiveDelete(new File(classesDir, "reposerv/provider"));
+ Map<String, String> annotations = new HashMap<String, String>();
+
+ annotations.put("@Version(", "@Version(\"1.5\")");
+ redefineAnnotations(annotations, "provider");
+ compileSources(scratchDir, classesDir);
+ File providerJam_15 = createJam(
+ pkgName, "provider", scratchDir, "provider-1.5.jam");
+
+ // Create test repositories
+ File repoDir_1 = new File(scratchDir, "repo1");
+ repoDir_1.mkdirs();
+ Repository repo_1 = Modules.newLocalRepository("DefaultTest", repoDir_1);
+ File repoDir_2 = new File(scratchDir, "repo2");
+ repoDir_2.mkdirs();
+ Repository repo_2 = Modules.newLocalRepository("DefaultTest", repoDir_2);
+
+ repo_1.install(serviceJam_10.toURI().toURL());
+ repo_1.install(providerJam_10.toURI().toURL());
+ ModuleArchiveInfo client = repo_1.install(clientJam.toURI().toURL());
+
+ repo_2.install(providerJam_15.toURI().toURL());
+
+ // Check JAM files in repository
+ check(repo_1.findAll().size() > 0);
+ check(repo_1.list().size() > 0);
+ check(repo_2.findAll().size() > 0);
+ check(repo_2.list().size() > 0);
+
+ dump(repo_1);
+ dump(repo_2);
+
+ String jamName = JamUtils.getJamFilename(
+ client.getName(), client.getVersion(), null, null) + ".jam";
+ runJavaCmd("client",
+ "-DrepoPath=" + repoDir_2, // See src/reposerv/service/FooService.java
+ "-jam",
+ new File(repoDir_1, jamName).getCanonicalPath());
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/ServiceTest.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.module.*;
+import java.util.*;
+import javax.tools.*;
+import sun.module.JamUtils;
+import sun.module.tools.*;
+
+/**
+ * Base class for service loader tests.
+ */
+abstract public class ServiceTest {
+ static final boolean DEBUG = System.getProperty("service.debug") != null;
+
+ static String javaCmd;
+
+ final String scratchDirName;
+
+ final String pkgName;
+
+ final File scratchDir;
+
+ final File srcDir;
+
+ final File repoDir;
+
+ final Repository repo;
+
+ ServiceTest() {
+ scratchDirName = getScratchDirName();
+ pkgName = getPkgName();
+ File scratch = null;
+ File srcD = null;
+ File rD = null;
+ try {
+ scratch = new File(
+ System.getProperty("test.scratch", "."), scratchDirName).getCanonicalFile();
+ srcD = new File(
+ System.getProperty("test.src", "."), "src/" + pkgName ).getCanonicalFile();
+ rD = new File(scratch, "repo");
+ } catch (Exception ex) {
+ // Should't happen, but if it does, much worse would happen later on
+ throw new RuntimeException(ex);
+ }
+ scratchDir = scratch;
+ srcDir = srcD;
+ repoDir = rD;
+
+ Repository r = null;
+ try {
+ check(JamUtils.recursiveDelete(scratchDir));
+ check(repoDir.mkdirs());
+ r = Modules.newLocalRepository(scratchDirName, repoDir);
+ } catch (IOException ex) {
+ fail(ex.getMessage());
+ }
+ repo = r;
+ }
+
+ abstract String getScratchDirName();
+
+ abstract String getPkgName();
+
+ File getScratchDir() {
+ return scratchDir;
+ }
+
+ File getSrcDir() {
+ return srcDir;
+ }
+
+ /** Compiles all files under srcDir to destDir. */
+ void compileSources(File srcDir, File destDir) throws Throwable {
+ List<File> srcs = new ArrayList<File>();
+ for (File dir : srcDir.listFiles(
+ new FileFilter() {
+ public boolean accept(File pathname) {
+ return pathname.isDirectory();
+ }
+ })) {
+ File[] srcFiles = dir.listFiles(
+ new FileFilter() {
+ public boolean accept(File pathname) {
+ return pathname.getName().endsWith(".java");
+ }});
+ srcs.addAll(Arrays.asList(srcFiles));
+ }
+
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ String cmdPrefix = "-source 6 -target 6 -implicit:class"
+ + " -processor sun.module.core.ServiceProcessor";
+ destDir.mkdirs();
+ String cmd = cmdPrefix + " -d " + destDir + " -cp " + destDir;
+ for (File f : srcs) {
+ cmd += " " + f.getCanonicalPath();
+ }
+ debug("compiling: " + cmd);
+ int rc = compiler.run(null, null, null, cmd.split(" "));
+ if (rc != 0) {
+ throw new Exception("Failed to compile");
+ }
+ }
+
+ /**
+ * Takes a set of source files and changes the @Version of the module
+ * which results from compiling and JAMming them. Resulting changed
+ * sources are placed under the scratch directory.
+ *
+ * @param srcDir directory containing all sources
+ * @param annotations Map from annotation prefixes to the new annotations
+ * @param dirname name of directory containing sources under srcDir
+ */
+ void redefineAnnotations(Map<String, String> annotations, String dirname) throws Throwable {
+ File dir = new File(srcDir, dirname);
+ File srcDestDir = new File(scratchDir, "src" + dirname);
+ for (File src : dir.listFiles(
+ new FileFilter() {
+ public boolean accept(File pathname) {
+ return pathname.getName().endsWith(".java");
+ }})) {
+ File dest = new File(srcDestDir, src.getName());
+ BufferedReader r = new BufferedReader(new FileReader(src));
+ dest.getParentFile().mkdirs();
+ PrintWriter w = new PrintWriter(new FileWriter(dest));
+ String s = null;
+ while ((s = r.readLine()) != null) {
+ s = s.trim();
+ boolean found = false;
+ for (String key : annotations.keySet()) {
+ if (s.startsWith(key)) {
+ w.println(annotations.get(key));
+ found = true;
+ }
+ }
+ if (!found) {
+ w.println(s);
+ }
+ }
+ w.close();
+ r.close();
+ }
+ }
+
+ /**
+ * Creates a JAM file
+ * @param pkgName name of package that locates super_package file
+ * @param srcDir name of directory that locates classes
+ * @param destDir directory where the JAM should be written
+ * @return a {@code File} representing the JAM file
+ */
+ File createJam(String pkgName, String srcDir, File destDir) throws Exception {
+ File rc = new File(destDir, srcDir + ".jam");
+ String classesDir = destDir + "/classes";
+ String cmd = "cfsS ";
+ cmd += rc.getCanonicalPath() + " ";
+ cmd += pkgName + "." + srcDir + " ";
+ cmd += classesDir + " ";
+ if (new File(classesDir, "META-INF").exists()) {
+ cmd += "-C " + classesDir + " META-INF ";
+ }
+ cmd += "-C ";
+ cmd += classesDir + " ";
+ cmd +=pkgName + "/" + srcDir;
+
+ debug("jam: " + cmd);
+ Jam jamTool = new Jam(System.out, System.err, "jam");
+ if (!jamTool.run(cmd.split(" "))) {
+ throw new Exception("jam failed for " + srcDir);
+ }
+ return rc;
+ }
+
+ /**
+ * @see #createJAM(String, String, File)
+ * @param destName name of resulting JAM file
+ */
+ File createJam(String pkgName, String srcDir, File destDir,
+ String destName) throws Exception {
+ File f = createJam(pkgName, srcDir, destDir);
+ File rc = new File(f.getParentFile(), destName);
+ if (!f.renameTo(rc)) {
+ throw new Exception("createJam: Couldn't rename " + f + " to " + rc);
+ } else {
+ return rc;
+ }
+ }
+
+ /**
+ * @return the path to the java command
+ */
+ static String getJava() {
+ if (javaCmd == null) {
+ javaCmd = System.getProperty("java.home")
+ + File.separator + "bin" + File.separator + "java";
+ if (!new File(javaCmd).exists()) {
+ javaCmd = javaCmd + ".exe";
+ }
+ }
+ return javaCmd;
+ }
+
+ /**
+ * @return the path to the java command followed by the given args
+ */
+ static List<String> getJavaCmd(String ... args) {
+ List<String> rc = new ArrayList<String>();
+ rc.add(getJava());
+ for (String a : args) {
+ rc.add(a);
+ }
+ if (DEBUG) {
+ rc.add("-Dservice.debug=true");
+ }
+ return rc;
+ }
+
+ /**
+ * Runs java on the given args
+ * @param name name of the jam; for debugging info
+ * @param args arguments to the java command
+ */
+ void runJavaCmd(String name, String ... args) throws Throwable {
+ runJavaCmd(name, true, args);
+ }
+
+ void runJavaCmd(String name, boolean deleteIfOK, String ... args) throws Throwable {
+ List<String> javaCmd = getJavaCmd(args);
+ ProcessBuilder pb = new ProcessBuilder(javaCmd);
+ try {
+ pb.redirectErrorStream(true);
+ pb.directory(new File(System.getProperty("test.scratch", ".")));
+ debug("Running " + Arrays.toString(javaCmd.toArray(new String[0])));
+ Process p = pb.start();
+ p.waitFor();
+ debug(name + " returned " + p.exitValue());
+ check(p.exitValue() == 0);
+ BufferedReader br = new BufferedReader(
+ new InputStreamReader(
+ p.getInputStream()), 8192);
+ String msg = "";
+ String s = null;
+ while ((s = br.readLine()) != null) {
+ msg += ">>> " + s + "\n";
+ }
+ debug(msg);
+ } catch (Exception ex) {
+ unexpected(ex);
+ }
+
+ // When not debugging and there are no failures, remove test dirs
+ if (deleteIfOK && !DEBUG && failed == 0) {
+ JamUtils.recursiveDelete(scratchDir);
+ }
+ }
+
+ /*
+ * Debugging
+ */
+
+ void debug(String s) {
+ if (DEBUG) System.err.println("### " + s);
+ }
+
+ void dump(Repository repo) throws IOException {
+ debug("findAll: " + repo.findAll().size() + ", list: " + repo.list().size());
+ for (ModuleArchiveInfo mai : repo.list()) {
+ debug("repo.list: " + mai);
+ }
+ for (ModuleDefinition md : repo.findAll()) {
+ debug("repo.findAll: " + md);
+ }
+ if (DEBUG) {
+ JRepo jrepo = new JRepo(System.out, System.err, null);
+ jrepo.run(new String[] {"list", "-v", "-r", repoDir.getCanonicalPath()});
+ }
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ static volatile int passed = 0, failed = 0;
+ static boolean pass() {passed++; return true;}
+ static boolean fail() {failed++; Thread.dumpStack(); return false;}
+ static boolean fail(String msg) {System.out.println(msg); return fail();}
+ static void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
+ static boolean equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) return pass();
+ else return fail(x + " not equal to " + y);}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/VersionServiceTest.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.module.ModuleArchiveInfo;
+import java.module.ModuleDefinition;
+import java.module.Modules;
+import java.module.Repository;
+import java.util.*;
+import javax.tools.*;
+import sun.module.JamUtils;
+import sun.module.tools.JRepo;
+
+/**
+ * @test VersionServiceTest.java
+ * @summary Test that expected versions of service provider modules are
+ * obtained.
+ * @compile -XDignore.symbol.file ServiceTest.java VersionServiceTest.java
+ * @run main VersionServiceTest
+ */
+public class VersionServiceTest extends ServiceTest {
+ String getScratchDirName() {
+ return "VerServTest";
+ }
+
+ String getPkgName() {
+ return "verserv";
+ }
+
+ public static void realMain(String args[]) throws Throwable {
+ new VersionServiceTest().run(args);
+ }
+
+ /**
+ * Creates multiple versions of a service and provider. The service has a
+ * default (i.e., the service module is also a service provider module).
+ * In concert with the Main class, this verifies that a service provider
+ * is used by the requestor of a service iff the service provider imports
+ * the same version of the service as that used by the requestor.
+ */
+ void run(String args[]) throws Throwable {
+ File classesDir = new File(scratchDir, "classes");
+ compileSources(srcDir, classesDir);
+
+ File serviceJam_10 = createJam(
+ pkgName, "service", scratchDir, "service-1.0.jam");
+ File providerJam_10 = createJam(
+ pkgName, "provider", scratchDir, "provider-1.0.jam");
+ File clientJam = createJam(pkgName, "client", scratchDir);
+
+ JamUtils.recursiveDelete(new File(classesDir, "verserv/provider"));
+ Map<String, String> annotations = new HashMap<String, String>();
+
+ annotations.put("@Version(", "@Version(\"1.5\")");
+ redefineAnnotations(annotations, "provider");
+ compileSources(scratchDir, classesDir);
+ File providerJam_15 = createJam(
+ pkgName, "provider", scratchDir, "provider-1.5.jam");
+
+ annotations.put("@Version(", "@Version(\"3.3\")");
+ redefineAnnotations(annotations, "service");
+ compileSources(scratchDir, classesDir);
+ File serviceJam_33 = createJam(
+ pkgName, "service", scratchDir, "service-3.3.jam");
+
+ annotations.put("@Version(", "@Version(\"3.3\")\n");
+ annotations.put("@ImportModules(",
+ "@ImportModules({\n"
+ + " @ImportModule(name=\"verserv.service\", version=\"[3.0, 4.0)\")\n"
+ + "})");
+ redefineAnnotations(annotations, "provider");
+ compileSources(scratchDir, classesDir);
+ File providerJam_33 = createJam(
+ pkgName, "provider", scratchDir, "provider-3.3.jam");
+
+ repo.install(serviceJam_10.toURI().toURL());
+ repo.install(serviceJam_33.toURI().toURL());
+ repo.install(providerJam_10.toURI().toURL());
+ repo.install(providerJam_15.toURI().toURL());
+ repo.install(providerJam_33.toURI().toURL());
+ ModuleArchiveInfo client = repo.install(clientJam.toURI().toURL());
+
+ // Check JAM files in repository
+ check(repo.findAll().size() > 0);
+ check(repo.list().size() > 0);
+
+ dump(repo);
+
+ String jamName = JamUtils.getJamFilename(
+ client.getName(), client.getVersion(), null, null) + ".jam";
+ runJavaCmd("client.jam",
+ "-jam",
+ new File(repoDir, jamName).getCanonicalPath());
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/charserv/client/Main.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package charserv.client;
+
+import java.nio.charset.spi.CharsetProvider;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+import java.module.ModuleDefinition;
+import java.module.Version;
+import java.util.NoSuchElementException;
+
+/**
+ * Checks that the test's provider for java.nio.charset.spi.CharsetProvider,
+ * which is defined in java.se.core, is available.
+ */
+public class Main {
+ public static void realMain(String[] args) throws Throwable {
+ Iterator<CharsetProvider> loader =
+ ServiceLoader.load(CharsetProvider.class).iterator();
+
+ CharsetProvider cp = loader.next();
+
+ // Check by name rather than by java.lang.class to ensure that we
+ // don't load the class by other than the ServiceLoader
+ check(cp.getClass().getName().equals("charserv.provider.CharsetServiceProvider"));
+
+ // Check that we can get a provider from the classpath
+ boolean found = false;
+ while (!found && loader.hasNext()) {
+ cp = loader.next();
+ if (cp.getClass().getName().equals("charserv.other.CharsetServiceProviderOnClasspath")) {
+ found = true;
+ break;
+ }
+ }
+ check(found);
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ static volatile int passed = 0, failed = 0;
+ static boolean pass() {passed++; return true;}
+ static boolean fail() {failed++; Thread.dumpStack(); return false;}
+ static boolean fail(String msg) {System.out.println(msg); return fail();}
+ static void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
+ static boolean equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) return pass();
+ else return fail(x + " not equal to " + y);}
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/charserv/client/module_info.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABbILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package charserv.client;
+
+import java.lang.ModuleInfo.*;
+import java.module.annotation.*;
+
+@ImportModules({
+ @ImportModule(name="java.se.core"),
+ @ImportModule(name="java.classpath")
+})
+@MainClass("charserv.client.Main")
+class module_info {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/charserv/other/CharsetServiceProviderOnClasspath.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package charserv.other;
+
+import java.nio.charset.Charset;
+import java.util.Iterator;
+import java.util.ServiceProvider;
+import java.nio.charset.spi.CharsetProvider;
+
+/**
+ * An implementation of CharsetProvider to should be accessed via classpath.
+ */
+@ServiceProvider
+public class CharsetServiceProviderOnClasspath extends CharsetProvider {
+
+ public CharsetServiceProviderOnClasspath() {
+ }
+
+ public Charset charsetForName(String charsetName) { return null; }
+
+ public Iterator<Charset> charsets() { return null; }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/charserv/provider/CharsetServiceProvider.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package charserv.provider;
+
+import java.nio.charset.Charset;
+import java.util.Iterator;
+import java.util.ServiceProvider;
+import java.nio.charset.spi.CharsetProvider;
+
+/**
+ * A non-default implementation of CharsetProvider
+ */
+@ServiceProvider
+public class CharsetServiceProvider extends CharsetProvider {
+
+ public CharsetServiceProvider() {
+ }
+
+ public Charset charsetForName(String charsetName) { return null; }
+
+ public Iterator<Charset> charsets() { return null; }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/charserv/provider/module_info.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package charserv.provider;
+
+import java.module.annotation.*;
+import java.lang.ModuleInfo.*;
+
+@ServiceProviders({
+ @ServiceProvider(service="java.nio.charset.spi.CharsetProvider",
+ providerClass="charserv.provider.CharsetServiceProvider")
+})
+@ImportModules({
+ @ImportModule(name="java.se.core")
+})
+class module_info {
+ // Export service provider type
+ exports charserv$provider$CharsetServiceProvider;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cliserv/client/Main.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package cliserv.client;
+
+import java.util.Iterator;
+import java.util.ServiceLoader;
+import java.module.ModuleDefinition;
+import java.module.Version;
+import java.util.NoSuchElementException;
+import cliserv.service.FooService;
+
+/**
+ * Checks that providers for service Foo are available. This class is in the
+ * client module, and so the providers must be returned in the expected order
+ * (i.e. default provider first).
+ */
+public class Main {
+ public static void realMain(String[] args) throws Throwable {
+ Iterator<FooService> loader =
+ ServiceLoader.load(FooService.class).iterator();
+
+ FooService fs = loader.next();
+
+ // Check by name rather than by java.lang.class to ensure that we
+ // don't load the class by other than the ServiceLoader
+ check(fs.getClass().getName().equals("cliserv.service.FooServiceDefaultProvider"));
+
+ try {
+ // Check that the next service is the non-default provider
+ fs = loader.next();
+ check(fs.getClass().getName().equals("cliserv.provider.FooService2Provider"));
+ try {
+ // Check that the provider of another service is *not*
+ // returned.
+ loader.next();
+ fail();
+ } catch (NoSuchElementException ex) {
+ pass();
+ }
+ } catch (NoSuchElementException ex) {
+ fail();
+ }
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ static volatile int passed = 0, failed = 0;
+ static boolean pass() {passed++; return true;}
+ static boolean fail() {failed++; Thread.dumpStack(); return false;}
+ static boolean fail(String msg) {System.out.println(msg); return fail();}
+ static void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
+ static boolean equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) return pass();
+ else return fail(x + " not equal to " + y);}
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cliserv/client/MainCP.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package cliserv.client;
+
+import java.util.Iterator;
+import java.util.ServiceLoader;
+import java.module.ModuleDefinition;
+import java.module.Version;
+import java.util.NoSuchElementException;
+import cliserv.service.FooService;
+
+/**
+ * Checks that providers for service Foo are available. This class is not
+ * part of a module when run, so the providers might be returned in any order.
+ */
+public class MainCP {
+ static final String[] providerNames = new String[] {
+ "cliserv.service.FooServiceDefaultProvider",
+ "cliserv.provider.FooService2Provider"
+ };
+
+ public static void realMain(String[] args) throws Throwable {
+ Iterator<FooService> loader =
+ ServiceLoader.load(FooService.class).iterator();
+
+ FooService fs = loader.next();
+
+ // Check by name rather than by java.lang.class to ensure that we
+ // don't load the class by other than the ServiceLoader
+ verify(fs.getClass().getName());
+
+ try {
+ // Check that the next service is the non-default provider
+ fs = loader.next();
+ verify(fs.getClass().getName());
+
+ try {
+ // Check that the provider of another service is *not*
+ // returned.
+ loader.next();
+ fail();
+ } catch (NoSuchElementException ex) {
+ pass();
+ }
+ } catch (NoSuchElementException ex) {
+ fail();
+ }
+ }
+
+ static void verify(String name) {
+ for (int i = 0; i < providerNames.length; i++) {
+ if (name.equals(providerNames[i])) {
+ pass();
+ return;
+ }
+ }
+ fail("Couldn't find provider for " + name);
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ static volatile int passed = 0, failed = 0;
+ static boolean pass() {passed++; return true;}
+ static boolean fail() {failed++; Thread.dumpStack(); return false;}
+ static boolean fail(String msg) {System.out.println(msg); return fail();}
+ static void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
+ static boolean equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) return pass();
+ else return fail(x + " not equal to " + y);}
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cliserv/client/module_info.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABbILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package cliserv.client;
+
+import java.lang.ModuleInfo.*;
+import java.module.annotation.*;
+
+
+@ImportModules({
+ @ImportModule(name="java.se.core"),
+ @ImportModule(name="cliserv.service")
+})
+@MainClass("cliserv.client.Main")
+class module_info {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cliserv/provider/BarService.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package cliserv.provider;
+
+import java.util.Iterator;
+import java.util.Service;
+import java.util.ServiceLoader;
+
+/**
+ * A service for which we provide a default provider
+ */
+@Service
+abstract public class BarService {
+ private static Iterator<BarService> loader =
+ ServiceLoader.load(BarService.class).iterator();
+
+ public static BarService getNextProvider() {
+ return loader.next();
+ }
+
+ public BarService() {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cliserv/provider/BarServiceProvider.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package cliserv.provider;
+
+import java.util.ServiceProvider;
+
+/**
+ * An implementation of BarService
+ */
+@ServiceProvider
+public class BarServiceProvider extends BarService {
+
+ public BarServiceProvider() {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cliserv/provider/FooService2Provider.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package cliserv.provider;
+
+import java.util.ServiceProvider;
+import cliserv.service.FooService;
+
+/**
+ * A non-default implementation of FooService
+ */
+@ServiceProvider
+public class FooService2Provider extends FooService {
+
+ public FooService2Provider() {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cliserv/provider/module_info.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package cliserv.provider;
+
+import java.module.annotation.*;
+import java.lang.ModuleInfo.*;
+
+@ServiceProviders({
+ @ServiceProvider(service="cliserv.service.FooService",
+ providerClass="cliserv.provider.FooService2Provider"),
+ @ServiceProvider(service="cliserv.service.BarService",
+ providerClass="cliserv.provider.BarServiceProvider")
+})
+@Services("BarProvider")
+@ImportModules({
+ @ImportModule(name="java.se.core"),
+ @ImportModule(name="cliserv.service") // Import service module defining Foo
+})
+class module_info {
+ // Export service provider type
+ exports cliserv$provider$FooService2Provider;
+
+ // Export service provider type
+ exports cliserv$provider$BarServiceProvider;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cliserv/service/FooService.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package cliserv.service;
+
+import java.util.Service;
+
+/**
+ * A service for which we provide a default provider
+ */
+@Service
+abstract public class FooService {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cliserv/service/FooServiceDefaultProvider.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package cliserv.service;
+
+import java.util.ServiceProvider;
+
+/**
+ * The default implementation of FooService
+ */
+@ServiceProvider
+public class FooServiceDefaultProvider extends FooService {
+
+ public FooServiceDefaultProvider() {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cliserv/service/module_info.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package cliserv.service;
+
+import java.module.annotation.*;
+import java.lang.ModuleInfo.*;
+
+@Services({"cliserv.service.FooService"})
+@ServiceProviders({
+ @ServiceProvider(service="cliserv.service.FooService",
+ providerClass="cliserv.service.FooServiceDefaultProvider")
+})
+@ImportModules({
+ @ImportModule(name="java.se.core")
+})
+class module_info {
+ // Export service type
+ exports cliserv$service$FooService;
+
+ // Note that the default service provider is *not* exported.
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cpserv/client/Main.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package cpserv.client;
+
+import java.module.ModuleDefinition;
+import java.module.Version;
+import java.util.NoSuchElementException;
+import cpserv.service.FooService;
+
+public class Main {
+ public static void realMain(String[] args) throws Throwable {
+ FooService fs = null;
+
+ // Check by name rather than by java.lang.class to ensure that we
+ // don't load the class by other than the ServiceLoader
+
+ // Verify both default providers are returned.
+ fs = FooService.getNextProvider();
+ check(fs.getClass().getName().equals("cpserv.service.FooServiceDefaultProvider"));
+
+ System.err.println("testing service");
+ fs.test();
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ static volatile int passed = 0, failed = 0;
+ static boolean pass() {passed++; return true;}
+ static boolean fail() {failed++; Thread.dumpStack(); return false;}
+ static boolean fail(String msg) {System.out.println(msg); return fail();}
+ static void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
+ static boolean equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) return pass();
+ else return fail(x + " not equal to " + y);}
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cpserv/client/module_info.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABbILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package cpserv.client;
+
+import java.lang.ModuleInfo.*;
+import java.module.annotation.*;
+
+@ImportModules({
+ @ImportModule(name="java.se.core"),
+ @ImportModule(name="java.classpath"),
+ @ImportModule(name="cpserv.service")
+})
+@MainClass("cpserv.client.Main")
+class module_info {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cpserv/other/Mumble.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,5 @@
+package cpserv.other;
+
+public class Mumble {
+ public String toString() { return "hello, mumble"; }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cpserv/service/FooService.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package cpserv.service;
+
+import java.util.Iterator;
+import java.util.Service;
+import java.util.ServiceLoader;
+
+/**
+ * A service for which we provide a default provider
+ */
+@Service
+abstract public class FooService {
+ private static Iterator<FooService> loader =
+ ServiceLoader.load(FooService.class).iterator();
+
+ public static FooService getNextProvider() {
+ return loader.next();
+ }
+
+ public FooService() {
+ }
+
+ abstract public void test() throws Throwable;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cpserv/service/FooServiceDefaultProvider.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package cpserv.service;
+
+import java.util.ServiceProvider;
+
+/**
+ * The default implementation of FooService
+ */
+@ServiceProvider
+public class FooServiceDefaultProvider extends FooService {
+
+ public FooServiceDefaultProvider() {
+ }
+
+ public void test() throws Throwable {
+ Class c = Class.forName("cpserv.other.Mumble");
+ Object o = c.newInstance();
+ System.out.println("Mumble: " + o.toString());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/cpserv/service/module_info.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package cpserv.service;
+
+import java.module.annotation.*;
+import java.lang.ModuleInfo.*;
+
+@Services({"cpserv.service.FooService"})
+@ServiceProviders({
+ @ServiceProvider(service="cpserv.service.FooService",
+ providerClass="cpserv.service.FooServiceDefaultProvider")
+})
+@ImportModules({
+ @ImportModule(name="java.se.core")
+})
+class module_info {
+ // Export service type
+ exports cpserv$service$FooService;
+
+ // Note that the default service providers are *not* exported.
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/defserv/client/Main.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package defserv.client;
+
+import java.module.ModuleDefinition;
+import java.module.Version;
+import java.util.NoSuchElementException;
+import defserv.service.FooService;
+
+public class Main {
+ public static void realMain(String[] args) throws Throwable {
+ FooService fs = null;
+
+ // Check by name rather than by java.lang.class to ensure that we
+ // don't load the class by other than the ServiceLoader
+
+ // Verify both default providers are returned.
+ fs = FooService.getNextProvider();
+ check(fs.getClass().getName().equals("defserv.service.FooServiceDefaultProvider"));
+ fs = FooService.getNextProvider();
+ check(fs.getClass().getName().equals("defserv.service.FooServiceDefaultProvider2"));
+
+ try {
+ // Check that the next service is the non-default provider
+ fs = FooService.getNextProvider();
+ check(fs.getClass().getName().equals("defserv.provider.FooService2Provider"));
+ try {
+ // Check that the default provider of another service is *not*
+ // returned.
+ fs = FooService.getNextProvider();
+ fail();
+ } catch (NoSuchElementException ex) {
+ pass();
+ }
+ } catch (NoSuchElementException ex) {
+ fail();
+ }
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ static volatile int passed = 0, failed = 0;
+ static boolean pass() {passed++; return true;}
+ static boolean fail() {failed++; Thread.dumpStack(); return false;}
+ static boolean fail(String msg) {System.out.println(msg); return fail();}
+ static void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
+ static boolean equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) return pass();
+ else return fail(x + " not equal to " + y);}
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/defserv/client/module_info.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABbILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package defserv.client;
+
+import java.lang.ModuleInfo.*;
+import java.module.annotation.*;
+
+@ImportModules({
+ @ImportModule(name="java.se.core"),
+ @ImportModule(name="defserv.service")
+})
+@MainClass("defserv.client.Main")
+class module_info {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/defserv/provider/BarService.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package defserv.provider;
+
+import java.util.Iterator;
+import java.util.Service;
+import java.util.ServiceLoader;
+
+/**
+ * A service for which we provide a default provider
+ */
+@Service
+abstract public class BarService {
+ private static Iterator<BarService> loader =
+ ServiceLoader.load(BarService.class).iterator();
+
+ public static BarService getNextProvider() {
+ return loader.next();
+ }
+
+ public BarService() {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/defserv/provider/BarServiceDefaultProvider.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package defserv.provider;
+
+import java.util.ServiceProvider;
+
+/**
+ * The default implementation of BarService
+ */
+@ServiceProvider
+public class BarServiceDefaultProvider extends BarService {
+
+ public BarServiceDefaultProvider() {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/defserv/provider/FooService2Provider.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package defserv.provider;
+
+import java.util.ServiceProvider;
+import defserv.service.FooService;
+
+/**
+ * A non-default implementation of FooService
+ */
+@ServiceProvider
+public class FooService2Provider extends FooService {
+
+ public FooService2Provider() {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/defserv/provider/module_info.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package defserv.provider;
+
+import java.module.annotation.*;
+import java.lang.ModuleInfo.*;
+
+@ServiceProviders({
+ @ServiceProvider(service="defserv.service.FooService",
+ providerClass="defserv.provider.FooService2Provider"),
+ @ServiceProvider(service="defserv.service.BarService",
+ providerClass="defserv.provider.BarServiceDefaultProvider")
+})
+@Services("BarProvider")
+@ImportModules({
+ @ImportModule(name="java.se.core"),
+ @ImportModule(name="defserv.service") // Import service module defining Foo
+})
+class module_info {
+ // Export service type
+ exports defserv$provider$BarService;
+
+ // Export service provider type
+ exports defserv$provider$FooService2Provider;
+
+ // Note that the default service provider is *not* exported.
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/defserv/service/FooService.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package defserv.service;
+
+import java.util.Iterator;
+import java.util.Service;
+import java.util.ServiceLoader;
+
+/**
+ * A service for which we provide a default provider
+ */
+@Service
+abstract public class FooService {
+ private static Iterator<FooService> loader =
+ ServiceLoader.load(FooService.class).iterator();
+
+ public static FooService getNextProvider() {
+ return loader.next();
+ }
+
+ public FooService() {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/defserv/service/FooServiceDefaultProvider.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package defserv.service;
+
+import java.util.ServiceProvider;
+
+/**
+ * The default implementation of FooService
+ */
+@ServiceProvider
+public class FooServiceDefaultProvider extends FooService {
+
+ public FooServiceDefaultProvider() {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/defserv/service/FooServiceDefaultProvider2.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package defserv.service;
+
+import java.util.ServiceProvider;
+
+/**
+ * The default implementation of FooService
+ */
+@ServiceProvider
+public class FooServiceDefaultProvider2 extends FooService {
+
+ public FooServiceDefaultProvider2() {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/defserv/service/module_info.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package defserv.service;
+
+import java.module.annotation.*;
+import java.lang.ModuleInfo.*;
+
+@Services({"defserv.service.FooService"})
+@ServiceProviders({
+ @ServiceProvider(service="defserv.service.FooService",
+ providerClass="defserv.service.FooServiceDefaultProvider"),
+ @ServiceProvider(service="defserv.service.FooService",
+ providerClass="defserv.service.FooServiceDefaultProvider2")
+})
+@ImportModules({
+ @ImportModule(name="java.se.core")
+})
+class module_info {
+ // Export service type
+ exports defserv$service$FooService;
+
+ // Note that the default service providers are *not* exported.
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/modserv/client/Main.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package modserv.client;
+
+import modserv.service.CodecSet;
+import modserv.service.Encoder;
+
+public class Main {
+ static final boolean DEBUG = System.getProperty("service.debug") != null;
+
+ public static void realMain(String[] args) throws Throwable {
+ Encoder e = CodecSet.getEncoder("foo");
+ boolean rc = check(e.getClass().getName().equals("modserv.provider1.StandardCodecs$FooEncoder"));
+ debug("e.getClass().getName()=" + e.getClass().getName());
+ debug("e cl=" + e.getClass().getClassLoader());
+ debug("e cl=" + e.getClass().getClassLoader().hashCode());
+
+ // Another class from the same module is accessible
+ Class<?> c = Class.forName("modserv.provider1.AdvancedCodecs", false, e.getClass().getClassLoader());
+ debug("c.getName()=" + c.getName());
+ debug("c cl= " + c.getClassLoader());
+ debug("c cl= " + c.getClassLoader().hashCode());
+
+ // Another class from a different module is NOT accessible
+ try {
+ c = Class.forName("modserv.provider2.AdvancedCodecs", false, e.getClass().getClassLoader());
+ fail(c.getName());
+ } catch (ClassNotFoundException ex) {
+ pass();
+ } catch (Throwable t) {
+ fail(t.getMessage());
+ }
+
+ Class<?> sc = c.getSuperclass();
+ debug("sc.getName()=" + sc.getName());
+ debug("sc cl= " + sc.getClassLoader());
+ debug("sc cl= " + sc.getClassLoader().hashCode());
+
+ if (!rc || args.length > 0) {
+ System.err.println("encoded result: " + e.encode("hello, world"));
+ }
+ }
+
+ static void debug(String s) {
+ if (DEBUG) System.err.println("*** " + s);
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ static volatile int passed = 0, failed = 0;
+ static boolean pass() {passed++; return true;}
+ static boolean fail() {failed++; Thread.dumpStack(); return false;}
+ static boolean fail(String msg) {System.out.println(msg); return fail();}
+ static void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
+ static boolean equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) return pass();
+ else return fail(x + " not equal to " + y);}
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/modserv/client/module_info.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package modserv.client;
+
+import java.lang.ModuleInfo.*;
+import java.module.annotation.*;
+
+@MainClass("modserv.client.Main")
+@ImportModules({
+ @ImportModule(name="java.se.core"),
+ @ImportModule(name="modserv.service", version="[2.0, 3.0)")
+})
+class module_info {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/modserv/provider1/AdvancedCodecs.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package modserv.provider1;
+
+import java.util.ServiceProvider;
+import modserv.service.CodecSet;
+import modserv.service.Encoder;
+
+/**
+ * Based on the example in {@link java.util.ServiceLoader}
+ */
+@ServiceProvider
+public class AdvancedCodecs extends CodecSet {
+ public AdvancedCodecs() {
+ }
+
+ public Encoder getEncoderFor(String name) {
+ Encoder rc = null;
+ if ("whiz".equals(name)) {
+ rc = new WhizzyEncoder();
+ }
+ return rc;
+ }
+
+ static class WhizzyEncoder extends Encoder {
+ public WhizzyEncoder() {
+ super("whiz");
+ }
+
+ public String encode(String s) {
+ return "whiz-provider1.AdvancedCodecs-1.3|" + s;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/modserv/provider1/StandardCodecs.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package modserv.provider1;
+
+import java.util.ServiceProvider;
+import modserv.service.CodecSet;
+import modserv.service.Encoder;
+
+/**
+ * Based on the example in {@link java.util.ServiceLoader}
+ */
+@ServiceProvider
+public class StandardCodecs extends CodecSet {
+
+ /** Creates a new instance of StandardCodecs */
+ public StandardCodecs() {
+ }
+
+ public Encoder getEncoderFor(String name) {
+ if ("foo".equals(name)) {
+ return new FooEncoder();
+ }
+ return null;
+ }
+
+ static class FooEncoder extends Encoder {
+ public FooEncoder() {
+ super("foo");
+ }
+
+ public String encode(String s) {
+ return "foo|" + s + "|foo";
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/module/service/src/modserv/provider1/module_info.java Mon Jul 07 10:13:08 2008 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package modserv.provider1;
+
+import java.lang.ModuleInfo.*;
+import java.module.annotation.*;
+
+@ServiceProviders({
+ @ServiceProvider(service="modserv.service.CodecSet",
+ providerClass="modserv.provider1.StandardCodecs"),
+ @ServiceProvider(service="modserv.service.CodecSet",
+ providerClass="modserv.provider1.AdvancedCodecs")
+})
+@Version("1.3")
+@ImportModules({
+ @ImportModule(name="java.se.core"),
+ @ImportModule(name="modserv.service", version="[2.