/* * * JBoss, Home of Professional Open Source. * Copyright 2014, 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.as.jmx; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DESCRIPTION; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.EXPRESSIONS_ALLOWED; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.TYPE; import java.math.BigDecimal; import java.math.BigInteger; import java.util.LinkedList; import java.util.List; import org.jboss.as.controller.AbstractAddStepHandler; import org.jboss.as.controller.AttributeDefinition; import org.jboss.as.controller.ModelOnlyWriteAttributeHandler; 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.PathAddress; import org.jboss.as.controller.PathElement; import org.jboss.as.controller.PrimitiveListAttributeDefinition; import org.jboss.as.controller.ReloadRequiredRemoveStepHandler; import org.jboss.as.controller.ReloadRequiredWriteAttributeHandler; import org.jboss.as.controller.SimpleAttributeDefinition; import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; import org.jboss.as.controller.SimpleMapAttributeDefinition; import org.jboss.as.controller.SimpleOperationDefinition; import org.jboss.as.controller.SimpleOperationDefinitionBuilder; import org.jboss.as.controller.SimpleResourceDefinition; import org.jboss.as.controller.descriptions.NonResolvingResourceDescriptionResolver; import org.jboss.as.controller.operations.validation.AllowedValuesValidator; import org.jboss.as.controller.operations.validation.ModelTypeValidator; import org.jboss.as.controller.registry.ManagementResourceRegistration; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; /** * @author Tomaz Cerar (c) 2014 Red Hat Inc. */ public class ModelControllerResourceDefinition extends SimpleResourceDefinition { private final boolean allowExpressions; private final boolean forStandalone; private ModelNode complexValueType; protected ObjectTypeAttributeDefinition complex; private SimpleOperationDefinition COMPLEX_OP_DEF; private void init() { complexValueType = new ModelNode(); complexValueType.get("int-value", DESCRIPTION).set("An int value"); complexValueType.get("int-value", EXPRESSIONS_ALLOWED).set(allowExpressions); complexValueType.get("int-value", TYPE).set(ModelType.INT); complexValueType.get("bigdecimal-value", DESCRIPTION).set("A bigdecimal value"); complexValueType.get("bigdecimal-value", TYPE).set(ModelType.BIG_DECIMAL); complexValueType.get("bigdecimal-value", EXPRESSIONS_ALLOWED).set(allowExpressions); SimpleAttributeDefinition intValue = createAttribute("int-value", ModelType.INT, allowExpressions); SimpleAttributeDefinition bigDecimal = createAttribute("bigdecimal-value", ModelType.BIG_DECIMAL, allowExpressions); complex = new ObjectTypeAttributeDefinition.Builder("complex", intValue, bigDecimal).build(); AttributeDefinition param1 = new ObjectTypeAttributeDefinition.Builder("param1", intValue, bigDecimal).build(); COMPLEX_OP_DEF = new SimpleOperationDefinitionBuilder("complex", new NonResolvingResourceDescriptionResolver()) .addParameter(param1) .setReplyType(ModelType.OBJECT) .setReplyParameters(complex) .build(); } public ModelControllerResourceDefinition(boolean allowExpressions, boolean forStandalone) { super(PathElement.pathElement("subsystem", "test"), new NonResolvingResourceDescriptionResolver(), TestSubystemAdd.INSTANCE, ReloadRequiredRemoveStepHandler.INSTANCE ); this.allowExpressions = allowExpressions; this.forStandalone = forStandalone; init(); } @Override public void registerOperations(ManagementResourceRegistration registration) { super.registerOperations(registration); // TODO for domain server we have to register ops as RUNTIME_ONLY or they get stripped from r-r-d results, // which is not ideal but not relevant to this test registration.registerOperationHandler(forStandalone ? VoidOperationNoParams.DEFINITION_STANDALONE : VoidOperationNoParams.DEFINITION_DOMAIN, VoidOperationNoParams.INSTANCE); IntOperationWithParams intOp = allowExpressions ? IntOperationWithParams.INSTANCE_EXPRESSIONS : IntOperationWithParams.INSTANCE_NO_EXPRESSIONS; registration.registerOperationHandler(forStandalone ? intOp.DEFINITION_STANDALONE : intOp.DEFINITION_DOMAIN, intOp); ComplexOperation op = new ComplexOperation(complexValueType); registration.registerOperationHandler(COMPLEX_OP_DEF, op); } @Override public void registerAttributes(ManagementResourceRegistration resourceRegistration) { super.registerAttributes(resourceRegistration); resourceRegistration.registerReadOnlyAttribute(createAttribute("ro-int", ModelType.INT, allowExpressions), null); addAttribute("undefined-int", ModelType.INT, resourceRegistration); addAttribute("int", ModelType.INT, resourceRegistration); addAttribute("bigint", ModelType.BIG_INTEGER, resourceRegistration); addAttribute("bigdec", ModelType.BIG_DECIMAL, resourceRegistration); addAttribute("boolean", ModelType.BOOLEAN, resourceRegistration); addAttribute("bytes", ModelType.BYTES, resourceRegistration); addAttribute("double", ModelType.DOUBLE, resourceRegistration); addAttribute("string", ModelType.STRING, resourceRegistration); addAttribute("long", ModelType.LONG, resourceRegistration); addAttribute("type", ModelType.TYPE, resourceRegistration); PrimitiveListAttributeDefinition list = new PrimitiveListAttributeDefinition.Builder("list", ModelType.INT).setAllowNull(true).setAllowExpression(allowExpressions).build(); resourceRegistration.registerReadWriteAttribute(list, null, new ReloadRequiredWriteAttributeHandler(list)); SimpleMapAttributeDefinition map = new SimpleMapAttributeDefinition.Builder("map", ModelType.INT, true).setAllowNull(true).setAllowExpression(allowExpressions).build(); resourceRegistration.registerReadWriteAttribute(map, null, new ReloadRequiredWriteAttributeHandler(map)); resourceRegistration.registerReadWriteAttribute(complex, null, new ComplexWriteAttributeHandler()); } private static SimpleAttributeDefinition createAttribute(String name, ModelType type, boolean allowExpressions) { return new SimpleAttributeDefinitionBuilder(name, type, true) .setAllowExpression(allowExpressions) .build(); } private void addAttribute(String name, ModelType type, ManagementResourceRegistration resourceRegistration) { AttributeDefinition attr = createAttribute(name, type, allowExpressions); resourceRegistration.registerReadWriteAttribute(attr, null, new ModelOnlyWriteAttributeHandler(attr)); } class ComplexWriteAttributeHandler extends ReloadRequiredWriteAttributeHandler { @Override public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { super.execute(context, operation); } } static class TestSubystemAdd extends AbstractAddStepHandler { static final TestSubystemAdd INSTANCE = new TestSubystemAdd(); @Override protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException { model.get("ro-int").set(1); model.get("int").set(2); model.get("bigint").set(new BigInteger("3")); model.get("bigdec").set(new BigDecimal("4")); model.get("boolean").set(false); model.get("bytes").set(new byte[]{5, 6}); model.get("double").set(7.0); model.get("string").set("8"); model.get("list").add(new Integer(9)); model.get("long").set(10L); model.get("type").set(ModelType.INT); model.get("map", "key1").set(11); model.get("map", "key2").set(12); } } static class VoidOperationNoParams implements OperationStepHandler { static final String OPERATION_NAME = "void-no-params"; static final OperationDefinition DEFINITION_STANDALONE = new SimpleOperationDefinitionBuilder(VoidOperationNoParams.OPERATION_NAME, new NonResolvingResourceDescriptionResolver()) .setReadOnly() .build(); static final OperationDefinition DEFINITION_DOMAIN = new SimpleOperationDefinitionBuilder(VoidOperationNoParams.OPERATION_NAME, new NonResolvingResourceDescriptionResolver()) .setReadOnly() .setRuntimeOnly() .build(); static final VoidOperationNoParams INSTANCE = new VoidOperationNoParams(); static final String OPERATION_JMX_NAME = "voidNoParams"; boolean invoked; @Override public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { invoked = true; } } static class IntOperationWithParams implements OperationStepHandler { boolean allowExpressions; final SimpleAttributeDefinition param1 = createAttribute("param1", ModelType.LONG, allowExpressions); final PrimitiveListAttributeDefinition param2 = new PrimitiveListAttributeDefinition.Builder("param2", ModelType.STRING).setAllowExpression(allowExpressions).build(); final SimpleMapAttributeDefinition param3 = new SimpleMapAttributeDefinition.Builder("param3", ModelType.INT, true) .setAllowExpression(allowExpressions) .build(); final SimpleAttributeDefinition param4 = new SimpleAttributeDefinitionBuilder("param4", ModelType.INT) .setDefaultValue(new ModelNode(6)) //.setValidator(new IntRangeValidator(5,10,true,false)) //todo expressions & min/max dont match well WFLY-3500 .setAllowExpression(allowExpressions) .build(); final SimpleAttributeDefinition param5 = new SimpleAttributeDefinitionBuilder("param5", ModelType.INT) .setAllowExpression(allowExpressions) .setValidator(new IntAllowedValuesValidator(3, 5, 7)) .build(); final OperationDefinition DEFINITION_STANDALONE = new SimpleOperationDefinitionBuilder(IntOperationWithParams.OPERATION_NAME, new NonResolvingResourceDescriptionResolver()) .setParameters(param1, param2, param3, param4, param5) .setReplyType(ModelType.STRING) .build(); final OperationDefinition DEFINITION_DOMAIN = new SimpleOperationDefinitionBuilder(IntOperationWithParams.OPERATION_NAME, new NonResolvingResourceDescriptionResolver()) .setParameters(param1, param2, param3, param4, param5) .setReplyType(ModelType.STRING) .setRuntimeOnly() .build(); static final IntOperationWithParams INSTANCE_NO_EXPRESSIONS = new IntOperationWithParams(false); static final IntOperationWithParams INSTANCE_EXPRESSIONS = new IntOperationWithParams(true); static final String OPERATION_NAME = "int-with-params"; static final String OPERATION_JMX_NAME = "intWithParams"; boolean invoked; private IntOperationWithParams(boolean allowExpressions) { this.allowExpressions = allowExpressions; } @Override public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { invoked = true; long l = operation.get("param1").resolve().asLong() + context.readResource(PathAddress.EMPTY_ADDRESS).getModel().get("int").asInt() + operation.get("param3", "test").resolve().asInt(); context.getResult().set(operation.get("param2").resolve().asList().get(0).asString() + l); } private static class IntAllowedValuesValidator extends ModelTypeValidator implements AllowedValuesValidator{ private final List<ModelNode> allowedValues = new LinkedList<>(); private IntAllowedValuesValidator(int ... allowedValues) { super(ModelType.INT); for (int allowedValue : allowedValues) { this.allowedValues.add(new ModelNode(allowedValue)); } } @Override public List<ModelNode> getAllowedValues() { return allowedValues; } } } class ComplexOperation implements OperationStepHandler { static final String OPERATION_NAME = "complex"; final ModelNode complexValueType; public ComplexOperation(ModelNode complexValueType) { this.complexValueType = complexValueType; } @Override public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { context.getResult().set(operation.get("param1")); } } }