001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss;
023:
024: import java.lang.reflect.InvocationHandler;
025: import java.lang.reflect.Method;
026: import java.lang.reflect.Proxy;
027: import java.lang.reflect.UndeclaredThrowableException;
028: import java.util.Hashtable;
029: import java.util.ArrayList;
030: import java.io.BufferedReader;
031: import java.io.InputStreamReader;
032: import javax.management.MBeanServerConnection;
033: import javax.management.ObjectName;
034: import javax.naming.Context;
035: import javax.naming.InitialContext;
036:
037: import gnu.getopt.Getopt;
038: import gnu.getopt.LongOpt;
039:
040: import org.jboss.system.server.Server;
041: import org.jboss.system.server.ServerImplMBean;
042: import org.jboss.security.SecurityAssociation;
043: import org.jboss.security.SimplePrincipal;
044: import org.jnp.interfaces.NamingContext;
045:
046: /**
047: * A JMX client that uses an MBeanServerConnection to shutdown a remote JBoss
048: * server.
049: *
050: * @version <tt>$Revision: 57209 $</tt>
051: * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
052: * @author Scott.Stark@jboss.org
053: */
054: public class Shutdown {
055: /////////////////////////////////////////////////////////////////////////
056: // Command Line Support //
057: /////////////////////////////////////////////////////////////////////////
058:
059: public static final String PROGRAM_NAME = System.getProperty(
060: "program.name", "shutdown");
061:
062: protected static void displayUsage() {
063: System.out
064: .println("A JMX client to shutdown (exit or halt) a remote JBoss server.");
065: System.out.println();
066: System.out.println("usage: " + PROGRAM_NAME
067: + " [options] <operation>");
068: System.out.println();
069: System.out.println("options:");
070: System.out
071: .println(" -h, --help Show this help message (default)");
072: System.out
073: .println(" -D<name>[=<value>] Set a system property");
074: System.out
075: .println(" -- Stop processing options");
076: System.out
077: .println(" -s, --server=<url> Specify the JNDI URL of the remote server");
078: System.out
079: .println(" -n, --serverName=<url> Specify the JMX name of the ServerImpl");
080: System.out
081: .println(" -a, --adapter=<name> Specify JNDI name of the MBeanServerConnection to use");
082: System.out
083: .println(" -u, --user=<name> Specify the username for authentication");
084: System.out
085: .println(" -p, --password=<name> Specify the password for authentication");
086: System.out.println();
087: System.out.println("operations:");
088: System.out
089: .println(" -S, --shutdown Shutdown the server");
090: System.out
091: .println(" -e, --exit=<code> Force the VM to exit with a status code");
092: System.out
093: .println(" -H, --halt=<code> Force the VM to halt with a status code");
094: System.out.println();
095: }
096:
097: public static void main(final String[] args) throws Exception {
098: if (args.length == 0) {
099: displayUsage();
100: System.exit(0);
101: }
102:
103: String sopts = "-:hD:s:n:a:u:p:Se:H:";
104: LongOpt[] lopts = {
105: new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h'),
106: new LongOpt("server", LongOpt.REQUIRED_ARGUMENT, null,
107: 's'),
108: new LongOpt("adapter", LongOpt.REQUIRED_ARGUMENT, null,
109: 'a'),
110: new LongOpt("serverName", LongOpt.REQUIRED_ARGUMENT,
111: null, 'n'),
112: new LongOpt("shutdown", LongOpt.NO_ARGUMENT, null, 'S'),
113: new LongOpt("exit", LongOpt.REQUIRED_ARGUMENT, null,
114: 'e'),
115: new LongOpt("halt", LongOpt.REQUIRED_ARGUMENT, null,
116: 'H'),
117: new LongOpt("user", LongOpt.REQUIRED_ARGUMENT, null,
118: 'u'),
119: new LongOpt("password", LongOpt.REQUIRED_ARGUMENT,
120: null, 'p'), };
121:
122: Getopt getopt = new Getopt(PROGRAM_NAME, args, sopts, lopts);
123: int code;
124: String arg;
125:
126: String serverURL = null;
127: String adapterName = "jmx/rmi/RMIAdaptor";
128: String username = null;
129: String password = null;
130: ObjectName serverJMXName = ServerImplMBean.OBJECT_NAME;
131: boolean exit = false;
132: boolean halt = false;
133: int exitcode = -1;
134:
135: while ((code = getopt.getopt()) != -1) {
136: switch (code) {
137: case ':':
138: case '?':
139: // for now both of these should exit with error status
140: System.exit(1);
141: break;
142:
143: case 1:
144: // this will catch non-option arguments
145: // (which we don't currently care about)
146: System.err.println(PROGRAM_NAME
147: + ": unused non-option argument: "
148: + getopt.getOptarg());
149: break;
150: case 'h':
151: displayUsage();
152: System.exit(0);
153: break;
154: case 'D': {
155: // set a system property
156: arg = getopt.getOptarg();
157: String name, value;
158: int i = arg.indexOf("=");
159: if (i == -1) {
160: name = arg;
161: value = "true";
162: } else {
163: name = arg.substring(0, i);
164: value = arg.substring(i + 1, arg.length());
165: }
166: System.setProperty(name, value);
167: break;
168: }
169: case 's':
170: serverURL = getopt.getOptarg();
171: break;
172: case 'n':
173: serverJMXName = new ObjectName(getopt.getOptarg());
174: break;
175: case 'S':
176: // nothing...
177: break;
178: case 'a':
179: adapterName = getopt.getOptarg();
180: break;
181: case 'u':
182: username = getopt.getOptarg();
183: SecurityAssociation.setPrincipal(new SimplePrincipal(
184: username));
185: break;
186: case 'p':
187: password = getopt.getOptarg();
188: SecurityAssociation.setCredential(password);
189: break;
190: case 'e':
191: exitcode = Integer.parseInt(getopt.getOptarg());
192: exit = true;
193: break;
194: case 'H':
195: exitcode = Integer.parseInt(getopt.getOptarg());
196: halt = true;
197: break;
198: }
199: }
200:
201: InitialContext ctx;
202:
203: // If there was a username specified, but no password prompt for it
204: if (username != null && password == null) {
205: System.out.print("Enter password for " + username + ": ");
206: BufferedReader br = new BufferedReader(
207: new InputStreamReader(System.in));
208: password = br.readLine();
209: SecurityAssociation.setCredential(password);
210: }
211:
212: if (serverURL == null) {
213: ctx = new InitialContext();
214: } else {
215: Hashtable env = new Hashtable();
216: env.put(Context.PROVIDER_URL, serverURL);
217: env.put(NamingContext.JNP_DISABLE_DISCOVERY, "true");
218: ctx = new InitialContext(env);
219: }
220:
221: Object obj = ctx.lookup(adapterName);
222: if (!(obj instanceof MBeanServerConnection)) {
223: throw new RuntimeException(
224: "Object not of type: MBeanServerConnection, but: "
225: + (obj == null ? "not found" : obj
226: .getClass().getName()));
227: }
228:
229: MBeanServerConnection adaptor = (MBeanServerConnection) obj;
230: ServerProxyHandler handler = new ServerProxyHandler(adaptor,
231: serverJMXName);
232: Class[] ifaces = { Server.class };
233: ClassLoader tcl = Thread.currentThread()
234: .getContextClassLoader();
235: Server server = (Server) Proxy.newProxyInstance(tcl, ifaces,
236: handler);
237:
238: if (exit) {
239: server.exit(exitcode);
240: } else if (halt) {
241: server.halt(exitcode);
242: } else {
243: server.shutdown();
244: }
245: System.out
246: .println("Shutdown message has been posted to the server.");
247: System.out
248: .println("Server shutdown may take a while - check logfiles for completion");
249: }
250:
251: private static class ServerProxyHandler implements
252: InvocationHandler {
253: ObjectName serverName;
254: MBeanServerConnection server;
255:
256: ServerProxyHandler(MBeanServerConnection server,
257: ObjectName serverName) {
258: this .server = server;
259: this .serverName = serverName;
260: }
261:
262: public Object invoke(Object proxy, Method method, Object[] args)
263: throws Throwable {
264: String methodName = method.getName();
265: Class[] sigTypes = method.getParameterTypes();
266: ArrayList sigStrings = new ArrayList();
267: for (int s = 0; s < sigTypes.length; s++)
268: sigStrings.add(sigTypes[s].getName());
269: String[] sig = new String[sigTypes.length];
270: sigStrings.toArray(sig);
271: Object value = null;
272: try {
273: value = server
274: .invoke(serverName, methodName, args, sig);
275: } catch (UndeclaredThrowableException e) {
276: System.out.println("getUndeclaredThrowable: "
277: + e.getUndeclaredThrowable());
278: throw e.getUndeclaredThrowable();
279: }
280: return value;
281: }
282: }
283: }
|