Package org.jboss.as.cli.handlers

Source Code of org.jboss.as.cli.handlers.GenericTypeOperationHandler

/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, 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.cli.handlers;


import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jboss.as.cli.CommandArgument;
import org.jboss.as.cli.CommandContext;
import org.jboss.as.cli.CommandFormatException;
import org.jboss.as.cli.CommandLineCompleter;
import org.jboss.as.cli.ParsedArguments;
import org.jboss.as.cli.Util;
import org.jboss.as.cli.impl.ArgumentWithValue;
import org.jboss.as.cli.impl.ArgumentWithoutValue;
import org.jboss.as.cli.impl.DefaultCompleter;
import org.jboss.as.cli.impl.DefaultCompleter.CandidatesProvider;
import org.jboss.as.cli.operation.OperationFormatException;
import org.jboss.as.cli.operation.OperationRequestAddress;
import org.jboss.as.cli.operation.OperationRequestParser;
import org.jboss.as.cli.operation.impl.DefaultOperationCallbackHandler;
import org.jboss.as.cli.operation.impl.DefaultOperationRequestAddress;
import org.jboss.as.cli.operation.impl.DefaultOperationRequestBuilder;
import org.jboss.as.cli.operation.impl.DefaultOperationRequestParser;
import org.jboss.as.controller.client.ModelControllerClient;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.Property;

/**
*
* @author Alexey Loubyansky
*/
public class GenericTypeOperationHandler extends BatchModeCommandHandler {

    protected final String commandName;
    protected final String type;
    protected final String idProperty;
    protected final OperationRequestAddress nodePath;
    protected final ArgumentWithValue profile;
    protected final ArgumentWithValue name;
    protected final ArgumentWithValue operation;

    protected final List<String> excludeOps;

    // help arguments
    protected final ArgumentWithoutValue helpProperties;
    protected final ArgumentWithoutValue helpCommands;

    protected final CommandLineCompleter genericCompleter;

    public GenericTypeOperationHandler(String nodeType, String idProperty) {
        this(nodeType, idProperty, Arrays.asList("read-attribute", "read-children-names", "read-children-resources",
                "read-children-types", "read-operation-description", "read-operation-names", "read-resource",
                "read-resource-description", "validate-address", "write-attribute"));
    }

    public GenericTypeOperationHandler(String nodeType, String idProperty, List<String> excludeOperations) {

        super("generic-type-operation", true);

        helpArg.setExclusive(false);
        nodePath = new DefaultOperationRequestAddress();
        OperationRequestParser.CallbackHandler handler = new DefaultOperationCallbackHandler(nodePath);
        try {
            DefaultOperationRequestParser.INSTANCE.parse(nodeType, handler);
        } catch (CommandFormatException e) {
            throw new IllegalArgumentException("Failed to parse nodeType: " + e.getMessage());
        }

        if(!nodePath.endsOnType()) {
            throw new IllegalArgumentException("The node path doesn't end on a type: '" + nodeType + "'");
        }
        this.type = nodePath.getNodeType();
        nodePath.toParentNode();
        addRequiredPath(nodePath);
        this.commandName = type;
        this.idProperty = idProperty;

        this.excludeOps = excludeOperations;

        profile = new ArgumentWithValue(this, new DefaultCompleter(new CandidatesProvider(){
            @Override
            public List<String> getAllCandidates(CommandContext ctx) {
                return Util.getNodeNames(ctx.getModelControllerClient(), null, "profile");
            }}), "--profile") {
            @Override
            public boolean canAppearNext(CommandContext ctx) throws CommandFormatException {
                if(!ctx.isDomainMode()) {
                    return false;
                }
                return super.canAppearNext(ctx);
            }
        };
        profile.addCantAppearAfter(helpArg);

        operation = new ArgumentWithValue(this, new DefaultCompleter(new CandidatesProvider(){
                @Override
                public List<String> getAllCandidates(CommandContext ctx) {

                    final boolean writeAttribute;
                    try {
                        writeAttribute = name.isPresent(ctx.getParsedArguments());
                    } catch (CommandFormatException e) {
                        return Collections.emptyList();
                    }

                    if(writeAttribute) {
                        Set<String> specified;
                        try {
                            specified = ctx.getParsedArguments().getArgumentNames();
                        } catch (CommandFormatException e) {
                            return Collections.emptyList();
                        }
                        final List<String> theProps = new ArrayList<String>();
                        for(Property prop : getNodeProperties(ctx)) {
                            final String propName = "--" + prop.getName();
                            if(!specified.contains(propName) && prop.getValue().has("access-type") &&
                                    prop.getValue().get("access-type").asString().contains("write")) {
                                theProps.add(propName + "=");
                            }
                        }
                        return theProps;
                    }

                    DefaultOperationRequestAddress address = new DefaultOperationRequestAddress();
                    if(ctx.isDomainMode()) {
                        final String profileName = profile.getValue(ctx.getParsedArguments());
                        if(profile == null) {
                            return Collections.emptyList();
                        }
                        address.toNode("profile", profileName);
                    }

                    for(OperationRequestAddress.Node node : nodePath) {
                        address.toNode(node.getType(), node.getName());
                    }
                    address.toNode(type, "?");
                    List<String> ops = ctx.getOperationCandidatesProvider().getOperationNames(address);
                    ops.removeAll(excludeOps);
                    return ops;
                }}), 0, "--operation") {
            @Override
            public boolean canAppearNext(CommandContext ctx) throws CommandFormatException {
                if(ctx.isDomainMode() && !profile.isPresent(ctx.getParsedArguments())) {
                    return false;
                }
                return super.canAppearNext(ctx);
            }
        };
        operation.addCantAppearAfter(helpArg);

        name = new ArgumentWithValue(this, new DefaultCompleter(new DefaultCompleter.CandidatesProvider() {
            @Override
            public List<String> getAllCandidates(CommandContext ctx) {
                ModelControllerClient client = ctx.getModelControllerClient();
                if (client == null) {
                    return Collections.emptyList();
                    }

                DefaultOperationRequestAddress address = new DefaultOperationRequestAddress();
                if(ctx.isDomainMode()) {
                    final String profileName = profile.getValue(ctx.getParsedArguments());
                    if(profile == null) {
                        return Collections.emptyList();
                    }
                    address.toNode("profile", profileName);
                }

                for(OperationRequestAddress.Node node : nodePath) {
                    address.toNode(node.getType(), node.getName());
                }

                return Util.getNodeNames(ctx.getModelControllerClient(), address, type);
                }
            }), "--" + idProperty) {
            @Override
            public boolean canAppearNext(CommandContext ctx) throws CommandFormatException {
                if(ctx.isDomainMode() && !profile.isPresent(ctx.getParsedArguments())) {
                    return false;
                }
                return super.canAppearNext(ctx);
            }
        };
        name.addCantAppearAfter(helpArg);

        helpArg.addCantAppearAfter(name);

        helpProperties = new ArgumentWithoutValue(this, "--properties");
        helpProperties.addRequiredPreceding(helpArg);
        helpProperties.addCantAppearAfter(operation);

        helpCommands = new ArgumentWithoutValue(this, "--commands");
        helpCommands.addRequiredPreceding(helpArg);
        helpCommands.addCantAppearAfter(operation);
        helpCommands.addCantAppearAfter(helpProperties);
        helpProperties.addCantAppearAfter(helpCommands);


        ///

        genericCompleter = new BaseArgumentTabCompleter(){
            private final List<CommandArgument> staticArgs = new ArrayList<CommandArgument>();
            {
                staticArgs.add(helpArg);
                staticArgs.add(helpCommands);
                staticArgs.add(helpProperties);
                staticArgs.add(profile);
                staticArgs.add(name);
                staticArgs.add(operation);
            }

            private List<CommandArgument> nodeProps;
            private Map<String, List<CommandArgument>> propsByOp;

            @Override
            protected Iterable<CommandArgument> getAllArguments(CommandContext ctx) {

                ParsedArguments args = ctx.getParsedArguments();

                final String theName = name.getValue(args);
                if(theName == null) {
                    return staticArgs;
                }

                final String op = operation.getValue(args);
                if(op == null) {
                    // list node properties
                    if(nodeProps == null) {
                        nodeProps = new ArrayList<CommandArgument>();
                        for(Property prop : getNodeProperties(ctx)) {
                            final ModelNode propDescr = prop.getValue();
                            if(propDescr.has("access-type") && "read-write".equals(propDescr.get("access-type").asString())) {
                                nodeProps.add(new ArgumentWithValue(GenericTypeOperationHandler.this, "--" + prop.getName()));
                            }
                        }
                    }
                    return nodeProps;
                } else {
                    // list operation properties
                    if(propsByOp == null) {
                        propsByOp = new HashMap<String, List<CommandArgument>>();
                    }
                    List<CommandArgument> opProps = propsByOp.get(op);
                    if(opProps == null) {
                        final ModelNode descr;
                        try {
                            descr = getOperationDescription(ctx, op);
                        } catch (IOException e1) {
                            return Collections.emptyList();
                        }

                        if(descr == null || !descr.has("request-properties")) {
                            opProps = Collections.emptyList();
                        } else {
                            opProps = new ArrayList<CommandArgument>();
                            for (Property prop : descr.get("request-properties").asPropertyList()) {
                                opProps.add(new ArgumentWithValue(GenericTypeOperationHandler.this, "--" + prop.getName()));
                            }
                        }
                        propsByOp.put(op, opProps);
                    }
                    return opProps;
                }
            }};
    }

    @Override
    public boolean hasArgument(String name) {
        return true;
    }

    @Override
    public boolean hasArgument(int index) {
        return true;
    }

    @Override
    public CommandLineCompleter getArgumentCompleter() {
        return genericCompleter;
    }

    protected BaseArgumentTabCompleter initArgumentCompleter() {
        return null;
    }

    public void addArgument(CommandArgument arg) {
    }

    @Override
    public ModelNode buildRequest(CommandContext ctx) throws CommandFormatException {
        final String operation = this.operation.getValue(ctx.getParsedArguments());
        if(operation == null) {
            return buildWritePropertyRequest(ctx);
        }
        return buildOperationRequest(ctx, operation);
    }

    protected ModelNode buildWritePropertyRequest(CommandContext ctx) throws CommandFormatException {

        final String name = this.name.getValue(ctx.getParsedArguments(), true);

        ModelNode composite = new ModelNode();
        composite.get("operation").set("composite");
        composite.get("address").setEmptyList();
        ModelNode steps = composite.get("steps");

        ParsedArguments args = ctx.getParsedArguments();

        final String profile;
        if(ctx.isDomainMode()) {
            profile = this.profile.getValue(args);
            if(profile == null) {
                throw new OperationFormatException("--profile argument value is missing.");
            }
        } else {
            profile = null;
        }

        for(String argName : args.getArgumentNames()) {
            if(argName.equals("--profile") || this.name.getFullName().equals(argName)) {
                continue;
            }

            final String valueString = args.getArgument(argName);
            if(valueString == null) {
                continue;
            }

            DefaultOperationRequestBuilder builder = new DefaultOperationRequestBuilder();
            if (profile != null) {
                builder.addNode("profile", profile);
            }

            for(OperationRequestAddress.Node node : nodePath) {
                builder.addNode(node.getType(), node.getName());
            }
            builder.addNode(type, name);
            builder.setOperationName("write-attribute");
            if(argName.charAt(1) == '-') {
                argName = argName.substring(2);
            } else {
                argName = argName.substring(1);
            }
            builder.addProperty("name", argName);

            // TODO this is just a guess and might not always work
            if(argName.endsWith("properties")) {

                ModelNode nodeValue = new ModelNode();
                String[] props = valueString.split(",");
                for(String prop : props) {
                    int equals = prop.indexOf('=');
                    if(equals == -1) {
                        throw new CommandFormatException("Property '" + prop + "' in '" + valueString + "' is missing the equals sign.");
                    }
                    String propName = prop.substring(0, equals);
                    if(propName.isEmpty()) {
                        throw new CommandFormatException("Property name is missing for '" + prop + "' in '" + valueString + "'");
                    }
                    nodeValue.add(propName, prop.substring(equals + 1));
                }
                builder.getModelNode().get("value").set(nodeValue);
            } else {
                builder.addProperty("value", valueString);
            }

            steps.add(builder.buildRequest());
        }

        return composite;
    }

    protected ModelNode buildOperationRequest(CommandContext ctx, final String operation) throws CommandFormatException {

        ParsedArguments args = ctx.getParsedArguments();

        DefaultOperationRequestBuilder builder = new DefaultOperationRequestBuilder();
        if(ctx.isDomainMode()) {
            final String profile = this.profile.getValue(args);
            if(profile == null) {
                throw new OperationFormatException("Required argument --profile is missing.");
            }
            builder.addNode("profile", profile);
        }

        final String name = this.name.getValue(ctx.getParsedArguments(), true);

        for(OperationRequestAddress.Node node : nodePath) {
            builder.addNode(node.getType(), node.getName());
        }
        builder.addNode(type, name);

        builder.setOperationName(operation);

        for(String argName : args.getArgumentNames()) {
            if(argName.equals("--profile")) {
                continue;
            }

            final String valueString = args.getArgument(argName);
            if(valueString == null) {
                continue;
            }

            if(argName.charAt(1) == '-') {
                argName = argName.substring(2);
            } else {
                argName = argName.substring(1);
            }

            // TODO this is just a guess and might not always work
            if(argName.endsWith("properties")) {

                ModelNode nodeValue = new ModelNode();
                String[] props = valueString.split(",");
                for(String prop : props) {
                    int equals = prop.indexOf('=');
                    if(equals == -1) {
                        throw new CommandFormatException("Property '" + prop + "' in '" + valueString + "' is missing the equals sign.");
                    }
                    String propName = prop.substring(0, equals);
                    if(propName.isEmpty()) {
                        throw new CommandFormatException("Property name is missing for '" + prop + "' in '" + valueString + "'");
                    }
                    nodeValue.add(propName, prop.substring(equals + 1));
                }
                builder.getModelNode().get(argName).set(nodeValue);
            } else {
                builder.addProperty(argName, valueString);
            }
        }

        return builder.buildRequest();
    }

    protected void printHelp(CommandContext ctx) {

        ParsedArguments args = ctx.getParsedArguments();
        try {
            if(helpProperties.isPresent(args)) {
                printAttributes(ctx);
                return;
            }
        } catch (CommandFormatException e) {
            ctx.printLine(e.getLocalizedMessage());
            return;
        }

        try {
            if(helpCommands.isPresent(args)) {
                printCommands(ctx);
                return;
            }
        } catch (CommandFormatException e) {
            ctx.printLine(e.getLocalizedMessage());
            return;
        }

        final String operationName = operation.getValue(args);
        if(operationName == null) {
            printNodeDescription(ctx);
            return;
        }

        try {
            ModelNode result = getOperationDescription(ctx, operationName);
            if(!result.hasDefined("description")) {
                ctx.printLine("Operation description is not available.");
                return;
            }

            final StringBuilder buf = new StringBuilder();
            buf.append("Operation description:\n\n\t");
            buf.append(result.get("description").asString());
            buf.append("\n\nProperties:");
            ctx.printLine(buf.toString());

            boolean idPropListed = false;
            if(result.has("request-properties")) {
                result = result.get("request-properties");
                for (Property attr : result.asPropertyList()) {
                    if(!idPropListed) {
                        idPropListed = idProperty.equals(attr.getName());
                    }
                    final ModelNode value = attr.getValue();

                    final boolean required = value.has("required") ? value.get("required").asBoolean() : false;

                    final String type = value.has("type") ? value.get("type").asString() : "no type info";

                    final StringBuilder descr = new StringBuilder();
                    descr.append("\n --");
                    descr.append(attr.getName());

                    final int length = descr.length();
                    int newLength = Math.max(24, ((length + 4) / 4) * 4);
                    descr.setLength(newLength);
                    for (int i = length; i < newLength; ++i) {
                        descr.setCharAt(i, ' ');
                    }

                    descr.append("- ");

                    if (value.has("description")) {
                        descr.append('(');
                        descr.append(type).append(',');
                        if (required) {
                            descr.append("required");
                        } else {
                            descr.append("optional");
                        }
                        descr.append(") ");
                        descr.append(value.get("description").asString());
                    } else {
                        descr.append("no description");
                    }
                    ctx.printLine(descr.toString());
                }
            }

            if(!idPropListed) {
                final StringBuilder descr = new StringBuilder();
                descr.append("\n --");
                descr.append(idProperty);

                final int length = descr.length();
                int newLength = Math.max(24, ((length + 4) / 4) * 4);
                descr.setLength(newLength);
                for (int i = length; i < newLength; ++i) {
                    descr.setCharAt(i, ' ');
                }

                descr.append("- identifies the instance to perform the operation on.");
                ctx.printLine(descr.toString());
            }
        } catch (Exception e) {
        }
    }

    protected void printNodeDescription(CommandContext ctx) {
        ModelNode request = initRequest(ctx);
        if(request == null) {
            return;
        }
        request.get("operation").set("read-resource-description");

        try {
            ModelNode result = ctx.getModelControllerClient().execute(request);
            if(!result.hasDefined("result")) {
                ctx.printLine("Node description is not available.");
                return;
            }
            result = result.get("result");
            if(!result.hasDefined("description")) {
                ctx.printLine("Node description is not available.");
                return;
            }
            ctx.printLine(result.get("description").asString());
        } catch (Exception e) {
        }
    }

    protected void printAttributes(CommandContext ctx) {

        final List<Property> props;
        try {
            props = getNodeProperties(ctx);
        } catch(Exception e) {
            ctx.printLine("Failed to obtain the list or properties: " + e.getLocalizedMessage());
            return;
        }

        for (Property attr : props) {
            final ModelNode value = attr.getValue();
            // filter metrics
            if (value.has("access-type") && "metric".equals(value.get("access-type").asString())) {
                continue;
            }

            final boolean required = value.has("required") ? value.get("required").asBoolean() : false;

            final StringBuilder descr = new StringBuilder();
            descr.append("\n ");
            descr.append(attr.getName());

            final int length = descr.length();
            int newLength = Math.max(24, ((length + 4) / 4) * 4);
            descr.setLength(newLength);
            for (int i = length; i < newLength; ++i) {
                descr.setCharAt(i, ' ');
            }

            descr.append("- ");

            if (value.has("description")) {
                descr.append('(');
                if (required) {
                    descr.append("required");
                } else {
                    descr.append("optional");
                }
                descr.append(") ");
                descr.append(value.get("description").asString());
            } else {
                descr.append("no description");
            }
            ctx.printLine(descr.toString());
        }
    }

    protected void printCommands(CommandContext ctx) {
        ModelNode request = initRequest(ctx);
        if(request == null) {
            return;
        }
        request.get("operation").set("read-operation-names");

        try {
            ModelNode result = ctx.getModelControllerClient().execute(request);
            if(!result.hasDefined("result")) {
                ctx.printLine("Operation names aren't available.");
                return;
            }
            final List<String> list = Util.getList(result);
            list.removeAll(this.excludeOps);
            list.add("To read the description of a specific command execute '" + this.commandName + " command_name --help'.");
            for(String name : list) {
                ctx.printLine(name);
            }
        } catch (Exception e) {
        }
    }

    protected List<Property> getNodeProperties(CommandContext ctx) {
        ModelNode request = initRequest(ctx);
        if(request == null) {
            return Collections.emptyList();
        }
        request.get("operation").set("read-resource-description");

        ModelNode result;
        try {
            result = ctx.getModelControllerClient().execute(request);
        } catch (IOException e) {
            return Collections.emptyList();
        }
        if(!result.hasDefined("result")) {
            return Collections.emptyList();
        }
        result = result.get("result");
        if(!result.hasDefined("attributes")) {
            return Collections.emptyList();
        }

        return result.get("attributes").asPropertyList();
    }

    protected ModelNode getOperationDescription(CommandContext ctx, String operationName) throws IOException {
        ModelNode request = initRequest(ctx);
        if(request == null) {
            return null;
        }
        request.get("operation").set("read-operation-description");
        request.get("name").set(operationName);

        ModelNode result = ctx.getModelControllerClient().execute(request);
        if (!result.hasDefined("result")) {
            return null;
        }
        return result.get("result");
    }

    protected ModelNode initRequest(CommandContext ctx) {
        ModelNode request = new ModelNode();
        ModelNode address = request.get("address");
        if(ctx.isDomainMode()) {
            final String profileName = profile.getValue(ctx.getParsedArguments());
            if(profile == null) {
                ctx.printLine("--profile argument is required to get the node description.");
                return null;
            }
            address.add("profile", profileName);
        }
        for(OperationRequestAddress.Node node : nodePath) {
            address.add(node.getType(), node.getName());
        }
        address.add(type, "?");
        return request;
    }
}
TOP

Related Classes of org.jboss.as.cli.handlers.GenericTypeOperationHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.