![JAR search and dependency download from the Maven repository](/logo.png)
org.jboss.byteman.modules.jbossmodules.JBossModulesSystem Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source
* Copyright 2015 Red Hat and individual contributors
* by the @authors tag. See the copyright.txt 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.
*
* @authors James Livingston
*/
package org.jboss.byteman.modules.jbossmodules;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import org.jboss.byteman.modules.ClassbyteClassLoader;
import org.jboss.byteman.modules.ModuleSystem;
import org.jboss.byteman.rule.helper.Helper;
import org.jboss.modules.DependencySpec;
import org.jboss.modules.Module;
import org.jboss.modules.ModuleFinder;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.modules.ModuleLoadException;
import org.jboss.modules.ModuleLoader;
import org.jboss.modules.ModuleSpec;
import org.jboss.modules.ModuleSpec.Builder;
public class JBossModulesSystem implements ModuleSystem
{
private boolean lazyInited = false;
private ModuleLoader ruleModuleLoader; // where the rule modules are stores
private final AtomicBoolean warningEmitted = new AtomicBoolean(false);
private final AtomicLong currentRuleNumber = new AtomicLong();
private Map ruleModules;
private static final String RULE_MODULE_PREFIX = "byteman.rule";
private static final Set BYTEMAN_PACKAGE_PATHS;
static
{
BYTEMAN_PACKAGE_PATHS = new HashSet();
BYTEMAN_PACKAGE_PATHS.add("org/jboss/byteman/rule/exception");
BYTEMAN_PACKAGE_PATHS.add("org/jboss/byteman/rule/helper");
}
public void initialize(String args)
{
if (!args.isEmpty())
Helper.err("Unexpcted module system arguments: " + args);
// NOTE: this will be run at agent start, be careful
}
private synchronized void lazyInit()
{
if (lazyInited)
return;
// perform any initialization that can't be done at agent start time
lazyInited = true;
// store all the module specification in an instance map.
ruleModules = new ConcurrentHashMap();
ModuleFinder[] finders = new ModuleFinder[] {
new ModuleFinder() {
public ModuleSpec findModule(ModuleIdentifier identifier,
ModuleLoader delegateLoader) throws ModuleLoadException {
return ruleModules.get(identifier);
}
}
};
ruleModuleLoader = new ModuleLoaderWrapper(finders);
}
/**
* Utility class to allow instantiating {@link ModuleLoader} with jboss-modules version 1.2.0 and earlier (protected constructors)
*/
public class ModuleLoaderWrapper extends ModuleLoader
{
public ModuleLoaderWrapper(ModuleFinder[] finders) {
super(finders);
}
}
public ClassbyteClassLoader createLoader(ClassLoader triggerClassLoader, String[] imports)
{
if (imports.length == 0) {
// do the same thing as NonModuleSystem
return new ClassbyteClassLoader(triggerClassLoader);
} else {
lazyInit();
try
{
// Installing the real MBean server is the last thing that JBoss Modules (1.4.3) does before calling Module.run
// if it's there, we should be safe to use JBoss Modules
Field regRefField = ModuleLoader.class.getDeclaredField("REG_REF");
regRefField.setAccessible(true);
Object regRef = regRefField.get(null);
if (regRef == null) {
return warnAndFallback(triggerClassLoader, "ModuleLoader.REG_REF is null, JBoss Modules internals may have changed. Assuming it is unsafe to use");
}
String regRefName = regRef.getClass().getName();
if (regRefName.equals("org.jboss.modules.ModuleLoader$TempMBeanReg")) {
return warnAndFallback(triggerClassLoader, "ModuleLoader.REG_REF is TempMBeanReg, JBoss Modules is not fully loaded. Assuming it is unsafe to use");
} else if (regRefName.equals("org.jboss.modules.ModuleLoader$RealMBeanReg")) {
// JBoss Modules appears to be loaded
return createModularLoader(triggerClassLoader, imports);
} else {
return warnAndContinue(triggerClassLoader, imports, "Unknown ModuleLoader.REG_REF implementation " + regRefName + ", JBoss Modules internals may have changed. Assuming it is safe to use");
}
} catch (SecurityException e) {
return warnAndContinue(triggerClassLoader, imports, e, "SecurityException accessing ModuleLoader.REG_REF, JBoss Modules internals may have changed. Assuming it is safe to use");
} catch (NoSuchFieldException e) {
return warnAndContinue(triggerClassLoader, imports, e, "Could not detect ModuleLoader.REG_REF, JBoss Modules internals may have changed. Assuming it is safe to use");
} catch (IllegalAccessException e) {
return warnAndContinue(triggerClassLoader, imports, e, "Could not access ModuleLoader.REG_REF, JBoss Modules internals may have changed. Assuming it is safe to use");
}
}
}
public void destroyLoader(ClassbyteClassLoader loader)
{
if (loader instanceof ModuleUsingClassbyteClassLoader) {
//TODO: is removing this safe?
ModuleUsingClassbyteClassLoader moduleLoader = (ModuleUsingClassbyteClassLoader) loader;
ModuleIdentifier moduleIdentifier = moduleLoader.getModule().getIdentifier();
ruleModules.remove(moduleIdentifier);
} else {
// do nothing
}
}
public Class> loadHelperAdapter(ClassbyteClassLoader helperLoader, String helperAdapterName, byte[] classBytes)
{
return helperLoader.addClass(helperAdapterName, classBytes);
}
protected ClassbyteClassLoader createModularLoader(ClassLoader triggerClassLoader, String[] imports)
{
try {
long ruleNumber = currentRuleNumber.incrementAndGet();
ModuleIdentifier ruleModuleIdentifier = ModuleIdentifier.create(RULE_MODULE_PREFIX + "." + ruleNumber);
Builder builder = ModuleSpec.build(ruleModuleIdentifier);
// add the package for Byteman bits that the classes need to see
builder.addDependency(DependencySpec.createSystemDependencySpec(BYTEMAN_PACKAGE_PATHS));
// add the imports
// TODO: should we use the module loader of 'triggerClassLoader' if it has one?
// ModuleLoader.forClassLoader(triggerClassLoader);
// FIXME: if JBoss modules has not yet been initialized, this will break things
ModuleLoader bootModuleLoader = Module.getBootModuleLoader();
for (int i = 0; i < imports.length; i++) {
ModuleIdentifier importIdentifier = ModuleIdentifier.fromString(imports[i]);
DependencySpec importDepSpec = DependencySpec.createModuleDependencySpec(bootModuleLoader, importIdentifier, false);
builder.addDependency(importDepSpec);
}
ruleModules.put(ruleModuleIdentifier, builder.create());
return new ModuleUsingClassbyteClassLoader(ruleModuleLoader.loadModule(ruleModuleIdentifier), triggerClassLoader);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
protected ClassbyteClassLoader warnAndFallback(ClassLoader triggerClassLoader, String message)
{
if (!warningEmitted.getAndSet(true)) {
Helper.err(message);
}
return new ClassbyteClassLoader(triggerClassLoader);
}
protected ClassbyteClassLoader warnAndContinue(ClassLoader triggerClassLoader, String[] imports, String message)
{
if (!warningEmitted.getAndSet(true)) {
Helper.err(message);
}
return createModularLoader(triggerClassLoader, imports);
}
protected ClassbyteClassLoader warnAndContinue(ClassLoader triggerClassLoader, String[] imports, Exception e, String message)
{
if (!warningEmitted.getAndSet(true)) {
Helper.err(message);
Helper.errTraceException(e);
}
return createModularLoader(triggerClassLoader, imports);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy