Package org.apache.servicemix.kernel.gshell.core.config

Source Code of org.apache.servicemix.kernel.gshell.core.config.CommandParser$Builder

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.apache.servicemix.kernel.gshell.core.config;

import java.util.ArrayList;
import java.util.List;

import org.w3c.dom.Element;

import org.apache.geronimo.gshell.command.Alias;
import org.apache.geronimo.gshell.command.Link;
import org.apache.geronimo.gshell.wisdom.command.AliasImpl;
import org.apache.geronimo.gshell.wisdom.command.ConfigurableCommandCompleter;
import org.apache.geronimo.gshell.wisdom.command.LinkImpl;
import org.apache.geronimo.gshell.wisdom.registry.CommandLocationImpl;
import org.apache.servicemix.kernel.gshell.core.CommandBundle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;

public class CommandParser extends AbstractBeanDefinitionParser {

    public static final String ID = ID_ATTRIBUTE;

    public static final String DESCRIPTION = "description";

    public static final String PLUGIN_TEMPLATE = "pluginTemplate";

    public static final String ACTION = "action";

    public static final String ACTION_ID = "actionId";

    public static final String COMMAND_TEMPLATE_SUFFIX = "CommandTemplate";

    public static final String COMMAND_BUNDLE = "command-bundle";

    public static final String NAME = "name";

    public static final String LOCATION = "location";

    public static final String COMMANDS = "commands";

    public static final String COMMAND = "command";

    public static final String TYPE = "type";

    public static final String DOCUMENTER = "documenter";

    public static final String COMPLETER = "completer";

    public static final String COMPLETERS = "completers";

    public static final String BEAN = "bean";

    public static final String REF = "ref";

    public static final String NULL = "null";

    public static final String MESSAGE_SOURCE = "message-source";

    public static final String MESSAGES = "messages";

    public static final String PROTOTYPE = "prototype";

    public static final String ALIAS = "alias";

    public static final String ALIASES = "aliases";

    public static final String LINK = "link";

    public static final String LINKS = "links";

    public static final String TARGET = "target";

    @Override
    protected boolean shouldGenerateId() {
        return true;
    }

    @Override
    protected boolean shouldGenerateIdAsFallback() {
        return true;
    }

    protected AbstractBeanDefinition parseInternal(final Element element, final ParserContext context) {
        assert element != null;
        assert context != null;

        Builder builder = new Builder(context);
        BeanDefinitionBuilder plugin = builder.parseCommandBundle(element);
        return plugin.getBeanDefinition();
    }

    /**
     * Helper to deal with command type.
     */
    private enum CommandType
    {
        STATELESS,
        STATEFUL;

        public static CommandType parse(final String text) {
            assert text != null;

            return valueOf(text.toUpperCase());
        }

        public String getTemplateName() {
            return name().toLowerCase() + COMMAND_TEMPLATE_SUFFIX;
        }

        public void wire(final BeanDefinitionBuilder command, final BeanDefinitionHolder action) {
            assert command != null;
            assert action != null;

            switch (this) {
                case STATELESS:
                    command.addPropertyReference(ACTION, action.getBeanName());
                    break;

                case STATEFUL:
                    command.addPropertyValue(ACTION_ID, action.getBeanName());
                    break;
            }
        }
    }

    /**
     * Helper to build plugin related bean definitions.
     */
    private class Builder
    {
        private final Logger log = LoggerFactory.getLogger(getClass());

        private ParserContext context;

        public Builder(final ParserContext context) {
            assert context != null;

            this.context = context;
        }

        private String resolveId(final Element element, final BeanDefinition def) throws BeanDefinitionStoreException {
            assert element != null;
            assert def != null;

            if (shouldGenerateId()) {
                return context.getReaderContext().generateBeanName(def);
            }

            String id = element.getAttribute(ID_ATTRIBUTE);

            if (!StringUtils.hasText(id) && shouldGenerateIdAsFallback()) {
                id = context.getReaderContext().generateBeanName(def);
            }

            return id;
        }

        @SuppressWarnings({"unchecked"})
        private List<Element> getChildElements(final Element element, final String name) {
            assert element != null;
            assert name != null;

            return DomUtils.getChildElementsByTagName(element, name);
        }

        @SuppressWarnings({"unchecked"})
        private List<Element> getChildElements(final Element element, final String[] names) {
            assert element != null;
            assert names != null;

            return DomUtils.getChildElementsByTagName(element, names);
        }

        @SuppressWarnings({"unchecked"})
        private Element getChildElement(final Element element, final String name) {
            assert element != null;
            assert name != null;

            List<Element> elements = DomUtils.getChildElementsByTagName(element, name);
            if (elements != null && !elements.isEmpty()) {
                return elements.get(0);
            }
            return null;
        }

        private BeanDefinitionParserDelegate createBeanDefinitionParserDelegate(final Element element) {
            assert element != null;

            BeanDefinitionParserDelegate parser = new BeanDefinitionParserDelegate(context.getReaderContext());
            parser.initDefaults(element.getOwnerDocument().getDocumentElement());
            return parser;
        }

        private BeanDefinitionHolder parseBeanDefinitionElement(final Element element) {
            assert element != null;

            BeanDefinitionParserDelegate parser = createBeanDefinitionParserDelegate(element);
            return parser.parseBeanDefinitionElement(element);
        }

        private void parseAndApplyDescription(final Element element, final BeanDefinition def) {
            assert element != null;
            assert def != null;

            Element desc = getChildElement(element, DESCRIPTION);
            if (desc != null) {
                if (def instanceof AbstractBeanDefinition) {
                    ((AbstractBeanDefinition)def).setDescription(desc.getTextContent());
                }
            }
        }

        private void parseAndApplyDescription(final Element element, final BeanDefinitionBuilder builder) {
            assert element != null;
            assert builder != null;

            parseAndApplyDescription(element, builder.getRawBeanDefinition());
        }

        private BeanDefinitionHolder register(final BeanDefinitionHolder holder) {
            assert holder != null;

            registerBeanDefinition(holder, context.getRegistry());
            return holder;
        }

        private BeanDefinitionHolder register(final BeanDefinition def, final String id) {
            assert def != null;
            assert id != null;

            BeanDefinitionHolder holder = new BeanDefinitionHolder(def, id);
            return register(holder);
        }

        //
        // <gshell:command-bundle>
        //

        private BeanDefinitionBuilder parseCommandBundle(final Element element) {
            assert element != null;

            log.trace("Parse command bundle; element; {}", element);

            BeanDefinitionBuilder bundle = BeanDefinitionBuilder.rootBeanDefinition(CommandBundle.class);
            parseAndApplyDescription(element, bundle);

            //
            // TODO: Figure out how we can save the order of <gshell:command> and <gshell:link> so that 'help' displays them in the order they are defined
            //

            ManagedList commands = new ManagedList();
            commands.addAll(parseCommands(element));
            bundle.addPropertyValue(COMMANDS, commands);

            ManagedList links = new ManagedList();
            links.addAll(parseLinks(element));
            bundle.addPropertyValue(LINKS, links);

            ManagedList aliases = new ManagedList();
            aliases.addAll(parseAliases(element));
            bundle.addPropertyValue(ALIASES, aliases);

            return bundle;
        }

        //
        // <gshell:command>
        //

        private List<BeanDefinition> parseCommands(final Element element) {
            assert element != null;

            log.trace("Parse commands; element; {}", element);

            List<BeanDefinition> commands = new ArrayList<BeanDefinition>();

            List<Element> children = getChildElements(element, COMMAND);

            for (Element child : children) {
                BeanDefinitionBuilder command = parseCommand(child);
                commands.add(command.getBeanDefinition());
            }

            return commands;
        }

        private BeanDefinitionBuilder parseCommand(final Element element) {
            assert element != null;

            log.trace("Parse command; element; {}", element);

            CommandType type = CommandType.parse(element.getAttribute(TYPE));
            BeanDefinitionBuilder command = BeanDefinitionBuilder.childBeanDefinition(type.getTemplateName());
            parseAndApplyDescription(element, command);

            Element child;

            // Required children elements

            String name = element.getAttribute(NAME);
            BeanDefinition def = new GenericBeanDefinition();
            def.setBeanClassName(CommandLocationImpl.class.getName());
            def.getConstructorArgumentValues().addGenericArgumentValue(name);
            command.addPropertyValue(LOCATION, def);

            child = getChildElement(element, ACTION);
            BeanDefinitionHolder action = parseCommandAction(child);
            type.wire(command, action);

            // Optional children elements

            child = getChildElement(element, DOCUMENTER);
            if (child != null) {
                BeanDefinitionHolder holder = parseBeanDefinitionElement(child);
                command.addPropertyValue(DOCUMENTER, holder.getBeanDefinition());
            }

            child = getChildElement(element, COMPLETER);
            if (child != null) {
                BeanDefinitionHolder holder = parseBeanDefinitionElement(child);
                command.addPropertyValue(COMPLETER, holder.getBeanDefinition());
            }

            child = getChildElement(element, COMPLETERS);
            if (child != null) {
                BeanDefinitionBuilder completer = parseCommandCompleters(child);
                command.addPropertyValue(COMPLETER, completer.getBeanDefinition());
            }

            child = getChildElement(element, MESSAGE_SOURCE);
            if (child != null) {
                BeanDefinitionHolder holder = parseBeanDefinitionElement(child);
                command.addPropertyValue(MESSAGES, holder.getBeanDefinition());
            }

            //String id = resolveId(element, command.getBeanDefinition());
            //BeanDefinitionHolder holder = register(command.getBeanDefinition(), id);

            return command;
        }

        //
        // <gshell:completers>
        //

        private BeanDefinitionBuilder parseCommandCompleters(final Element element) {
            assert element != null;

            BeanDefinitionBuilder completer = BeanDefinitionBuilder.rootBeanDefinition(ConfigurableCommandCompleter.class);

            ManagedList completers = new ManagedList();

            List<Element> children = getChildElements(element, new String[] {BEAN, REF, NULL});

            for (Element child : children) {
                if (DomUtils.nodeNameEquals(child, BEAN)) {
                    BeanDefinitionHolder holder = parseBeanDefinitionElement(child);
                    // noinspection unchecked
                    completers.add(holder.getBeanDefinition());
                }
                else if (DomUtils.nodeNameEquals(child, REF)) {
                    BeanDefinitionParserDelegate parser = createBeanDefinitionParserDelegate(child);
                    RuntimeBeanReference ref = (RuntimeBeanReference) parser.parsePropertySubElement(child, completer.getRawBeanDefinition());
                    // noinspection unchecked
                    completers.add(ref);
                }
                else if (DomUtils.nodeNameEquals(child, NULL)) {
                    // noinspection unchecked
                    completers.add(null);
                }
            }

            completer.addConstructorArgValue(completers);

            return completer;
        }

        //
        // <gshell:action>
        //

        private BeanDefinitionHolder parseCommandAction(final Element element) {
            assert element != null;

            log.trace("Parse command action; element; {}", element);

            // Construct the action
            BeanDefinition action = parseBeanDefinitionElement(element).getBeanDefinition();

            // All actions are configured as prototypes
            action.setScope(PROTOTYPE);

            // Generate id and register the bean
            String id = resolveId(element, action);
            return register(action, id);
        }

        //
        // <gshell:link>
        //

        private List<Link> parseLinks(final Element element) {
            assert element != null;

            log.trace("Parse links; element; {}", element);

            List<Link> links = new ArrayList<Link>();

            List<Element> children = getChildElements(element, LINK);

            for (Element child : children) {
                String name = child.getAttribute(NAME);
                String target = child.getAttribute(TARGET);

                links.add(new LinkImpl(name, target));
            }

            return links;
        }

        //
        // <gshell:alias>
        //

        private List<Alias> parseAliases(final Element element) {
            assert element != null;

            log.trace("Parse aliases; element; {}", element);

            List<Alias> aliases = new ArrayList<Alias>();

            List<Element> children = getChildElements(element, ALIAS);

            for (Element child : children) {
                String name = child.getAttribute(NAME);
                String alias = child.getAttribute(ALIAS);

                aliases.add(new AliasImpl(name, alias));
            }

            return aliases;
        }
    }
}
TOP

Related Classes of org.apache.servicemix.kernel.gshell.core.config.CommandParser$Builder

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.