/** * Copyright 2003-2008 Luck Consulting Pty Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.sf.ehcache.server.standalone; import org.apache.commons.daemon.Daemon; import org.apache.commons.daemon.DaemonContext; import org.apache.commons.daemon.DaemonController; import org.glassfish.embeddable.Deployer; import org.glassfish.embeddable.GlassFish; import org.glassfish.embeddable.GlassFishException; import org.glassfish.embeddable.GlassFishProperties; import org.glassfish.embeddable.GlassFishRuntime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; /** * The ehcache server. *

* By default the server listens for HTTP at 8080 and JMX at 8081. *

* The HTTP Port may be passed in. The JMX port is always the HTTP port + 1. So, if the HTTP port is 9076, the JMX * listening port will be 9077. *

* No other ports are opened. * * @author Greg Luck * @version $Id$ */ public class Server implements Daemon { /** * Default port: 8080 */ public static final Integer DEFAULT_BASE_PORT = 8080; private static final Logger LOG = LoggerFactory.getLogger(Server.class); private static ServerThread serverThread; private DaemonController controller; private File war; private Integer httpPort = DEFAULT_BASE_PORT; /** * Empty constructor. * This will create a server listening on the default port of 9998 and using the LightWeight HTTP Server * * @see #Server(Integer, java.io.File) */ public Server() { // } /** * Constructs a server listening at the given HTTP port * * @param httpPort the HTTP port to listen on. The JMX connector port is always to set to the HTTP port + 1. * @param ehcacheServerWar the ehcache-server.war */ public Server(Integer httpPort, File ehcacheServerWar) { this.httpPort = httpPort; this.war = ehcacheServerWar; } /** * Invoked by Jsvc with a context which includes the arguments passed to Jsvc. The main() method * also calls through here so that the server can be started using either Jsvc or java -jar... * * @param daemonContext * @throws Exception */ public void init(DaemonContext daemonContext) throws Exception { String[] args = daemonContext.getArguments(); if (args.length < 1 || args.length > 2 || (args.length == 1 && args[0].matches("--help"))) { System.out.println("Usage: java -jar ... [http httpPort] warfile | wardir "); System.exit(0); } if (args.length == 1) { war = new File(args[0]); if (!war.exists()) { System.err.println("Error: War file or exploded directory " + war + " does not exist."); System.exit(1); } } if (args.length == 2) { httpPort = Integer.parseInt(args[0]); war = new File(args[1]); if (!war.exists()) { System.err.println("Error: War file or exploded directory " + war + " does not exist."); System.exit(1); } } /* Dump a message */ System.err.println("\nEhcache standalone server initializing..."); /* Set up this simple daemon */ this.controller = daemonContext.getController(); } /** * Starts the server. This method is called by Jsvc. The main() method * also calls through here so that the server can be started using either Jsvc or java -jar... * * @throws Exception */ public void start() throws Exception { System.out.println("\nStarting standalone ehcache server on httpPort " + httpPort + " with WAR file or directory " + war); serverThread = new GlassfishServerThread(); serverThread.start(); } /** * A method for stopping a server. This is meant to be used by integration tests thus the package protected. * * @throws InterruptedException if the server is interrupted while stopping */ static void stopStatic() throws InterruptedException, GlassFishException { serverThread.stopServer(); //wait indefinitely until it shuts down serverThread.join(); } /** * Shuts down the HTTP server in an orderly way. */ public void stop() throws InterruptedException, GlassFishException { System.out.println("\nEhcache standalone server stopping..."); stopStatic(); System.out.println("\nEhcache standalone server stopped."); } /** * Interrupts the server thread. */ public void destroy() { System.out.println("\nEhcache standalone server destroyed."); serverThread.interrupt(); } /** * A mock DaemonContext which allows the main() method to call init. */ static class MockDaemonContext implements DaemonContext { private String[] args; /** * Constructor. * * @param args the main() method arguments. */ public MockDaemonContext(String[] args) { this.args = args; } /** * @return null as it is not a real Daemon */ public DaemonController getController() { return null; } /** * @return the arguments main() was invoked with. */ public String[] getArguments() { return args; } } /** * Wires in main() to use the Jsvc invocation path. *

* Usage: java -jar ... [http port] warfile | wardir *

* The port is optional. It should be <= 65536 *

* If no war is specified, the LightWeight Http server is used. Otherwise Glassfish is used. * * @param args The first argument is the server port. The second is optional and is the path to the ehcache-server.war. * @throws Exception */ public static void main(String[] args) throws Exception { // String[] arguments = {"9090", "target/war/work/net.sf.ehcache/ehcache-server/greg.war"}; Server server = new Server(); server.init(new MockDaemonContext(args)); server.start(); } /** * Forks the Server into its own thread. */ abstract class ServerThread extends Thread { /** * Stops the server. */ public abstract void stopServer() throws GlassFishException; } /** * Embedded Glassfish implementation */ class GlassfishServerThread extends ServerThread { private GlassFish server; /** * Creates a server in a separate thread. *

* This permits the calling thread to immediately return */ public void run() { startWithGlassfish(); } private void startWithGlassfish() { try { GlassFishRuntime gfr = GlassFishRuntime.bootstrap(); GlassFishProperties glassfishProps = new GlassFishProperties(); glassfishProps.setPort("http-listener", httpPort); Integer jmxPort = httpPort + 1; // todo embeddedInfo.setJmxConnectorPort(jmxPort); // Jerome Dochez confirmed 4 March 2010 this did not make it into 3 embedded server = gfr.newGlassFish(glassfishProps); server.start(); Deployer deployer = server.getDeployer(); deployer.deploy(war, "--contextroot=ehcache", "--enabled=true", "--force=true"); LOG.info("Glassfish server running on httpPort " + httpPort + " with WAR " + war); //+ ". JMX is listening at " + jmxPort); } catch (Exception e) { LOG.error("Cannot start server. ", e); } } /** * Stops the server */ public void stopServer() throws GlassFishException { //will cause the startsWithGlassfish method to return, and thus run() thus ending the thread. server.stop(); } } }