/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.cache.interop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.PropertyConfigurator;
import org.jboss.cache.TreeCache;
import org.jboss.cache.TreeCacheMBean;
import java.io.BufferedInputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Starts a JBossCache instance and then listens on a socket for
* a call from {@link Shutdown}.
*
* @author Brian Stansberry
* @version $Revision$
*/
public class Main
{
private static final Log log = LogFactory.getLog(Main.class);
private static final String SHUTDOWN = "SHUTDOWN";
private String configFile_;
private int listenerPort_ = 11111;
private String bindAddressString_;
private ServerSocket srvSock_;
private TreeCacheMBean cache_;
private Thread listenerThread_;
private boolean stopped;
/**
*
* @param args
*/
public static void main(final String[] args)
{
try
{
// Runnable worker = new Runnable() {
// public void run()
// {
// try
// {
Main main = new Main();
main.start(args);
// }
// catch (Throwable t)
// {
// log.fatal("Failed to boot JBossCache", t);
// }
// }
//
// };
//
// ThreadGroup threads = new ThreadGroup("jbosscache");
// new Thread(threads, worker, "main").start();
log.info("Started");
}
catch (Throwable t)
{
log.fatal("Failed to boot JBossCache", t);
}
}
/**
* Create a new Main.
*
*/
public Main()
{
super();
}
public void start(final String[] args) throws Exception
{
// First process the command line to pickup custom props/settings
processCommandLine(args);
Runtime.getRuntime().addShutdownHook(new ShutdownHook());
try
{
startCache();
startListener();
}
catch (Exception e)
{
stopCache();
throw e;
}
}
public void shutdown()
{
stopCache();
stopListener();
}
private void processCommandLine(final String[] args)
{
if (args == null || args.length == 0 || args[0] == null)
{
usage();
return;
}
configFile_ = args[0];
if (args.length > 1)
{
listenerPort_ = Integer.parseInt(args[1]);
if (args.length > 2)
bindAddressString_ = args[2];
}
}
private void usage()
{
System.out.println("Usage:");
System.out.println("java -cp $CLASSPATH org.jboss.cache.misc.Main configURL [bindAddress] [port]");
System.out.println();
System.out.println("Arguments");
System.out.println("---------");
System.out.println();
System.out.println("configFile Location of a JBossCache configuration descriptor file.");
System.out.println(" Can be a classpath resource or a location in the file system.");
System.out.println();
System.out.println("port Port on which we should listen for shutdown commands (Optional).");
System.out.println(" Default is 11111");
System.out.println();
System.out.println("bindAddress IP address on which the socket that listens for shutdown");
System.out.println(" commands should bind (Optional)");
System.out.println(" Default is to bind to all addresses");
}
private void startCache() throws Exception
{
if (cache_ == null)
{
cache_ = new TreeCache();
PropertyConfigurator config = new PropertyConfigurator();
config.configure(cache_, configFile_);
cache_.create();
cache_.start();
log.info("Cache started");
}
}
private void startListener() throws Exception
{
if (srvSock_!=null) {
throw new Exception("Listener already started.");
}
if (bindAddressString_!=null) {
InetAddress bindAddress = InetAddress.getByName(bindAddressString_);
srvSock_ = new ServerSocket(listenerPort_, 50, bindAddress);
}
else {
srvSock_ = new ServerSocket(listenerPort_, 50);
}
listenerThread_ = new Thread(new Runnable()
{
public void run()
{
mainLoop();
stopListener();
}
}, "JBossCache Shutdown Listener Thread");
listenerThread_.start();
log.info("Listener started");
}
private void mainLoop()
{
Socket sock = null;
while (!stopped)
{
ObjectInputStream ois = null;
try
{
// blocks until shutdown request or 'forever'
sock=srvSock_.accept();
sock.setSoLinger(true, 500);
if(log.isTraceEnabled()) {
log.trace("accepted connection from "+sock);
}
BufferedInputStream bis = new BufferedInputStream(sock.getInputStream());
ois = new ObjectInputStream(bis);
ObjectOutputStream oos = new ObjectOutputStream(sock.getOutputStream());
try
{
String cmd = (String) ois.readObject();
if (SHUTDOWN.equals(cmd))
{
stopped = true;
stopCache();
oos.writeObject("OK");
}
else {
cmd = (cmd == null) ? "null" : cmd;
oos.writeObject("Invalid command: " + cmd);
}
}
catch (Exception e)
{
oos.writeObject("FAILED: " + e.getLocalizedMessage());
}
finally
{
oos.close();
}
bis.close();
sock.close();
}
catch(Exception e) {
if(log.isDebugEnabled()) log.debug("listener thread exception :"+e);
}
finally {
try {
ois.close();
}
catch(Exception e) {
// OK
}
}
}
}
private void stopListener()
{
stopped = true;
if (Thread.currentThread() != listenerThread_)
{
listenerThread_.interrupt();
}
try
{
srvSock_.close();
}
catch(Exception e)
{
log.error("Failed to close server socket: "+e);
}
srvSock_ = null;
log.info("Listener thread stopped");
}
private void stopCache()
{
if (cache_ != null)
{
try
{
cache_.stop();
cache_.destroy();
}
catch (Exception e)
{
log.error("Error stopping cache", e);
}
finally
{
cache_ = null;
}
}
}
private class ShutdownHook extends Thread
{
public void run()
{
try
{
stopCache();
}
catch (Exception e)
{
}
try
{
stopListener();
}
catch (Exception e)
{
}
}
}
}