/*
* JBoss, Home of Professional Open Source
* Copyright 2015, Red Hat, Inc., and individual contributors as indicated
* by the @authors tag.
*
* 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.as.server.controller.resources;
import java.lang.reflect.Field;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.ObjectListAttributeDefinition;
import org.jboss.as.controller.ObjectTypeAttributeDefinition;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationDefinition;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.OperationStepHandler;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.SimpleOperationDefinitionBuilder;
import org.jboss.as.controller.StringListAttributeDefinition;
import org.jboss.as.server.logging.ServerLogger;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
import org.jboss.modules.Module;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.modules.ModuleLoader;
import org.jboss.modules.management.DependencyInfo;
import org.jboss.modules.management.ModuleInfo;
import org.jboss.modules.management.ModuleLoaderMXBean;
import org.jboss.modules.management.ResourceLoaderInfo;
/**
* @author Tomaz Cerar (c) 2015 Red Hat Inc.
*/
public class ModuleInfoHandler implements OperationStepHandler {
static final AttributeDefinition MODULE_NAME = SimpleAttributeDefinitionBuilder.create("name", ModelType.STRING)
.setAllowNull(false)
.build();
static final AttributeDefinition MODULE_SLOT = SimpleAttributeDefinitionBuilder.create("slot", ModelType.STRING)
.setDefaultValue(new ModelNode("main"))
.setAllowNull(true)
.build();
//reply parameters
static final AttributeDefinition MAIN_CLASS = SimpleAttributeDefinitionBuilder.create("main-class", ModelType.STRING, true)
.setStorageRuntime()
.build();
static final AttributeDefinition FALLBACK_LOADER = SimpleAttributeDefinitionBuilder.create("fallback-loader", ModelType.STRING, true)
.setStorageRuntime()
.build();
static final ObjectTypeAttributeDefinition DEPENDENCY = ObjectTypeAttributeDefinition.Builder.of("dependency",
SimpleAttributeDefinitionBuilder.create("dependency-name", ModelType.STRING).build(),
SimpleAttributeDefinitionBuilder.create("module-name", ModelType.STRING).build(),
SimpleAttributeDefinitionBuilder.create("export-filter", ModelType.STRING).build(),
SimpleAttributeDefinitionBuilder.create("import-filter", ModelType.STRING).build(),
SimpleAttributeDefinitionBuilder.create("optional", ModelType.BOOLEAN).build(),
SimpleAttributeDefinitionBuilder.create("local-loader-class", ModelType.STRING, true).build(),
new StringListAttributeDefinition.Builder("local-loader-paths").build()
)
.setStorageRuntime()
.build();
static final AttributeDefinition DEPENDENCIES = ObjectListAttributeDefinition.Builder.of("dependencies", DEPENDENCY)
.setStorageRuntime()
.build();
static final ObjectTypeAttributeDefinition RESOURCE_LOADER = ObjectTypeAttributeDefinition.Builder.of("resource-loader",
SimpleAttributeDefinitionBuilder.create("type", ModelType.STRING).build(),
new StringListAttributeDefinition.Builder("paths").build()
)
.setStorageRuntime()
.build();
static final AttributeDefinition RESOURCE_LOADERS = ObjectListAttributeDefinition.Builder.of("resource-loaders", RESOURCE_LOADER)
.setStorageRuntime()
.build();
public static final OperationDefinition DEFINITION = new SimpleOperationDefinitionBuilder("module-info", ModuleLoadingResourceDefinition.INSTANCE.getResourceDescriptionResolver())
.setParameters(MODULE_NAME, MODULE_SLOT)
.setRuntimeOnly()
.setReadOnly()
.setReplyType(ModelType.OBJECT)
.setReplyParameters(MODULE_NAME, MAIN_CLASS, FALLBACK_LOADER, DEPENDENCIES, RESOURCE_LOADERS)
.build();
public static ModuleInfoHandler INSTANCE = new ModuleInfoHandler();
protected void populateModel(final ModelNode operation, final ModelNode model) throws OperationFailedException {
for (AttributeDefinition attr : DEFINITION.getParameters()) {
attr.validateAndSet(operation, model);
}
}
@Override
public void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
ModelNode model = new ModelNode();
populateModel(operation, model);
String moduleName = MODULE_NAME.resolveModelAttribute(context, model).asString();
String slot = MODULE_SLOT.resolveModelAttribute(context, model).asString();
ModuleIdentifier id = ModuleIdentifier.create(moduleName, slot);
ModuleLoader loader = Module.getBootModuleLoader();
try {
ModuleLoaderMXBean mxBean = getMxBean(loader);
ModuleInfo moduleInfo = mxBean.getModuleDescription(id.toString());
context.getResult().set(populateModuleInfo(moduleInfo));
} catch (Exception e) {
throw ServerLogger.ROOT_LOGGER.couldNotGetModuleInfo(id.toString(), e);
}
}
protected ModuleLoaderMXBean getMxBean(ModuleLoader loader) throws ReflectiveOperationException {
Field mxBeanField = ModuleLoader.class.getDeclaredField("mxBean");
mxBeanField.setAccessible(true);
return (ModuleLoaderMXBean) mxBeanField.get(loader);
}
/*
Here is the information to expose (use ModuleLoaderMXBean as a source of information):
Loaded module names
For each module:
Module name
Main class name (if any)
Class loader name string
Fallback loader name string
Dependency information:
Dependency type
Export filter string
Import filter string
Dependency module name
Is-optional flag
Local loader type class name
Local loader paths
Resource loader information for each module:
Resource loader type string
Resource loader paths
Note that there are multiple module loaders. For our purposes there should be (at least) two categories displayed:
The static module loader
The deployment module loader
*/
private ModelNode populateModuleInfo(ModuleInfo module) throws Exception {
ModelNode result = new ModelNode();
result.get("name").set(module.getName());
ModelNode value;
value = result.get("main-class");
if (module.getMainClass() != null) {
value.set(module.getMainClass());
}
value = result.get("fallback-loader");
if (module.getFallbackLoader() != null) {
value.set(module.getFallbackLoader());
}
ModelNode dependencies = result.get("dependencies").setEmptyList();
for (DependencyInfo dependencySpec : module.getDependencies()) {
if (dependencySpec.getModuleName() == null) {
continue; //todo check why it returns empty dependancy
}
ModelNode dependency = dependencies.add();
dependency.get("dependency-name").set(dependencySpec.getDependencyType());
dependency.get("module-name").set(dependencySpec.getModuleName());
dependency.get("export-filter").set(dependencySpec.getExportFilter());
dependency.get("import-filter").set(dependencySpec.getImportFilter());
dependency.get("optional").set(dependencySpec.isOptional());
value = result.get("local-loader-class");
if (dependencySpec.getLocalLoader() != null) {
value.set(dependencySpec.getLocalLoader());
}
if (dependencySpec.getLocalLoaderPaths() != null) {
ModelNode paths = dependency.get("local-loader-paths");
for (String path : dependencySpec.getLocalLoaderPaths()) {
paths.add(path);
}
}
}
ModelNode resourceLoaders = result.get("resource-loaders").setEmptyList();
for (ResourceLoaderInfo loaderInfo : module.getResourceLoaders()) {
ModelNode loader = resourceLoaders.add();
loader.get("type").set(loaderInfo.getType());
ModelNode paths = loader.get("paths");
for (String path : loaderInfo.getPaths()) {
paths.add(path);
}
}
return result;
}
}