org.shaf.shell.Shell.java Source code

Java tutorial

Introduction

Here is the source code for org.shaf.shell.Shell.java

Source

/**
 * Copyright 2014-2015 SHAF-WORK
 * 
 * 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.shaf.shell;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.shaf.client.net.ClientException;
import org.shaf.core.event.EventListenerHandler;
import org.shaf.core.net.NetworkContentException;
import org.shaf.core.net.NetworkTransportException;
import org.shaf.core.util.Log;
import org.shaf.shell.action.Action;
import org.shaf.shell.action.ActionContext;
import org.shaf.shell.action.ActionRegister;
import org.shaf.shell.io.Terminal;

import com.google.common.base.Strings;

/**
 * The {@code Shell} provides handling of command line commands.
 * 
 * @author Mykola Galushka
 */
public class Shell extends EventListenerHandler implements Closeable {

    /**
     * Defines a logger.
     */
    private static final Log LOG = Log.forClass(Shell.class);

    /**
     * The actions register.
     */
    private final ActionRegister actions;

    /**
     * The system configuration.
     */
    private final Configuration config;

    /**
     * The shell terminal.
     */
    private final Terminal terminal;

    /**
     * Constructs a new {@code Shell} with specified output stream.
     * 
     * @param in
     *            the input stream associated with this shell.
     * @param out
     *            the output stream associated with this shell.
     */
    public Shell(final InputStream in, final OutputStream out) {
        super();

        this.actions = new ActionRegister();
        this.config = new PropertiesConfiguration();
        this.terminal = new Terminal(in, out);

        Runtime.getRuntime()
                .addShutdownHook(new Thread(new ShellShutdownHook(this.terminal), "shell-shutdown-hook"));

        String path = System.getProperty("shaf.configuration");
        try {
            if (path != null) {
                ((PropertiesConfiguration) config).load(path);
                LOG.info("Loaded Shell configuration: " + path);
            } else {
                LOG.warn("The Shell configuration file is not specified.");
            }
        } catch (ConfigurationException exc) {
            LOG.fatal("Failed to load Shell configuration: " + path, exc);
        }

    }

    /**
     * Constructs a new default {@code Shell}.
     */
    public Shell() {
        this(null, null);
    }

    /**
     * Shows the shell introduction message.
     */
    public final void intro() {
        this.terminal.print("  ___  _  _    _    ___   ___  _          _  _   ",
                " / __|| || |  /_\\  | __| / __|| |_   ___ | || | ",
                " \\__ \\| __ | / _ \\ | _|  \\__ \\| ' \\ / -_)| || | ",
                " |___/|_||_|/_/ \\_\\|_|   |___/|_||_|\\___||_||_| ", " wwww.shaf-work.org", "");

    }

    /**
     * Scans the console input and returns the shell request.
     * 
     * @return the shell request.
     */
    public final ShellRequest scan() {
        return ShellRequest.parse(this.terminal.scan("shaf> "));
    }

    /**
     * Handles the specified shell request.
     *
     * @param request
     *            the shell request.
     * @return {@code 0} if request executed successfully and {@code 1}
     *         otherwise.
     */
    public int handle(final ShellRequest request) {
        String cmd = Strings.isNullOrEmpty(request.getCommand()) ? "" : request.getCommand();
        String[] args = (request.getArguments() == null) ? new String[0] : request.getArguments();

        try {
            this.fireCommandStarted(request);

            /*
             * Creates an action instance based on the specified command and
             * initiates it execution.
             */
            if (this.actions.contains(cmd)) {

                LOG.debug("Executes '" + cmd + "' command.");

                Action action = this.actions.get(cmd).newInstance();

                try {
                    if (args.length == 1 && "-?".equals(args[0])) {
                        terminal.print(action.usage());

                        LOG.debug("Execution successful.");
                        return 0;
                    } else {
                        action.perform(new ActionContext(this.actions, this.config, this.terminal), args);

                        LOG.debug("Execution successful.");
                        return 0;
                    }
                } catch (IllegalArgumentException exc) {
                    terminal.print("Error:", "\tInvalid command arguments: " + exc.getMessage());
                    terminal.print(action.usage());
                }
            } else {
                terminal.println("Unknown command: " + cmd);
            }
        } catch (Throwable exc) {

            terminal.print("Execution failed: " + exc.getMessage(), "",
                    "NOTE: To see the full information about occured error, please, check the ", "      Shell log.",
                    "");

            LOG.fatal("Execution failed.", exc);

            if (exc instanceof ClientException) {
                if (exc.getCause() instanceof NetworkContentException) {
                    LOG.fatal("The faulty content: " + ((NetworkContentException) exc.getCause()).getContent());
                } else if (exc.getCause() instanceof NetworkTransportException) {
                    LOG.fatal(
                            "The faulty transport: " + ((NetworkTransportException) exc.getCause()).getTransport());
                }
            }
        } finally {
            fireCommandFinished(request);
        }

        return 1;
    }

    /**
     * Closes the {@code Shell} object.
     */
    @Override
    public void close() throws IOException {
        if (this.terminal != null) {
            this.terminal.close();
        }
    }

    /**
     * Fires the {@link ShellListener#shellCommandStarted(ShellEvent)} action.
     * 
     * @param request
     *            the shell request.
     */
    private void fireCommandStarted(final ShellRequest request) {
        if (this.listeners != null) {
            for (ShellListener listener : super.getEventListeners(ShellListener.class)) {
                listener.commandStarted(new ShellEvent(this, request));
            }
        }
    }

    /**
     * Fires the {@link ShellListener#shellCommandFinished(ShellEvent)} action.
     * 
     * @param request
     *            the shell request.
     */
    private void fireCommandFinished(final ShellRequest request) {
        if (this.listeners != null) {
            for (ShellListener listener : super.getEventListeners(ShellListener.class)) {
                listener.commandFinished(new ShellEvent(this, request));
            }
        }
    }
}