Skip to content
Commits on Source (2)
File added
......@@ -23,13 +23,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.jboss.modules</groupId>
<artifactId>jboss-modules</artifactId>
<version>1.9.0.Final</version>
<version>1.9.2.Final</version>
<name>JBoss Modules</name>
<parent>
<groupId>org.jboss</groupId>
<artifactId>jboss-parent</artifactId>
<version>24</version>
<version>32</version>
</parent>
<licenses>
......@@ -233,8 +233,13 @@
<artifactId>maven-javadoc-plugin</artifactId>
<version>${version.javadoc.plugin}</version>
<configuration>
<detectJavaApiLink>false</detectJavaApiLink>
<excludePackageNames>__redirected</excludePackageNames>
<excludePackageNames>org.jboss.modules._private</excludePackageNames>
<sourcepath>${project.basedir}/src/main/java9;${project.basedir}/src/main/java</sourcepath>
<sourceFileExcludes>
<exclude>org/jboss/modules/JDKSpecific.java</exclude>
</sourceFileExcludes>
</configuration>
</plugin>
......
......@@ -23,7 +23,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
......@@ -43,36 +42,6 @@ public final class JDKModuleFinder implements IterableModuleFinder {
private final ConcurrentHashMap<String, FutureSpec> modules = new ConcurrentHashMap<>();
private final List<String> moduleNames;
static final class SEDeps {
static final List<DependencySpec> javaSeDeps;
static {
List<DependencySpec> deps = new ArrayList<>();
for (String dep : Arrays.asList(
"java.compiler",
"java.datatransfer",
"java.desktop",
"java.instrument",
"java.logging",
"java.management",
"java.management.rmi",
"java.naming",
"java.prefs",
"java.rmi",
"java.scripting",
"java.security.jgss",
"java.security.sasl",
"java.sql",
"java.sql.rowset",
"java.xml",
"java.xml.crypto"
)) {
deps.add(new ModuleDependencySpecBuilder().setName(dep).setExport(true).build());
}
javaSeDeps = deps;
}
}
private static final JDKModuleFinder INSTANCE = new JDKModuleFinder();
private JDKModuleFinder() {
......@@ -148,8 +117,8 @@ public final class JDKModuleFinder implements IterableModuleFinder {
} else {
switch (name) {
case "java.se": {
final ModuleSpec.Builder builder = ModuleSpec.build("java.se", false);
for (DependencySpec dep : SEDeps.javaSeDeps) {
final ModuleSpec.Builder builder = ModuleSpec.build(name, false);
for (DependencySpec dep : JavaSeDeps.list) {
builder.addDependency(dep);
}
futureSpec.setModuleSpec(builder.create());
......
package org.jboss.modules;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
final class JavaSeDeps {
static final List<DependencySpec> list;
static {
List<DependencySpec> deps = new ArrayList<>();
for (String dep : Arrays.asList(
"java.compiler",
"java.datatransfer",
"java.desktop",
"java.instrument",
"java.logging",
"java.management",
"java.management.rmi",
"java.naming",
"java.prefs",
"java.rmi",
"java.scripting",
"java.security.jgss",
"java.security.sasl",
"java.sql",
"java.sql.rowset",
"java.xml",
"java.xml.crypto"
)) {
deps.add(new ModuleDependencySpecBuilder().setName(dep).setExport(true).build());
}
list = deps;
}
}
......@@ -25,9 +25,12 @@ import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.URL;
import java.security.CodeSource;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
......@@ -1149,6 +1152,30 @@ public class ModuleLoader {
return result;
}
public String getClassLocation(final String moduleName, final String className) {
final ModuleLoader loader = getModuleLoader();
final Module module = loadModule(moduleName, loader);
final Class<?> clazz;
try {
clazz = Class.forName(className, false, module.getClassLoaderPrivate());
} catch (ClassNotFoundException e) {
return null;
}
final ProtectionDomain pd = clazz.getProtectionDomain();
if (pd == null) {
return null;
}
final CodeSource cs = pd.getCodeSource();
if (cs == null) {
return null;
}
final URL url = cs.getLocation();
if (url == null) {
return null;
}
return url.toString();
}
private Module loadModule(final String name, final ModuleLoader loader) {
try {
final Module module = loader.findLoadedModuleLocal(name);
......
......@@ -21,6 +21,7 @@ package org.jboss.modules;
import java.lang.instrument.ClassFileTransformer;
import java.security.AllPermission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
......@@ -79,7 +80,7 @@ public abstract class ModuleSpec {
private LocalLoader fallbackLoader;
private ModuleClassLoaderFactory moduleClassLoaderFactory;
private ClassTransformer classFileTransformer;
private PermissionCollection permissionCollection;
private PermissionCollection permissionCollection = getAllPermission();
private Version version;
@Override
......@@ -184,6 +185,12 @@ public abstract class ModuleSpec {
public String getName() {
return name;
}
private Permissions getAllPermission() {
final Permissions permissions = new Permissions();
permissions.add(new AllPermission());
return permissions;
}
};
if (addBaseDep) builder.addDependency(ModuleDependencySpec.JAVA_BASE);
return builder;
......
......@@ -160,4 +160,13 @@ public interface ModuleLoaderMXBean {
* @return the paths map information
*/
SortedMap<String, List<String>> getModulePathsInfo(String name, boolean exports);
/**
* Get the code source location of a class within a module.
*
* @param moduleName the module name
* @param className the class name
* @return the location, or {@code null} if the class isn't found or the location cannot be determined
*/
String getClassLocation(String moduleName, String className);
}
......@@ -22,8 +22,8 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
......@@ -157,10 +157,21 @@ public final class MavenArtifactUtil {
if (dest.exists()){
return;
}
final URL url = new URL(src);
final URLConnection connection = MavenSettings.getSettings().openConnection(url);
URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection)MavenSettings.getSettings().openConnection(url);
boolean message = Boolean.getBoolean("maven.download.message");
int statusCode = connection.getResponseCode();
if (statusCode == HttpURLConnection.HTTP_NOT_FOUND) {
return;
}
if (statusCode == HttpURLConnection.HTTP_MOVED_TEMP
|| statusCode == HttpURLConnection.HTTP_MOVED_PERM) {
src = connection.getHeaderField("Location");
url = new URL(src);
connection = (HttpURLConnection) url.openConnection();
}
try (InputStream bis = connection.getInputStream()){
dest.getParentFile().mkdirs();
if (message) { System.out.println("Downloading " + artifact); }
......@@ -194,7 +205,7 @@ public final class MavenArtifactUtil {
/**
* A utility method to create a Maven artifact resource loader for the given artifact coordinates.
*
* @param name the resource root name to use (must not be {@code null})
* @param rootName the resource root name to use (must not be {@code null})
* @param coordinates the artifact coordinates to use (must not be {@code null})
* @param mavenResolver the Maven resolver to use (must not be {@code null})
* @return the resource loader
......
......@@ -27,8 +27,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.AllPermission;
import java.security.Permissions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
......@@ -623,16 +621,6 @@ public final class ModuleXmlParser {
}
}
private static final AllPermission ALL_PERMISSION = new AllPermission();
static final Permissions DEFAULT_PERMISSION_COLLECTION = getAllPermission();
private static Permissions getAllPermission() {
final Permissions permissions = new Permissions();
permissions.add(ALL_PERMISSION);
return permissions;
}
private static ModuleSpec.Builder parseModuleContents(final MavenResolver mavenResolver, final XmlPullParser reader, final ResourceRootFactory factory, final ModuleLoader moduleLoader, final String moduleName, final String rootPath) throws XmlPullParserException, IOException {
final int count = reader.getAttributeCount();
String name = null;
......@@ -693,7 +681,6 @@ public final class ModuleXmlParser {
for (DependencySpec dependency : dependencies) {
specBuilder.addDependency(dependency);
}
if (! gotPerms) specBuilder.setPermissionCollection(DEFAULT_PERMISSION_COLLECTION);
return specBuilder;
}
case START_TAG: {
......@@ -1059,6 +1046,9 @@ public final class ModuleXmlParser {
try {
coordinates = ArtifactCoordinates.fromString(name);
final File file = mavenResolver.resolveJarArtifact(coordinates);
if (file == null) {
throw new XmlPullParserException(String.format("Failed to resolve artifact '%s'", coordinates), reader, null);
}
resourceLoader = factory.createResourceLoader("", file.getPath(), name);
} catch (IOException | IllegalArgumentException e) {
throw new XmlPullParserException(String.format("Failed to add artifact '%s'", name), reader, e);
......
......@@ -87,7 +87,7 @@ import java.io.Reader;
* factory.setNamespaceAware(true);
* XmlPullParser xpp = factory.newPullParser();
*
* xpp.<a href="#setInput">setInput</a>( new StringReader ( "&lt;foo>Hello World!&lt;/foo>" ) );
* xpp.<a href="#setInput">setInput</a>( new StringReader ( "&lt;foo&gt;Hello World!&lt;/foo&gt;" ) );
* int eventType = xpp.getEventType();
* while (eventType != XmlPullParser.END_DOCUMENT) {
* if(eventType == XmlPullParser.START_DOCUMENT) {
......@@ -545,7 +545,7 @@ public interface XmlPullParser {
* XmlPullParser pp = ...
* int nsStart = pp.getNamespaceCount(pp.getDepth()-1);
* int nsEnd = pp.getNamespaceCount(pp.getDepth());
* for (int i = nsStart; i < nsEnd; i++) {
* for (int i = nsStart; i &lt; nsEnd; i++) {
* String prefix = pp.getNamespacePrefix(i);
* String ns = pp.getNamespaceUri(i);
* // ...
......@@ -592,7 +592,7 @@ public interface XmlPullParser {
* <p>This method is a convenience method for
*
* <pre>
* for (int i = getNamespaceCount(getDepth ())-1; i >= 0; i--) {
* for (int i = getNamespaceCount(getDepth ())-1; i &gt;= 0; i--) {
* if (getNamespacePrefix(i).equals( prefix )) {
* return getNamespaceUri(i);
* }
......@@ -627,7 +627,7 @@ public interface XmlPullParser {
*
* <pre>
* &lt;!-- outside --&gt; 0
* &lt;root> 1
* &lt;root&gt; 1
* sometext 1
* &lt;foobar&gt; 2
* &lt;/foobar&gt; 2
......@@ -913,9 +913,9 @@ public interface XmlPullParser {
* must be expanded or exception mus be thrown if entity reerence can not be exapnded).
* If element content is empty (content is "") then no TEXT event will be reported.
*
* <p><b>NOTE:</b> empty element (such as &lt;tag/>) will be reported
* <p><b>NOTE:</b> empty element (such as &lt;tag/&gt;) will be reported
* with two separate events: START_TAG, END_TAG - it must be so to preserve
* parsing equivalency of empty element to &lt;tag>&lt;/tag>.
* parsing equivalency of empty element to &lt;tag&gt;&lt;/tag&gt;.
* (see isEmptyElementTag ())
*
* @see #isEmptyElementTag
......@@ -950,9 +950,9 @@ public interface XmlPullParser {
* <dt>START_DOCUMENT<dd>null
* <dt>END_DOCUMENT<dd>null
* <dt>START_TAG<dd>null unless FEATURE_XML_ROUNDTRIP
* enabled and then returns XML tag, ex: &lt;tag attr='val'>
* enabled and then returns XML tag, ex: &lt;tag attr='val'&gt;
* <dt>END_TAG<dd>null unless FEATURE_XML_ROUNDTRIP
* id enabled and then returns XML tag, ex: &lt;/tag>
* id enabled and then returns XML tag, ex: &lt;/tag&gt;
* <dt>TEXT<dd>return element content.
* <br>Note: that element content may be delivered in multiple consecutive TEXT events.
* <dt>IGNORABLE_WHITESPACE<dd>return characters that are determined to be ignorable white
......@@ -961,15 +961,15 @@ public interface XmlPullParser {
* <br>Note: that element content may be delevered in multiple consecutive IGNORABLE_WHITESPACE events.
* <dt>CDSECT<dd>
* return text <em>inside</em> CDATA
* (ex. 'fo&lt;o' from &lt;!CDATA[fo&lt;o]]>)
* (ex. 'fo&lt;o' from &lt;!CDATA[fo&lt;o]]&gt;)
* <dt>PROCESSING_INSTRUCTION<dd>
* if FEATURE_XML_ROUNDTRIP is true
* return exact PI content ex: 'pi foo' from &lt;?pi foo?>
* return exact PI content ex: 'pi foo' from &lt;?pi foo?&gt;
* otherwise it may be exact PI content or concatenation of PI target,
* space and data so for example for
* &lt;?target data?> string &quot;target data&quot; may
* &lt;?target data?&gt; string &quot;target data&quot; may
* be returned if FEATURE_XML_ROUNDTRIP is false.
* <dt>COMMENT<dd>return comment content ex. 'foo bar' from &lt;!--foo bar-->
* <dt>COMMENT<dd>return comment content ex. 'foo bar' from &lt;!--foo bar--&gt;
* <dt>ENTITY_REF<dd>getText() MUST return entity replacement text if PROCESS_DOCDECL is false
* otherwise getText() MAY return null,
* additionally getTextCharacters() MUST return entity name
......@@ -987,10 +987,10 @@ public interface XmlPullParser {
* if FEATURE_XML_ROUNDTRIP is true or PROCESS_DOCDECL is false
* then return what is inside of DOCDECL for example it returns:<pre>
* &quot; titlepage SYSTEM "http://www.foo.bar/dtds/typo.dtd"
* [&lt;!ENTITY % active.links "INCLUDE">]&quot;</pre>
* [&lt;!ENTITY % active.links "INCLUDE"&gt;]&quot;</pre>
* <p>for input document that contained:<pre>
* &lt;!DOCTYPE titlepage SYSTEM "http://www.foo.bar/dtds/typo.dtd"
* [&lt;!ENTITY % active.links "INCLUDE">]></pre>
* [&lt;!ENTITY % active.links "INCLUDE"&gt;]&gt;</pre>
* otherwise if FEATURE_XML_ROUNDTRIP is false and PROCESS_DOCDECL is true
* then what is returned is undefined (it may be even null)
* </dd>
......
......@@ -50,6 +50,15 @@ public final class JDKModuleFinder implements IterableModuleFinder {
}
public ModuleSpec findModule(final String name, final ModuleLoader delegateLoader) {
if ("java.se".equals(name)) {
// provide our own "java.se" aggregator module, as the one in JDK isn't accessible by default
final ModuleSpec.Builder builder = ModuleSpec.build(name, false);
for (DependencySpec dep : JavaSeDeps.list) {
builder.addDependency(dep);
}
return builder.create();
}
final Set<String> packages;
final Module module;
if ("org.jboss.modules".equals(name)) {
......
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
*/
package org.jboss.modules;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
/**
* Forms a list of {@link DependencySpec} which represent the dependencies of the "java.se"
* module
*/
final class JavaSeDeps {
static final List<DependencySpec> list;
static {
final Optional<ModuleReference> javaSe = ModuleFinder.ofSystem().find("java.se");
final ModuleDescriptor javaSeDescriptor = javaSe.isPresent() ? javaSe.get().descriptor() : null;
if (javaSeDescriptor == null) {
// this shouldn't happen ever, since Java 9+ always has the java.se module.
// But, if it does happen for some reason, we tolerate it and use an empty
// DependencySpec
list = Collections.emptyList();
} else {
final List<DependencySpec> deps = new ArrayList<>();
for (final ModuleDescriptor.Requires dep : javaSeDescriptor.requires()) {
deps.add(new ModuleDependencySpecBuilder().setName(dep.name()).setExport(true).build());
}
list = Collections.unmodifiableList(deps);
}
}
}
\ No newline at end of file
......@@ -19,7 +19,11 @@
package org.jboss.modules;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
/**
......@@ -31,4 +35,29 @@ public class JDKModuleLoaderTest extends AbstractModuleTestCase {
final URL resource = module.getClassLoader().getResource("org/jboss/modules/Main.class");
Assert.assertNotNull("Main.class", resource);
}
/**
* Tests that loading of "java.se" module works and classes that are present
* in modules "required" by this "java.se" module can be loaded too
*
* @throws Exception
*/
@Test
public void testJavaSeModuleLoad() throws Exception {
final Module module = Module.getBootModuleLoader().loadModule("java.se");
Assert.assertNotNull("java.se module not found", module);
final String resultSetClassName = "java.sql.ResultSet";
final Class<?> klass = module.getClassLoader().loadClass(resultSetClassName);
Assert.assertNotNull(resultSetClassName + " class couldn't be loaded from java.se module", klass);
// test a class that was introduced in Java 11
String specString = System.getProperty("java.specification.version");
Pattern pat = Pattern.compile("(?:1\\.)?(\\d+)");
Matcher matcher = pat.matcher(specString);
Assume.assumeTrue("Java 11 is required to test loading of classes " +
"in java.net.http module", matcher.matches() && Integer.parseInt(matcher.group(1)) >= 11);
final String httpClientClassName = "java.net.http.HttpClient";
final Class<?> httpClientClass = module.getClassLoader().loadClass(httpClientClassName);
Assert.assertNotNull(httpClientClassName + " class couldn't be loaded from java.se module", httpClientClass);
}
}
......@@ -56,7 +56,7 @@ public class MavenResourceTest {
@Test
public void testWithPassedRepository() throws Exception {
System.setProperty("maven.repo.local", tmpdir.newFolder("repository").getAbsolutePath());
System.setProperty("remote.maven.repo", "http://repository.jboss.org/nexus/content/groups/public/,https://maven-central.storage.googleapis.com/");
System.setProperty("remote.maven.repo", "https://repository.jboss.org/nexus/content/groups/public/,https://maven-central.storage.googleapis.com/");
try {
Module module = moduleLoader.loadModule(MODULE_ID);
URL url = module.getResource("org/jboss/resteasy/plugins/providers/jackson/ResteasyJacksonProvider.class");
......