How to gracefully shutdown embeded jetty - java

I have an application runs on an embedded jetty server. Now i want to start/stop the server as a service.
I use a script to start the server.
java $JAVA_OPTS -DREQ_JAVA_VERSION=$JAVA_VERSION -jar myjetty.jar
Main Class
Server server = new Server();
SelectChannelConnector connector = new SelectChannelConnector();
connector.setPort(PORT);
server.addConnector(connector);
HandlerCollection handlers = new HandlerCollection();
NCSARequestLog requestLog = new NCSARequestLog();
requestLog.setFilename(home + "/logs/access_" + logFileDateFormat
+ ".log");
requestLog.setFilenameDateFormat(logFileDateFormat);
requestLog.setRetainDays(10);
requestLog.setAppend(true);
requestLog.setExtended(false);
requestLog.setLogCookies(false);
requestLog.setLogTimeZone(TimeZone.getDefault().getID());
RequestLogHandler requestLogHandler = new RequestLogHandler();
requestLogHandler.setRequestLog(requestLog);
handlers.addHandler(requestLogHandler);
server.setHandler(handlers);
server.start();
server.join();
This starts the server.Stopping and/or Restarting an embedded Jetty instance via web call can be used to stop server but,
How to stop the server from the script? and what changes should i make to shout down server in the main class.

Since Jetty 7.5.x you can use org.eclipse.jetty.server.handler.ShutdownHandler in your code:
Server server = new Server(8080);
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[]
{ someOtherHandler, new ShutdownHandler("secret_password", false, true) });
server.setHandler(handlers);
server.start();
... which will allow you to shut down your jetty by issuing the following http POST request:
curl -X POST http://localhost:8080/shutdown?token=secret_password

You can call setStopTimeout(long timeout) to shutdown Jetty in a relatively graceful way. A statisticsHandler must be configured when calling this method.
Referencing: Jetty Server.class setStopTimeout(long)
e.g.
YourServletHandler servletHandler = new YourServletHandler();
StatisticsHandler statsHandler = new StatisticsHandler();
statsHandler.setHandler(servletHandler);
Server server = new Server(80);
server.setHandler(statsHandler);
server.setStopTimeout(3000L);
//...
server.start();
//...
server.stop();

There is no predefined solution to shut-down the Jetty server. The only ordered way to shut-down the Jetty server is to call the method stop() on the running server instance. You must implement the way how this method is called yourself.
You could achieve this (for example) by...
implementing an RMI server thread and invoke the method from a RMI client
implementing a JMX MBean and from a client call a method on that MBean
implementing a custom handler like described in the link you have posted
If you only want to find a way which does not depend on additional tools like curl, than you could solve it for example like below (it's your own code with small modifications)
public class MyJetty {
public static void main(String[] args) throws Exception {
int PORT = 9103;
String home = System.getProperty("user.home");
String logFileDateFormat = "yyyy_MM_dd";
// execute a request to http://localhost:9103/stop
// instead of `curl -v http://localhost:9103/stop`
if (args.length == 1 && "stop".equalsIgnoreCase(args[0])) {
URL url = new URL("http", "localhost", PORT, "/stop");
try (InputStream in = url.openStream()) {
int r;
while ((r = in.read()) != -1) {
System.out.write(r);
}
return;
} catch (IOException ex) {
System.err.println("stop Jetty failed: " + ex.getMessage());
}
}
Server server = new Server();
SelectChannelConnector connector = new SelectChannelConnector();
connector.setPort(PORT);
server.addConnector(connector);
HandlerCollection handlers = new HandlerCollection();
NCSARequestLog requestLog = new NCSARequestLog();
requestLog.setFilename(home + "/logs/access_" + logFileDateFormat + ".log");
requestLog.setFilenameDateFormat(logFileDateFormat);
requestLog.setRetainDays(10);
requestLog.setAppend(true);
requestLog.setExtended(false);
requestLog.setLogCookies(false);
requestLog.setLogTimeZone(TimeZone.getDefault().getID());
RequestLogHandler requestLogHandler = new RequestLogHandler();
requestLogHandler.setRequestLog(requestLog);
handlers.addHandler(requestLogHandler);
// the class YourHandler is the one from your link
handlers.addHandler(new YourHandler(server));
server.setHandler(handlers);
server.start();
server.join();
}
}
start the server with java MyJetty
stop the server with java MyJetty stop

I don't know why (or if it is a bug) but in my case I had to set shutdownAtStart argument to false to get it working. If I set it as true the Server connector never starts, so it doesn't attend external requests like http://localhost:8888/shutdown?token=secret
new ShutdownHandler("secret", false, false);

Related

How to configure the netty-SocketIO server so that it is accessible from all remote java clients in jelastic

I am developing a Spring-Boot project which also includes a socketIO server based on netty-socket Io. And therefore two clients: a web client and an android client!
all of them work wonderfully locally! But when I deploy online server in Jelastic only the web client which accesses netty-SocketIO server, but android client fails to connect to netty-SocketIO server. someone could help me configure the netty-socketIO server to accept all requests from any address on port 8888
Server configuration
Configuration config = new Configuration();
//config.setHostname("sec.j.layershift.co.uk");
config.setHostname("0.0.0.0");
config.setPort(8888);
final SocketIOServer server = new SocketIOServer(config);
// Listen for client connections
server.addConnectListener(client -> {
System.out.println("************ Client: " + getIpByClient(client) + " Connected ************");
});
Web client configuration
#CrossOrigin("*")
#RestController
public class ClientLocation {
Socket socket =null;
EventBuilder eventBuilder =null;
Gson gs = new Gson();
//................................
socket = IO.socket("http://sec.j.layershift.co.uk:8888");
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
ChatObject co = new ChatObject("ADMIN", "");
String infUser = gs.toJson(co);
System.out.println("\n"+infUser);
JSONObject jb = new JSONObject();
try {
// jb.put("userName", co.getUserName());
// jb.put("message", co.getMessage());
jb = new JSONObject(infUser);
socket.emit("username", jb);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Configuration of the java or android client
private void clientIO(){
try {
socket = IO.socket("http://aug-sec.j.layershift.co.uk:8888");
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
Nb. the configuration of the java or android client is identical to that of the web because all use the Socket.IO v1.0.0. But only the web client works from the Jelastic host because it is in the same folder as the server and the java clients do not succeed, so everything works in localhost or in LAN
There are 2 possible solutions
You can use the public IP (the way suggested by #Ruslan)
Also, the Jelastic platform resolver supports the WebSocket proxying (if the "Upgrade: websocket" header is present). You can use the JELASTIC_EXPOSE variable to forward the requests from port 80 to 8888 (more info here https://docs.jelastic.com/container-ports/#ports-auto-redirect) inside your container and then just access the app by your environment domain and port 80

Jetty Server blocks when setting handler

I am trying to setup a Jetty Server with Servlet Contexts and it blocks when calling server.setHandler(context). If I run the code snippet from below, which is actually following the example from http://www.eclipse.org/jetty/documentation/9.3.x/embedding-jetty.html#_embedding_servletcontexts , it only prints one "a" and then blocks.
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
Server server = new Server(8070);
log.info("a");
server.setHandler(context);
log.info("a");
context.addServlet(EventServer.class, "/response");
context.addServlet(NotificationServer.class, "/notification");
log.info("a");
context.addEventListener(new ConfigureService());
context.addEventListener(new NotificationService());
try {
server.start();
log.info("Jetty-Server Started");
server.join();
} catch (Exception e) {
log.error(ExceptionUtils.getFullStackTrace(e));
} finally {
server.destroy();
}
Any idea why it does not execute the rest of the code and blocks when setting the handler?
It turns out that you can't actually run the jetty-server and jetty-servlet while them being different versions and this will cause the block when setting the handler.

Akka HTTP server with SSL support in Java - How to create configuration?

I am trying to create an Akka HTTP server, which will support SSL.
I am aware of this question for scala Akka HTTP 2.0 to use SSL (HTTPS) and I am trying to work it into Java code but I am getting lost.
The DSL akka.http.javadsl.Http class is different for Java and requires akka.actor.ExtendedActorSystem, when I try to create an instance for it I am required to create an application configuration with the com.typesafe.config.Config class, which I can't figure out how to instantiate and what to put in it.
Is there any simpler way? Or any classes I can use to create all the required configurations?
This is a snippet of the code:
// boot up server using the route as defined below
final ActorSystem system = ActorSystem.create();
final ActorMaterializer materializer = ActorMaterializer.create(system);
// Run the server bound to the local machine IP
String hostAddress = InetAddress.getLocalHost().getHostAddress();
// No implementation here?????
Config applicationConfig = new Config() {
}
ExtendedActorSystem extendedActorSystem = new ActorSystemImpl("HttpProxy", applicationConfig, ClassLoader.getSystemClassLoader(), Option.empty());
// todo: missing handler, settings, httpsContext and log
Flow<HttpRequest, HttpResponse, ?> handler;
ServerSettings settings;
akka.japi.Option<HttpsContext> httpsContext;
LoggingAdapter log;
new Http(extendedActorSystem).bindAndHandle(handler, hostAddress, PORT, settings, httpsContext, log, materializer);
System.out.println("Starting server on " + hostAddress + ":" + PORT);
// The server would stop if carriage return is entered in the system cosole
System.out.println("Type RETURN to exit");
System.in.read();
system.shutdown();
It supposed to be something like this:
// boot up server using the route as defined below
// Run the server bound to the local machine IP
String hostAddress = InetAddress.getLocalHost().getHostAddress();
// No implementation here?????
Config applicationConfig = ConfigFactory.load();
ActorSystem system = ActorSystem.create("HttpProxy", applicationConfig);
final ActorMaterializer materializer = ActorMaterializer.create(system);
// todo: missing handler, settings, httpsContext and log
Flow<HttpRequest, HttpResponse, ?> handler;
ServerSettings settings;
akka.japi.Option<HttpsContext> httpsContext;
LoggingAdapter log;
Http.get(system).bindAndHandle(handler, hostAddress, 9000, settings, httpsContext, log, materializer);
System.out.println("Starting server on " + hostAddress + ":" + 9000);

two contexts one server jetty

i have two jetty embedded servers,
localhost:9001/WebApp1 and localhost:9002/WebApp2,
as you can see they're on different ports.
I'd like them to share the same port during creation of server
is it possible? (BTW they are two separate jar files as well).
so can i do something like this instead
localhost:9001/WebApp1 and localhost:9001/WebApp2
or am I stuck with producing war files then having them
contained by a tomcat/glassfish server
during creation of server i usually see this
ContextHandler context = new ContextHandler();
context.setContextPath("/WebApp1");
context.setHandler(new WebApp1());
Server server = new Server(9001);
server.setHandler(context);
server.start();
server.join();
on second app i'd like to have something that looks like this
ContextHandler context = new ContextHandler();
context.setContextPath("/WebApp2");
context.setHandler(new WebApp2());
Server server = getExistingServer(9001);
server.addHandler(context);
i see that there is such method server.getHandlers(); which returns an array of handlers how do i add new handler to the existing list, or get the existing jetty server running at port 9001
Jetty is a standard servlet container and can of course handle different contexts.
See section Embedding Contexts in Chapter 24 of the Jetty documentation.
Here is the ManyContexts example (part of Jetty docs):
public class ManyContexts
{
public static void main( String[] args ) throws Exception
{
Server server = new Server(8080);
ContextHandler context = new ContextHandler("/");
context.setContextPath("/");
context.setHandler(new HelloHandler("Root Hello"));
ContextHandler contextFR = new ContextHandler("/fr");
contextFR.setHandler(new HelloHandler("Bonjoir"));
ContextHandler contextIT = new ContextHandler("/it");
contextIT.setHandler(new HelloHandler("Bongiorno"));
ContextHandler contextV = new ContextHandler("/");
contextV.setVirtualHosts(new String[] { "127.0.0.2" });
contextV.setHandler(new HelloHandler("Virtual Hello"));
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(new Handler[] { context, contextFR, contextIT, contextV });
server.setHandler(contexts);
server.start();
server.join();
}
}

jetty server 9.1 multiple embeded ports and application in same server instance

I should use one Server object, and need to open multiple ports and multiple application(WAR files).
Ex, one server object,
8080 addition.war
8081 subraction.war
etc.
I'm using Jetty server 9.1.0
How can I do this?
To accomplish this, you need:
Each ServerConnector should have a unique name declared via ServerConnector.setName(String)
When you define your WebAppContext, declare a set of virtual hosts that take a named virtual host syntax "#{name}", where the {name} is the same one you chose for the connector. (Note: A virtualhost without the "#" sign is a traditional virtualhost based on hostnames)
Like this ...
package jetty.demo;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.webapp.WebAppContext;
public class ConnectorSpecificContexts
{
public static void main(String[] args)
{
Server server = new Server();
ServerConnector connectorA = new ServerConnector(server);
connectorA.setPort(8080);
connectorA.setName("connA"); // connector name A
ServerConnector connectorB = new ServerConnector(server);
connectorB.setPort(9090);
connectorB.setName("connB"); // connector name B
server.addConnector(connectorA);
server.addConnector(connectorB);
// Basic handler collection
HandlerCollection contexts = new HandlerCollection();
server.setHandler(contexts);
// WebApp A
WebAppContext appA = new WebAppContext();
appA.setContextPath("/a");
appA.setWar("./webapps/webapp-a.war");
appA.setVirtualHosts(new String[]{"#connA"}); // connector name A
contexts.addHandler(appA);
// WebApp B
WebAppContext appB = new WebAppContext();
appB.setContextPath("/b");
appB.setWar("./webapps/webapp-b.war");
appB.setVirtualHosts(new String[]{"#connB"}); // connector name B
contexts.addHandler(appB);
try
{
server.start(); // start server thread
server.join(); // wait for server thread to end
}
catch (Throwable t)
{
t.printStackTrace(System.err);
}
}
}

Categories