1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */
22 package org.jboss;
23
24 import java.lang.reflect.InvocationHandler;
25 import java.lang.reflect.Method;
26 import java.lang.reflect.Proxy;
27 import java.lang.reflect.UndeclaredThrowableException;
28 import java.util.Hashtable;
29 import java.util.ArrayList;
30 import java.io.BufferedReader;
31 import java.io.InputStreamReader;
32 import javax.management.MBeanServerConnection;
33 import javax.management.ObjectName;
34 import javax.naming.Context;
35 import javax.naming.InitialContext;
36
37
38 import gnu.getopt.Getopt;
39 import gnu.getopt.LongOpt;
40
41 import org.jboss.system.server.Server;
42 import org.jboss.system.server.ServerImplMBean;
43 import org.jboss.security.SecurityAssociation;
44 import org.jboss.security.SimplePrincipal;
45 import org.jnp.interfaces.NamingContext;
46
47 /**
48 * A JMX client that uses an MBeanServerConnection to shutdown a remote JBoss
49 * server.
50 *
51 * @version <tt>$Revision: 37459 $</tt>
52 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
53 * @author Scott.Stark@jboss.org
54 */
55 public class Shutdown
56 {
57 /////////////////////////////////////////////////////////////////////////
58 // Command Line Support //
59 /////////////////////////////////////////////////////////////////////////
60
61 public static final String PROGRAM_NAME = System.getProperty("program.name", "shutdown");
62
63 protected static void displayUsage()
64 {
65 System.out.println("A JMX client to shutdown (exit or halt) a remote JBoss server.");
66 System.out.println();
67 System.out.println("usage: " + PROGRAM_NAME + " [options] <operation>");
68 System.out.println();
69 System.out.println("options:");
70 System.out.println(" -h, --help Show this help message (default)");
71 System.out.println(" -D<name>[=<value>] Set a system property");
72 System.out.println(" -- Stop processing options");
73 System.out.println(" -s, --server=<url> Specify the JNDI URL of the remote server");
74 System.out.println(" -n, --serverName=<url> Specify the JMX name of the ServerImpl");
75 System.out.println(" -a, --adapter=<name> Specify JNDI name of the MBeanServerConnection to use");
76 System.out.println(" -u, --user=<name> Specify the username for authentication");
77 System.out.println(" -p, --password=<name> Specify the password for authentication");
78 System.out.println();
79 System.out.println("operations:");
80 System.out.println(" -S, --shutdown Shutdown the server");
81 System.out.println(" -e, --exit=<code> Force the VM to exit with a status code");
82 System.out.println(" -H, --halt=<code> Force the VM to halt with a status code");
83 System.out.println();
84 }
85
86 public static void main(final String[] args) throws Exception
87 {
88 if (args.length == 0)
89 {
90 displayUsage();
91 System.exit(0);
92 }
93
94 String sopts = "-:hD:s:n:a:u:p:Se:H:";
95 LongOpt[] lopts =
96 {
97 new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h'),
98 new LongOpt("server", LongOpt.REQUIRED_ARGUMENT, null, 's'),
99 new LongOpt("adapter", LongOpt.REQUIRED_ARGUMENT, null, 'a'),
100 new LongOpt("serverName", LongOpt.REQUIRED_ARGUMENT, null, 'n'),
101 new LongOpt("shutdown", LongOpt.NO_ARGUMENT, null, 'S'),
102 new LongOpt("exit", LongOpt.REQUIRED_ARGUMENT, null, 'e'),
103 new LongOpt("halt", LongOpt.REQUIRED_ARGUMENT, null, 'H'),
104 new LongOpt("user", LongOpt.REQUIRED_ARGUMENT, null, 'u'),
105 new LongOpt("password", LongOpt.REQUIRED_ARGUMENT, null, 'p'),
106 };
107
108 Getopt getopt = new Getopt(PROGRAM_NAME, args, sopts, lopts);
109 int code;
110 String arg;
111
112 String serverURL = null;
113 String adapterName = "jmx/rmi/RMIAdaptor";
114 String username = null;
115 String password = null;
116 ObjectName serverJMXName = ServerImplMBean.OBJECT_NAME;
117 boolean exit = false;
118 boolean halt = false;
119 int exitcode = -1;
120
121 while ((code = getopt.getopt()) != -1)
122 {
123 switch (code)
124 {
125 case ':':
126 case '?':
127 // for now both of these should exit with error status
128 System.exit(1);
129 break;
130
131 case 1:
132 // this will catch non-option arguments
133 // (which we don't currently care about)
134 System.err.println(PROGRAM_NAME + ": unused non-option argument: " +
135 getopt.getOptarg());
136 break;
137 case 'h':
138 displayUsage();
139 System.exit(0);
140 break;
141 case 'D':
142 {
143 // set a system property
144 arg = getopt.getOptarg();
145 String name, value;
146 int i = arg.indexOf("=");
147 if (i == -1)
148 {
149 name = arg;
150 value = "true";
151 }
152 else
153 {
154 name = arg.substring(0, i);
155 value = arg.substring(i + 1, arg.length());
156 }
157 System.setProperty(name, value);
158 break;
159 }
160 case 's':
161 serverURL = getopt.getOptarg();
162 break;
163 case 'n':
164 serverJMXName = new ObjectName(getopt.getOptarg());
165 break;
166 case 'S':
167 // nothing...
168 break;
169 case 'a':
170 adapterName = getopt.getOptarg();
171 break;
172 case 'u':
173 username = getopt.getOptarg();
174 SecurityAssociation.setPrincipal(new SimplePrincipal(username));
175 break;
176 case 'p':
177 password = getopt.getOptarg();
178 SecurityAssociation.setCredential(password);
179 break;
180 case 'e':
181 exitcode = Integer.parseInt(getopt.getOptarg());
182 exit = true;
183 break;
184 case 'H':
185 exitcode = Integer.parseInt(getopt.getOptarg());
186 halt = true;
187 break;
188 }
189 }
190
191 InitialContext ctx;
192
193 // If there was a username specified, but no password prompt for it
194 if( username != null && password == null )
195 {
196 System.out.print("Enter password for "+username+": ");
197 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
198 password = br.readLine();
199 SecurityAssociation.setCredential(password);
200 }
201
202 if (serverURL == null)
203 {
204 ctx = new InitialContext();
205 }
206 else
207 {
208 Hashtable env = new Hashtable();
209 env.put(Context.PROVIDER_URL, serverURL);
210 env.put(NamingContext.JNP_DISABLE_DISCOVERY, "true");
211 ctx = new InitialContext(env);
212 }
213
214 Object obj = ctx.lookup(adapterName);
215 if (!(obj instanceof MBeanServerConnection))
216 {
217 throw new RuntimeException("Object not of type: MBeanServerConnection, but: " +
218 (obj == null ? "not found" : obj.getClass().getName()));
219 }
220
221 MBeanServerConnection adaptor = (MBeanServerConnection) obj;
222 ServerProxyHandler handler = new ServerProxyHandler(adaptor, serverJMXName);
223 Class[] ifaces = {Server.class};
224 ClassLoader tcl = Thread.currentThread().getContextClassLoader();
225 Server server = (Server) Proxy.newProxyInstance(tcl, ifaces, handler);
226
227 if (exit)
228 {
229 server.exit(exitcode);
230 }
231 else if (halt)
232 {
233 server.halt(exitcode);
234 }
235 else
236 {
237 server.shutdown();
238 }
239 System.out.println("Shutdown message has been posted to the server.");
240 System.out.println("Server shutdown may take a while - check logfiles for completion");
241 }
242
243 private static class ServerProxyHandler implements InvocationHandler
244 {
245 ObjectName serverName;
246 MBeanServerConnection server;
247 ServerProxyHandler(MBeanServerConnection server, ObjectName serverName)
248 {
249 this.server = server;
250 this.serverName = serverName;
251 }
252
253 public Object invoke(Object proxy, Method method, Object[] args)
254 throws Throwable
255 {
256 String methodName = method.getName();
257 Class[] sigTypes = method.getParameterTypes();
258 ArrayList sigStrings = new ArrayList();
259 for(int s = 0; s < sigTypes.length; s ++)
260 sigStrings.add(sigTypes[s].getName());
261 String[] sig = new String[sigTypes.length];
262 sigStrings.toArray(sig);
263 Object value = null;
264 try
265 {
266 value = server.invoke(serverName, methodName, args, sig);
267 }
268 catch(UndeclaredThrowableException e)
269 {
270 System.out.println("getUndeclaredThrowable: "+e.getUndeclaredThrowable());
271 throw e.getUndeclaredThrowable();
272 }
273 return value;
274 }
275 }
276 }