/* * 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; } }