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     */
017    package org.apache.activemq.console.command;
018    
019    
020    import java.util.Collection;
021    import java.util.Iterator;
022    import java.util.List;
023    
024    import javax.management.MBeanServerConnection;
025    import javax.management.ObjectInstance;
026    import javax.management.ObjectName;
027    
028    
029    /**
030     * A StopGracefullyCommand
031     *
032     */
033    public 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    }