View Javadoc

1   package org.sourceforge.jemm;
2   
3   import java.io.File;
4   
5   import org.apache.commons.cli.CommandLine;
6   import org.apache.commons.cli.GnuParser;
7   import org.apache.commons.cli.HelpFormatter;
8   import org.apache.commons.cli.Options;
9   import org.apache.commons.cli.ParseException;
10  import org.apache.log4j.Logger;
11  import org.sourceforge.jemm.comm.connection.ConnectionException;
12  import org.sourceforge.jemm.comm.connection.socket.SocketServerConnectionFactory;
13  import org.sourceforge.jemm.database.Database;
14  import org.sourceforge.jemm.database.memory.MemoryDatabase;
15  import org.sourceforge.jemm.database.persistent.berkeley.BDbDatabase;
16  import org.sourceforge.jemm.database.remote.server.RemoteDatabaseServer;
17  import org.sourceforge.jemm.server.ServerOptions;
18  import org.sourceforge.jemm.server.ShutdownRequestListener;
19  import org.sourceforge.jemm.server.ShutdownRequestReceiver;
20  import org.sourceforge.jemm.server.ShutdownRequestSender;
21  
22  /**
23   * JemmServer represents a remote JEMM Server for clients to connect to and share data.
24   * It is able to run in either persistent mode or pure memory mode.
25   * It also supports shutdown and a number of command line configuration options.
26   * 
27   * @author Rory Graves
28   *
29   */
30  public final class JemmServer {
31  	
32  	private static final Logger LOG = Logger.getLogger(JemmServer.class);
33  
34  	private static RemoteDatabaseServer remoteDatabase;
35  	private static MemoryDatabase memoryDatabase;
36  	private static BDbDatabase persistentDatabase;
37  	private static ShutdownRequestReceiver shutdownHandler; 	
38  
39  	/** private constructor to prevent instantiation */
40  	private JemmServer() {}
41  	
42  
43  	public static void main(String args[]) throws Exception {
44  		
45  		GnuParser parser = new GnuParser();
46  		Options cmdLineOptions = ServerOptions.generateOptions();
47      	CommandLine cmd = parser.parse(cmdLineOptions,args);
48      	if(cmd.hasOption('h')) {
49      		HelpFormatter helpFormatter = new HelpFormatter();
50      		helpFormatter.printHelp(80,"java org.sourceforge.jemm.JemmServer <options>", null, cmdLineOptions, null);
51      		System.exit(0);
52      	}
53  
54      	try {
55      		ServerOptions options = new ServerOptions(cmd);
56      		switch(options.getAction()) {
57              case START:
58                  serverStart(options);
59                  break;
60              case STOP:
61                  serverStop(options);
62                  break;
63              default:
64                  throw new IllegalStateException("Action " + options.getAction() + " not handled");
65      		}
66      		
67      	} catch(ParseException pe) {
68      		HelpFormatter helpFormatter = new HelpFormatter();
69      		System.out.println("Error parsing command line options: " + pe.getMessage());
70      		helpFormatter.printHelp(80,"java org.sourceforge.jemm.JemmServer <options>", null, cmdLineOptions, null);
71      	}
72  	}
73  
74  
75  	private static void serverStop(ServerOptions options) {
76  		ShutdownRequestSender.sendRequest("localhost", options.getControlPort());
77  	}
78  
79  
80  	private static void serverStart(ServerOptions options) {				
81  		Database db = null;
82  	
83  		System.out.println("Running with configuration:");
84  		System.out.println(options.toString());
85  		
86  		switch(options.getMode()) {
87  		case PERSISTENT:
88  			File storageDir = options.getDataDir();
89  			persistentDatabase = new BDbDatabase(storageDir);
90  			db = persistentDatabase;
91  			break;
92  		case MEMORY:
93  			memoryDatabase = new MemoryDatabase();
94  			db = memoryDatabase;
95  			break;
96          default:
97              throw new IllegalStateException("Server mode " + options.getMode() + " not handled");
98  		}
99  
100 		shutdownHandler = new ShutdownRequestReceiver(options.getControlPort(),
101 				new ShutdownRequestListener() {
102 			@Override
103 			public void shutdownRequest() {
104 				LOG.info("Shutdown request received");
105 				LOG.info("Closing client connections");
106 				remoteDatabase.shutdown();
107 
108 				LOG.info("Waiting 2 second for client connection cleanup");
109 				
110 				try {
111 					Thread.sleep(2000);
112 				} catch(InterruptedException ie) {
113 					LOG.warn("Interrupted Exception received whilst waiting for shutdown",ie);
114 				}
115 				
116 				LOG.info("Closing underlying database");
117 				if(memoryDatabase != null)
118 					memoryDatabase.shutdown();
119 				else if(persistentDatabase != null)
120 					persistentDatabase.shutdown();
121 				
122 				shutdownHandler.shutdown();
123 				LOG.info("System shutdown");
124 				
125 			}			
126 		});
127 		shutdownHandler.start();
128 		
129 		try {
130 			remoteDatabase = new RemoteDatabaseServer(new SocketServerConnectionFactory(options.getPort()),db);
131 			System.out.println("JemmServer running, listening for clients on port " + options.getPort());
132 		} catch(ConnectionException ce) {
133 			System.out.println("Unable to initialise database, is the port available?");
134 			System.out.println("Reported error is:");
135 			ce.printStackTrace();
136 			System.exit(1);
137 		}
138 	}
139 }