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
019
020import java.util.Collection;
021import java.util.Iterator;
022import java.util.List;
023
024import javax.management.MBeanServerConnection;
025import javax.management.ObjectInstance;
026import javax.management.ObjectName;
027
028
029/**
030 * A StopGracefullyCommand
031 *
032 */
033public class StopGracefullyCommand extends ShutdownCommand {
034    
035    @Override
036    public String getName() {
037        return "stop-gracefully";
038    }
039
040    @Override
041    public String getOneLineDescription() {
042        return "Stops a running broker gracefully.";
043    }
044
045        protected String connectorName, queueName;
046        protected long timeout;
047        protected long pollInterval;
048        /**
049         * Constructor
050         */
051        public StopGracefullyCommand(){
052            super();
053            this.helpFile = new String[] {
054                "Task Usage: Main stopGracefully [stop-options] [broker-name1] [broker-name2] ...",
055                "Description: Stops a running broker if there is no pending messages in the queues. It first stops the connector for client connection, then check queuesize until it becomes 0 before stop the broker.",
056                "", 
057                "Stop Options:",
058                "    --connectorName <connectorName> connectorName to stop",
059                "    --queueName <queueName>         check the queuesize of the queueName for pending message",
060                "    --timeout <timeout>             periodically check the queuesize before the timeout expires",
061                "    --pollInterval <pollInterval>   the time interval it checks the queuesize",
062                "    --jmxurl <url>             Set the JMX URL to connect to.",
063                "    --jmxuser <user>           Set the JMX user used for authenticating.",
064                "    --jmxpassword <password>   Set the JMX password used for authenticating.",
065                "    --jmxlocal                 Use the local JMX server instead of a remote one.",
066                "    --localProcessId           Use the local process id to connect( ignore jmxurl, jmxuser, jmxpassword), need to be root to use this option",
067                "    --all                      Stop all brokers.",
068                "    --version                  Display the version information.",
069                "    -h,-?,--help               Display the stop broker help information.",
070                "",
071                "Broker Names:",
072                "    Name of the brokers that will be stopped.",
073                "    If omitted, it is assumed that there is only one broker running, and it will be stopped.",
074                "    Use -all to stop all running brokers.",
075                ""
076            };
077        }
078
079        /**
080         * Stops the list of brokers.
081         * 
082         * @param jmxConnection - connection to the mbean server
083         * @param brokerBeans - broker mbeans to stop @throws Exception
084         */
085        protected void stopBrokers(MBeanServerConnection jmxConnection, Collection brokerBeans) throws Exception {
086            ObjectName brokerObjName;
087            for (Iterator i = brokerBeans.iterator(); i.hasNext();) {
088                brokerObjName = ((ObjectInstance)i.next()).getObjectName();
089
090                String brokerName = brokerObjName.getKeyProperty("BrokerName");
091                context.print("Stopping broker: " + brokerName);
092
093                try {
094                    jmxConnection.invoke(brokerObjName, "stopGracefully", new Object[] {
095                       connectorName, queueName, timeout, pollInterval
096                    }, new String[] {
097                        "java.lang.String", "java.lang.String", "long", "long"
098                    });
099                    context.print("Succesfully stopped broker: " + brokerName);
100                } catch (Exception e) {
101                    if(!(e.getMessage().startsWith("Error unmarshaling return header"))){
102                        context.print("Exception:"+e.getMessage());
103                    }
104                }
105            }
106
107            closeJmxConnection();
108        }
109    /**
110     * @param token - option token to handle
111     * @param tokens - succeeding command arguments
112     * @throws Exception
113     */
114    protected void handleOption(String token, List<String> tokens) throws Exception {
115        // Try to handle the options first
116        if (token.equals("--connectorName")) {
117            if (tokens.isEmpty() || ((String)tokens.get(0)).startsWith("-")) {
118                context.printException(new IllegalArgumentException("connectorName not specified"));
119                return;
120            }
121
122            connectorName=(String)tokens.remove(0);
123        } else if (token.equals("--timeout")) {
124            if (tokens.isEmpty() || ((String)tokens.get(0)).startsWith("-")) {
125                context.printException(new IllegalArgumentException("timeout not specified"));
126                return;
127            }
128            timeout=Long.parseLong(tokens.remove(0));
129        } else if (token.equals("--pollInterval")) {
130            if (tokens.isEmpty() || ((String)tokens.get(0)).startsWith("-")) {
131                context.printException(new IllegalArgumentException("pollInterval not specified"));
132                return;
133            }
134            pollInterval=Long.parseLong(tokens.remove(0));
135        }else if(token.equals("--queueName")) {
136            if (tokens.isEmpty() || ((String)tokens.get(0)).startsWith("-")) {
137                context.printException(new IllegalArgumentException("queueName not specified"));
138                return;
139            }
140            queueName=(String)tokens.remove(0);
141        }else {
142            // Let the super class handle the option
143            super.handleOption(token, tokens);
144        }
145    }
146
147}