Skip to content
Commits on Source (8)
jboss-modules (1.9.0-1) unstable; urgency=medium
* New upstream version 1.9.0.
* Declare compliance with Debian Policy 4.3.0.
* Use canonical VCS URI.
* Remove get-orig-source target.
-- Markus Koschany <apo@debian.org> Mon, 21 Jan 2019 23:25:15 +0100
jboss-modules (1.8.7-1) unstable; urgency=medium
* New upstream version 1.8.7.
......
......@@ -14,9 +14,9 @@ Build-Depends:
libmaven-javadoc-plugin-java,
libmaven-source-plugin-java,
maven-debian-helper (>= 1.5)
Standards-Version: 4.2.1
Vcs-Git: https://anonscm.debian.org/git/pkg-java/jboss-modules.git
Vcs-Browser: https://anonscm.debian.org/cgit/pkg-java/jboss-modules.git
Standards-Version: 4.3.0
Vcs-Git: https://salsa.debian.org/java-team/jboss-modules.git
Vcs-Browser: https://salsa.debian.org/java-team/jboss-modules
Homepage: https://github.com/jboss-modules/jboss-modules
Package: libjboss-modules-java
......
......@@ -3,7 +3,7 @@ Upstream-Name: JBoss Modules
Source: https://github.com/jboss-modules/jboss-modules
Files: *
Copyright: 2014, Red Hat, Inc.
Copyright: 2014-2019, Red Hat, Inc.
License: Apache-2.0
Files: src/main/java/org/jboss/modules/xml/XmlPullParser.java
......@@ -25,7 +25,7 @@ License: LGPL-2.1+
Files: debian/*
Copyright: 2015, Alexandre Viau <alexandre@alexandreviau.net>
2015-2018, Markus Koschany <apo@debian.org>
2015-2019, Markus Koschany <apo@debian.org>
License: Apache-2.0
License: Apache-2.0
......
......@@ -3,5 +3,3 @@
%:
dh $@ --buildsystem=maven
get-orig-source:
uscan --verbose --download-current-version --force-download
......@@ -23,7 +23,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.jboss.modules</groupId>
<artifactId>jboss-modules</artifactId>
<version>1.8.7.Final</version>
<version>1.9.0.Final</version>
<name>JBoss Modules</name>
<parent>
......
/*
* JBoss, Home of Professional Open Source.
* Copyright 2018 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.modules;
import java.nio.ByteBuffer;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import static java.security.AccessController.doPrivileged;
/**
* A hook for frameworks which need to define additional classes to a module's class loader.
*/
public final class ClassDefiner {
private static final ClassDefiner instance = new ClassDefiner();
private static final RuntimePermission createClassLoaderPermission = new RuntimePermission("createClassLoader");
private ClassDefiner() {}
/**
* Define a class using the module and protection domain of an existing class.
*
* @param originalClass the existing class (must not be {@code null})
* @param className the new class name (must not be {@code null})
* @param classBytes the new class bytes (must not be {@code null})
* @return the defined class (not {@code null})
*/
public Class<?> defineClass(Class<?> originalClass, String className, ByteBuffer classBytes) {
return defineClass(originalClass, className, getProtectionDomain(originalClass), classBytes);
}
/**
* Define a class using the module and protection domain of an existing class.
*
* @param originalClass the existing class (must not be {@code null})
* @param className the new class name (must not be {@code null})
* @param classBytes the new class bytes (must not be {@code null})
* @param off the offset into the {@code classBytes} array
* @param len the number of bytes to use from the {@code classBytes} array
* @return the defined class (not {@code null})
*/
public Class<?> defineClass(Class<?> originalClass, String className, byte[] classBytes, int off, int len) {
return defineClass(originalClass, className, getProtectionDomain(originalClass), classBytes, off, len);
}
/**
* Define a class using the module and protection domain of an existing class.
*
* @param originalClass the existing class (must not be {@code null})
* @param className the new class name (must not be {@code null})
* @param classBytes the new class bytes (must not be {@code null})
* @return the defined class (not {@code null})
*/
public Class<?> defineClass(Class<?> originalClass, String className, byte[] classBytes) {
return defineClass(originalClass, className, getProtectionDomain(originalClass), classBytes, 0, classBytes.length);
}
/**
* Define a class using the module of an existing class.
*
* @param originalClass the existing class (must not be {@code null})
* @param className the new class name (must not be {@code null})
* @param protectionDomain the protection domain of the new class (must not be {@code null})
* @param classBytes the new class bytes (must not be {@code null})
* @return the defined class (not {@code null})
*/
public Class<?> defineClass(Class<?> originalClass, String className, ProtectionDomain protectionDomain, ByteBuffer classBytes) {
final Module module = Module.forClass(originalClass);
if (module == null) throw new IllegalArgumentException("Original " + originalClass + " does not have a module");
return module.getClassLoaderPrivate().defineClassInternal(className, classBytes, protectionDomain);
}
/**
* Define a class using the module of an existing class.
*
* @param originalClass the existing class (must not be {@code null})
* @param className the new class name (must not be {@code null})
* @param protectionDomain the protection domain of the new class (must not be {@code null})
* @param classBytes the new class bytes (must not be {@code null})
* @param off the offset into the {@code classBytes} array
* @param len the number of bytes to use from the {@code classBytes} array
* @return the defined class (not {@code null})
*/
public Class<?> defineClass(Class<?> originalClass, String className, ProtectionDomain protectionDomain, byte[] classBytes, int off, int len) {
final Module module = Module.forClass(originalClass);
if (module == null) throw new IllegalArgumentException("Original " + originalClass + " does not have a module");
return module.getClassLoaderPrivate().defineClassInternal(className, classBytes, off, len, protectionDomain);
}
/**
* Define a class using the module of an existing class.
*
* @param originalClass the existing class (must not be {@code null})
* @param className the new class name (must not be {@code null})
* @param protectionDomain the protection domain of the new class (must not be {@code null})
* @param classBytes the new class bytes (must not be {@code null})
* @return the defined class (not {@code null})
*/
public Class<?> defineClass(Class<?> originalClass, String className, ProtectionDomain protectionDomain, byte[] classBytes) {
return defineClass(originalClass, className, protectionDomain, classBytes, 0, classBytes.length);
}
/**
* Define a class.
*
* @param module the module to define the class to (must not be {@code null})
* @param className the new class name (must not be {@code null})
* @param protectionDomain the protection domain of the new class (must not be {@code null})
* @param classBytes the new class bytes (must not be {@code null})
* @return the defined class (not {@code null})
*/
public Class<?> defineClass(Module module, String className, ProtectionDomain protectionDomain, ByteBuffer classBytes) {
return module.getClassLoaderPrivate().defineClassInternal(className, classBytes, protectionDomain);
}
/**
* Define a class.
*
* @param module the module to define the class to (must not be {@code null})
* @param className the new class name (must not be {@code null})
* @param protectionDomain the protection domain of the new class (must not be {@code null})
* @param classBytes the new class bytes (must not be {@code null})
* @param off the offset into the {@code classBytes} array
* @param len the number of bytes to use from the {@code classBytes} array
* @return the defined class (not {@code null})
*/
public Class<?> defineClass(Module module, String className, ProtectionDomain protectionDomain, byte[] classBytes, int off, int len) {
return module.getClassLoaderPrivate().defineClassInternal(className, classBytes, off, len, protectionDomain);
}
/**
* Define a class.
*
* @param module the module to define the class to (must not be {@code null})
* @param className the new class name (must not be {@code null})
* @param protectionDomain the protection domain of the new class (must not be {@code null})
* @param classBytes the new class bytes (must not be {@code null})
* @return the defined class (not {@code null})
*/
public Class<?> defineClass(Module module, String className, ProtectionDomain protectionDomain, byte[] classBytes) {
return defineClass(module, className, protectionDomain, classBytes, 0, classBytes.length);
}
/**
* Get the class definer instance. The caller must have the {@code createClassLoader} {@link RuntimePermission}.
*
* @return the singleton class definer instance (not {@code null})
*/
public static ClassDefiner getInstance() {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(createClassLoaderPermission);
}
return instance;
}
private ProtectionDomain getProtectionDomain(final Class<?> clazz) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
return doPrivileged((PrivilegedAction<ProtectionDomain>) clazz::getProtectionDomain);
} else {
return clazz.getProtectionDomain();
}
}
}
......@@ -449,6 +449,42 @@ public class ModuleClassLoader extends ConcurrentClassLoader {
}
}
Class<?> defineClassInternal(final String className, ByteBuffer byteBuffer, final ProtectionDomain protectionDomain) {
if (transformer != null) {
int pos = byteBuffer.position();
int lim = byteBuffer.limit();
ByteBuffer transformed;
try {
transformed = transformer.transform(this, className.replace('.', '/'), protectionDomain, byteBuffer);
} catch (Exception e) {
ClassFormatError error = new ClassFormatError(e.getMessage());
error.initCause(e);
throw error;
}
if (transformed != null) {
byteBuffer = transformed;
} else {
byteBuffer.position(0);
byteBuffer.limit(lim);
byteBuffer.position(pos);
}
}
final long start = Metrics.getCurrentCPUTime();
final Class<?> defined = defineClass(className, byteBuffer, protectionDomain);
module.getModuleLoader().addClassLoadTime(Metrics.getCurrentCPUTime() - start);
return defined;
}
Class<?> defineClassInternal(final String className, byte[] bytes, int off, int len, final ProtectionDomain protectionDomain) {
if (transformer != null) {
return defineClassInternal(className, ByteBuffer.wrap(bytes, off, len), protectionDomain);
}
final long start = Metrics.getCurrentCPUTime();
final Class<?> defined = defineClass(className, bytes, off, len, protectionDomain);
module.getModuleLoader().addClassLoadTime(Metrics.getCurrentCPUTime() - start);
return defined;
}
/**
* Define a class from a class name and class spec. Also defines any enclosing {@link Package} instances,
* and performs any sealed-package checks.
......
......@@ -108,6 +108,13 @@ public final class ModuleXmlParser {
}
}
/**
* XML parsing callback for property elements.
*/
private interface PropertiesCallback {
void parsedProperty(String name, String value);
}
private ModuleXmlParser() {
}
......@@ -120,6 +127,7 @@ public final class ModuleXmlParser {
private static final String MODULE_1_6 = "urn:jboss:module:1.6";
private static final String MODULE_1_7 = "urn:jboss:module:1.7";
private static final String MODULE_1_8 = "urn:jboss:module:1.8";
private static final String MODULE_1_9 = "urn:jboss:module:1.9";
private static final String E_MODULE = "module";
private static final String E_ARTIFACT = "artifact";
......@@ -175,6 +183,24 @@ public final class ModuleXmlParser {
private static final List<String> LIST_A_NAME_A_TARGET_NAME = Arrays.asList(A_NAME, A_TARGET_NAME);
private static final List<String> LIST_A_PERMISSION_A_NAME = Arrays.asList(A_PERMISSION, A_NAME);
private static PropertiesCallback NOOP_PROPS_CALLBACK;
/**
* Returns a no-op implementation of properties callback currently used for
* parsing properties attached to module dependencies that aren't used at
* runtime in jboss-modules but are important in other projects where
* module dependencies are analyzed.
*
* @return a no-op implementation of properties callback
*/
private static PropertiesCallback getNoopPropsCallback() {
return NOOP_PROPS_CALLBACK == null ? NOOP_PROPS_CALLBACK = new PropertiesCallback() {
@Override
public void parsedProperty(String name, String value) {
}
} : NOOP_PROPS_CALLBACK;
}
/**
* Parse a {@code module.xml} file.
*
......@@ -394,6 +420,7 @@ public final class ModuleXmlParser {
case MODULE_1_6:
case MODULE_1_7:
case MODULE_1_8:
case MODULE_1_9:
break;
default: throw unexpectedContent(reader);
}
......@@ -408,7 +435,11 @@ public final class ModuleXmlParser {
}
private static boolean atLeast1_8(final XmlPullParser reader) {
return MODULE_1_8.equals(reader.getNamespace());
return MODULE_1_8.equals(reader.getNamespace()) || atLeast1_9(reader);
}
private static boolean atLeast1_9(final XmlPullParser reader) {
return MODULE_1_9.equals(reader.getNamespace());
}
private static void assertNoAttributes(final XmlPullParser reader) throws XmlPullParserException {
......@@ -677,7 +708,15 @@ public final class ModuleXmlParser {
case E_DEPENDENCIES: parseDependencies(reader, dependencies); break;
case E_MAIN_CLASS: parseMainClass(reader, specBuilder); break;
case E_RESOURCES: parseResources(mavenResolver, factory, rootPath, reader, specBuilder); break;
case E_PROPERTIES: parseProperties(reader, specBuilder); break;
case E_PROPERTIES: parseProperties(reader, new PropertiesCallback() {
@Override
public void parsedProperty(String name, String value) {
specBuilder.addProperty(name, value);
if ("jboss.assertions".equals(name)) try {
specBuilder.setAssertionSetting(AssertionSetting.valueOf(value.toUpperCase(Locale.US)));
} catch (IllegalArgumentException ignored) {}
}
}); break;
case E_PERMISSIONS: parsePermissions(reader, moduleLoader, realModuleName, specBuilder); gotPerms = true; break;
case E_PROVIDES: if (is1_8) parseProvidesType(reader, specBuilder); else throw unexpectedContent(reader); break;
default: throw unexpectedContent(reader);
......@@ -794,6 +833,7 @@ public final class ModuleXmlParser {
switch (reader.getName()) {
case E_EXPORTS: parseFilterList(reader, exportBuilder); break;
case E_IMPORTS: parseFilterList(reader, importBuilder); break;
case E_PROPERTIES: if (atLeast1_9(reader)) { parseProperties(reader, getNoopPropsCallback()); break; }
default: throw unexpectedContent(reader);
}
break;
......@@ -1019,9 +1059,6 @@ 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);
......@@ -1281,7 +1318,7 @@ public final class ModuleXmlParser {
parseNoContent(reader);
}
private static void parseProperties(final XmlPullParser reader, final ModuleSpec.Builder specBuilder) throws XmlPullParserException, IOException {
private static void parseProperties(final XmlPullParser reader, final PropertiesCallback propsCallback) throws XmlPullParserException, IOException {
assertNoAttributes(reader);
// xsd:choice
int eventType;
......@@ -1295,7 +1332,7 @@ public final class ModuleXmlParser {
validateNamespace(reader);
switch (reader.getName()) {
case E_PROPERTY: {
parseProperty(reader, specBuilder);
parseProperty(reader, propsCallback);
break;
}
default: throw unexpectedContent(reader);
......@@ -1309,7 +1346,7 @@ public final class ModuleXmlParser {
}
}
private static void parseProperty(final XmlPullParser reader, final ModuleSpec.Builder specBuilder) throws XmlPullParserException, IOException {
private static void parseProperty(final XmlPullParser reader, final PropertiesCallback propsCallback) throws XmlPullParserException, IOException {
String name = null;
String value = null;
final Set<String> required = new HashSet<>(LIST_A_NAME);
......@@ -1327,10 +1364,7 @@ public final class ModuleXmlParser {
if (! required.isEmpty()) {
throw missingAttributes(reader, required);
}
specBuilder.addProperty(name, value == null ? "true" : value);
if ("jboss.assertions".equals(name)) try {
specBuilder.setAssertionSetting(AssertionSetting.valueOf(value.toUpperCase(Locale.US)));
} catch (IllegalArgumentException ignored) {}
propsCallback.parsedProperty(name, value == null ? "true" : value);
// consume remainder of element
parseNoContent(reader);
......
This diff is collapsed.
/*
* JBoss, Home of Professional Open Source.
* Copyright 2018 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.modules;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.CodeSigner;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.Collection;
import java.util.Collections;
import org.jboss.modules.util.TestModuleLoader;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*/
public class ClassDefinerTest extends AbstractModuleTestCase {
private TestModuleLoader moduleLoader;
@Before
public void setupModuleLoader() {
moduleLoader = new TestModuleLoader();
ModuleSpec.Builder builder = ModuleSpec.build("org.module.foo");
builder.addDependency(ModuleDependencySpec.JAVA_BASE);
builder.addDependency(DependencySpec.OWN_DEPENDENCY);
builder.addResourceRoot(ResourceLoaderSpec.createResourceLoaderSpec(new ResourceLoader() {
public ClassSpec getClassSpec(final String fileName) {
return null;
}
public PackageSpec getPackageSpec(final String name) {
return null;
}
public Resource getResource(final String name) {
return null;
}
public String getLibrary(final String name) {
return null;
}
public Collection<String> getPaths() {
return Collections.singletonList("org/module/foo");
}
}));
moduleLoader.addModuleSpec(builder.create());
}
@Test
public void testDefineClass() throws ModuleLoadException, IOException, ClassNotFoundException {
final ClassDefiner classDefiner = ClassDefiner.getInstance();
final Module module = moduleLoader.loadModule("org.module.foo");
final URL resource = ClassDefinerTest.class.getClassLoader().getResource("test/GeneratedClass.class");
assertNotNull(resource);
final byte[] classBytes;
try (final InputStream stream = resource.openConnection().getInputStream()) {
try (final ByteArrayOutputStream os = new ByteArrayOutputStream()) {
byte[] buf = new byte[256];
int res;
while ((res = stream.read(buf)) != -1) {
os.write(buf, 0, res);
}
classBytes = os.toByteArray();
}
}
Class<?> c1 = classDefiner.defineClass(module, "org.module.foo.GeneratedClass", new ProtectionDomain(
new CodeSource(
resource, (CodeSigner[]) null
),
ModulesPolicy.DEFAULT_PERMISSION_COLLECTION
), classBytes);
Class<?> c2 = module.getClassLoaderPrivate().loadClass("org.module.foo.GeneratedClass");
assertEquals(c1, c2);
assertEquals(module.getClassLoaderPrivate(), c1.getClassLoader());
}
}
......@@ -24,6 +24,7 @@ import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
/**
* Test to verify the functionality of module properties.
......@@ -47,4 +48,37 @@ public class ModulePropertyTest extends AbstractModuleTestCase {
assertEquals("true", module.getProperty("test.prop.1"));
assertEquals("propertyValue", module.getProperty("test.prop.2"));
}
/**
* This test parses properties attached to module dependencies.
* The properties are currently not exposed via the dependency spec API,
* so the test simply makes sure they can be parsed w/o errors.
* @throws Exception
*/
@Test
public void testModuleDependencyProperties() throws Exception {
Module module = moduleLoader.loadModule("test.dep-props");
assertNull(module.getProperty("non-existent"));
assertEquals("blah", module.getProperty("non-existent", "blah"));
final DependencySpec[] deps = module.getDependencies();
int testedDepsTotal = 0;
for(DependencySpec dep : deps) {
if(!(dep instanceof ModuleDependencySpec)) {
continue;
}
final ModuleDependencySpec moduleDep = (ModuleDependencySpec) dep;
String depName = moduleDep.getName();
if(!depName.startsWith("test.")) {
continue;
}
++testedDepsTotal;
depName = depName.substring("test.".length());
if(depName.equals("test")) {
} else {
fail("Unexpected module dependency " + moduleDep);
}
}
assertEquals(1, testedDepsTotal);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2018 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<module xmlns="urn:jboss:module:1.9" name="test.dep-props">
<resources/>
<dependencies>
<module name="test.test">
<properties>
<property name="test.dep.prop.1"/>
<property name="test.dep.prop.2" value="depPropertyValue"/>
</properties>
</module>
</dependencies>
</module>