001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.activemq.console.command;
018
019import java.io.BufferedReader;
020import java.io.IOException;
021import java.io.InputStream;
022import java.io.InputStreamReader;
023import java.net.ConnectException;
024import java.util.List;
025
026import org.apache.activemq.ActiveMQConnectionMetaData;
027import org.apache.activemq.console.CommandContext;
028import org.apache.activemq.util.IntrospectionSupport;
029
030public abstract class AbstractCommand implements Command {
031    public static final String COMMAND_OPTION_DELIMETER = ",";
032
033    private boolean isPrintHelp;
034    private boolean isPrintVersion;
035
036    protected CommandContext context;
037
038    public void setCommandContext(CommandContext context) {
039        this.context = context;
040    }
041    
042    /**
043     * Execute a generic command, which includes parsing the options for the
044     * command and running the specific task.
045     * 
046     * @param tokens - command arguments
047     * @throws Exception
048     */
049    public void execute(List<String> tokens) throws Exception {
050        // Parse the options specified by "-"
051        parseOptions(tokens);
052
053        // Print the help file of the task
054        if (isPrintHelp) {
055            printHelp();
056
057            // Print the AMQ version
058        } else if (isPrintVersion) {
059            context.printVersion(ActiveMQConnectionMetaData.PROVIDER_VERSION);
060
061            // Run the specified task
062        } else {
063            runTask(tokens);
064        }
065    }
066
067    /**
068     * Parse any option parameters in the command arguments specified by a '-'
069     * as the first character of the token.
070     * 
071     * @param tokens - command arguments
072     * @throws Exception
073     */
074    protected void parseOptions(List<String> tokens) throws Exception {
075        while (!tokens.isEmpty()) {
076            String token = tokens.remove(0);
077            if (token.startsWith("-")) {
078                // Token is an option
079                handleOption(token, tokens);
080            } else {
081                // Push back to list of tokens
082                tokens.add(0, token);
083                return;
084            }
085        }
086    }
087
088    /**
089     * Handle the general options for each command, which includes -h, -?,
090     * --help, -D, --version.
091     * 
092     * @param token - option token to handle
093     * @param tokens - succeeding command arguments
094     * @throws Exception
095     */
096    protected void handleOption(String token, List<String> tokens) throws Exception {
097        isPrintHelp = false;
098        isPrintVersion = false;
099        // If token is a help option
100        if (token.equals("-h") || token.equals("-?") || token.equals("--help")) {
101            isPrintHelp = true;
102            tokens.clear();
103
104            // If token is a version option
105        } else if (token.equals("--version")) {
106            isPrintVersion = true;
107            tokens.clear();
108        } else if (token.startsWith("-D")) {
109            // If token is a system property define option
110            String key = token.substring(2);
111            String value = "";
112            int pos = key.indexOf("=");
113            if (pos >= 0) {
114                value = key.substring(pos + 1);
115                key = key.substring(0, pos);
116            }
117            System.setProperty(key, value);
118        } else {
119            if (token.startsWith("--")) {
120                String prop = token.substring(2);
121                if (tokens.isEmpty() || tokens.get(0).startsWith("-")) {
122                    context.print("Property '" + prop + "' is not specified!");
123                } else if (IntrospectionSupport.setProperty(this, prop, tokens.remove(0))) {
124                    return;
125                }
126            }
127            // Token is unrecognized
128            context.printInfo("Unrecognized option: " + token);
129            isPrintHelp = true;
130        }
131    }
132
133    /**
134     * Run the specific task.
135     * 
136     * @param tokens - command arguments
137     * @throws Exception
138     */
139    protected abstract void runTask(List<String> tokens) throws Exception;
140
141    /**
142     * Print the help messages for the specific task
143     */
144    protected abstract void printHelp();
145
146    protected void printHelpFromFile() {
147        BufferedReader reader = null;
148        try {
149            InputStream is = getClass().getResourceAsStream(getName() + ".txt");
150            reader = new BufferedReader(new InputStreamReader(is));
151            String line;
152            while ((line = reader.readLine()) != null) {
153                context.print(line);
154            }
155        } catch (Exception e) {} finally {
156            if (reader != null) {
157                try {
158                    reader.close();
159                } catch (IOException e) {}
160            }
161        }
162    }
163
164    protected void handleException(Exception exception, String serviceUrl) throws Exception {
165        Throwable cause = exception.getCause();
166        while (true) {
167            Throwable next = cause.getCause();
168            if (next == null) {
169                break;
170            }
171            cause = next;
172        }
173        if (cause instanceof ConnectException) {
174            context.printInfo("Broker not available at: " + serviceUrl);
175        } else {
176            context.printInfo("Failed to execute " + getName() + " task.");
177            throw exception;
178        }
179    }
180}