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}