// JigKill.java
// $Id: JigKill.java,v 1.4 2000/08/16 21:37:33 ylafon Exp $
// (c) COPYRIGHT MIT, INRIA and Keio, 1999.
// Please first read the full copyright statement in file COPYRIGHT.html
package org.w3c.jigsaw.admin;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.Vector;
import org.w3c.www.http.HttpCredential;
import org.w3c.www.http.HttpFactory;
import org.w3c.tools.codec.Base64Encoder;
/**
* Simple class used to save and/or kill Jigsaw.
*
* <DL>
* <DT><B>Options:</B>
* <DD><CODE>-u username</CODE> User name (defaults to "admin")
* <DD><CODE>-p password</CODE> Password (required)
* <DD><CODE>--username username</CODE> Same as <CODE>-u</CODE>
* <DD><CODE>--password password</CODE> Same as <CODE>-p</CODE>
* <DD><CODE>--save</CODE> Save configuration of all servers</DD>
* <DD><CODE>--stop</CODE> Stop all servers</DD>
* <DD><CODE>--ping</CODE> check if servers are reachable</DL>
* (The last argument is assumed to be the URL to the Admin server,
* see Usage examples below...)
* <P>
* <DL>
* <DT><B>Example usage:</B>
* <DD>(be sure that jigsaw's <CODE>*.jar</CODE> file is in CLASSPATH,
* e.g. <CODE>export CLASSPATH=~/Jigsaw/classes/jigsaw.zip:
* ${CLASSPATH}</CODE>)</DD>
* <DL><DT>- Save and exit the server
* http://gyros.informatik.med.uni-giessen.de:
* <DD><CODE>java org.w3c.jigsaw.admin.JigKill -u admin -p for#8pj
* http://gyros.informatik.med.uni-giessen.de:8009/</CODE></DD>
*
* <DD>OR (using explicit options)</DD>
*
* <DD><CODE>java org.w3c.jigsaw.admin.JigKill -u admin -p for#8pj
* --save --stop http://gyros.informatik.med.uni-giessen.de:8009/</CODE></DL>
*
* <DL><DT>- Stop a server (as fast as possible, e.g. for system shutdown):
* <DD><CODE>java org.w3c.jigsaw.admin.JigKill -u admin -p for#8pj
* --stop http://gyros.informatik.med.uni-giessen.de:8009/</CODE></DL>
*
* <DL><DT>- Save the servers current configuration:
* <DD><CODE>java org.w3c.jigsaw.admin.JigKill -u admin -p for#8pj
* --save http://gyros.informatik.med.uni-giessen.de:8009/</CODE></DL>
*
* <DL><DT>- Check if a server is still alive:
* <DD><CODE>java org.w3c.jigsaw.admin.JigKill -u admin -p for#8pj
* --ping http://gyros.informatik.med.uni-giessen.de:8009/</CODE></DL></DL>
* <P>
* <DL>
* <DT><B>Changes from V1.1 to 1.2:</B>
* <DD>- Added <CODE>--stop</CODE> option: Simply stop jigsaw quick&savely.
* </DD>
* <DD>- Added <CODE>--save</CODE> option: Snapshot the current config
* (something for a daily crontab job).</DD>
* <DD>- Added <CODE>--ping</CODE> option to see if the server is still
* running (usefull for scripts).</DD>
* <DD>- Added <CODE>--username</CODE> and <CODE>--password</CODE> options
* as aliases for <CODE>-u</CODE> and <CODE>-p</CODE>.</DD></DL>
*
* <DD>- JigKill now returns 0 for success and non-0 for failure
* (of the requested operation) EVERYTIMES
* (except the JVM cores) to make script-processing as much as easy.</DD>
* <DD>- <CODE>-u</CODE> option now defaults to "admin", as jigsaw's
* default config does.</DD>
* <DD>- JigKill now saves all servers first before stopping them all
* (first backup, then destroy...).</DD></DL>
* <P>
* <DL>
* <DT><B>ToDo:</B>
* <DD>- Adding a <CODE>--restart</CODE> option.</DD></DL>
*
* @version $Revision: 1.4 $
* @author Beno�t Mah� (bmahe@w3.org)
* @author Roland Mainz (Roland.Mainz@informatik.med.uni-giessen.de)
*/
public class JigKill {
// the following variables are equivalents to ANSI-C's <stdlib.h> defines
/**
* Exit value of the JVM on success of the requested operation.
*/
final protected static int EXIT_SUCCESS = 0;
// JigKill has done it's operation successfull
/**
* Exit value of the JVM on failure of the requested operation.
*/
final protected static int EXIT_FAILURE = 1;
// JigKill failed to do it's work
/* object instance variables */
protected RemoteResource adminServer = null;
protected RemoteResource ctrls[] = null;
/**
* Print usage description and exit with exit status
* {@link #EXIT_FAILURE EXIT_FAILURE}
* @see #main(String[])
*/
protected static void usage() {
System.err.println( "Usage:\n" +
"\tjava org.w3c.jigsaw.admin.JigKill "+
"-u <username> -p <password> [--save] "+
"[--stop] [--ping] <admin server url>\n" );
System.exit( EXIT_FAILURE );
}
/**
* Get all the server's ControlResource.
* @param admin the admin server (a RemoteResource)
* @return an array of RemoteResource
* @exception RemoteAccessException if any remote error occurs.
*/
protected RemoteResource[] getControls( RemoteResource admin )
throws RemoteAccessException
{
String names[] = admin.enumerateResourceIdentifiers();
Vector vcontrols = new Vector( 2 );
for( int i = 0 ; i < names.length ; i++ )
{
if( (! names[ i ].equals( "control" )) &&
(! names[ i ].equals( "realms" )) )
{
RemoteResource srr = admin.loadResource( names[ i ] );
// load the control node
RemoteResource control = srr.loadResource( "control" );
vcontrols.addElement( control );
}
}
RemoteResource controls[] = new RemoteResource[ vcontrols.size() ];
vcontrols.copyInto( controls );
return controls;
}
/**
* Save the configuration of the servers and the admin server
* and then kill all servers (including the admin server).
* @exception RemoteAccessException if any remote error occurs.
* @see #save()
* @see #stop()
*/
public void kill()
throws RemoteAccessException
{
// first save all servers...
save();
// ...then stop/kill them all
stop();
}
/**
* Stop the servers and the admin server.
* @exception RemoteAccessException if any remote error occurs.
* @see #doLoadResource(String)
* @see #kill()
* @since JigKill 1.2
*/
public void stop()
throws RemoteAccessException
{
// stop all servers
doLoadResource( "stop" );
}
/**
* Save the configuration of the servers and the admin server.
* @exception RemoteAccessException if any remote error occurs.
* @see #doLoadResource(String)
* @see #kill()
* @since JigKill 1.2
*/
public void save()
throws RemoteAccessException
{
// save all servers
doLoadResource( "save" );
}
/**
* Send a "command" to all servers and the admin server.
* @param cmd name of the resource to load.
* @exception RemoteAccessException if any remote error occurs.
* @see #save()
* @see #stop()
* @since JigKill 1.2
*/
protected void doLoadResource( String cmd )
throws RemoteAccessException
{
// servers
for( int i = 0 ; i < ctrls.length ; i++ ) {
ctrls[ i ].loadResource( cmd );
}
// admin servers
RemoteResource ctrl = adminServer.loadResource( "control" );
ctrl.loadResource( cmd );
//done
}
/**
* Contructor.
* @param adminURL the admin server URL
* @param username the username
* @param password the password
*/
public JigKill( URL adminURL, String username, String password )
throws RemoteAccessException
{
AdminContext ctxt = new AdminContext( adminURL );
HttpCredential credential = HttpFactory.makeCredential( "Basic" );
Base64Encoder encoder = new Base64Encoder( username + ":" +
password );
credential.setAuthParameter( "cookie", encoder.processString() );
ctxt.setCredential( credential );
ctxt.initialize();
adminServer = ctxt.getAdminResource();
ctrls = getControls( adminServer );
}
/**
* Main program entry.
* This method exits the JVM with either
* {@link #EXIT_SUCCESS EXIT_SUCCESS} or
* {@link #EXIT_FAILURE EXIT_FAILURE} for the requested operation.
* @param args program arguments
* @see #usage()
*/
public static void main( String args[] ) {
// options
String username = "admin";
String password = null;
String url = null;
boolean doSave = false;
boolean doStop = false;
boolean doPing = false;
boolean doKill = true;
// not an option, but a flag:
// If none of the --save, --stop, --ping switches are given,
// kill the server (e.g. set --save, --stop options)
try {
for( int i = 0 ; i < args.length ; i++ )
{
if (args[i].equals("-u") || args[i].equals("--username"))
username = args[ ++i ];
else if (args[i].equals("-p") ||
args[i].equals("--password"))
password = args[ ++i ];
else if (args[i].equals("--save")) {
doSave = true;
doKill = false;
} else if (args[i].equals("--stop")) {
doStop = true;
doKill = false;
} else if (args[i].equals("--ping")) {
doPing = true;
doKill = false;
} else {
url = args[ i ];
}
}
} catch( ArrayIndexOutOfBoundsException exc ) {
// ignore this...
}
// check for required arguments...
if( (username == null) || (password == null) || (url == null) )
usage();
// the default action is (e.g. none of the --save,
// --stop, --ping option set is to KILL)
if( doKill ) {
doSave = doStop = true;
}
// process URL
URL adminURL = null;
try {
adminURL = new URL( url );
} catch( MalformedURLException ex ) {
System.err.println( "Invalid URL : " + url );
System.exit( EXIT_FAILURE );
}
// and now: EXECUTE !
try {
JigKill jigk = new JigKill( adminURL, username, password );
if( doPing ) {
System.out.println( "Servers are alive." );
}
if( doSave ) {
jigk.save();
System.out.println( "Servers saved." );
}
if( doStop ) {
jigk.stop();
System.out.println( "Servers killed." );
}
// success :-)
System.exit( EXIT_SUCCESS );
} catch( RemoteAccessException ex ) {
// catch RemoteAccessException (problems lile wrong login,
//server not found etc.)
String msg = ex.getMessage();
if( msg.equals( "Unauthorized" ) )
System.err.println( "Invalid username/password." );
else
System.err.println( "Error : " + msg );
System.exit( EXIT_FAILURE );
} catch( Exception exc ) {
// catch ANY other exception which may occur...
System.err.println( "Unexcepted fatal error:" );
exc.printStackTrace();
}
// for all cases (except the only one above) return
// failure for usage by the underlying scripts
System.exit( EXIT_FAILURE );
}
}