Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
arey committed Apr 5, 2015
0 parents commit c46b3bb
Show file tree
Hide file tree
Showing 11 changed files with 712 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Maven
/target/

# IntelliJ IDEA
*.idea
*.iml


366 changes: 366 additions & 0 deletions pom.xml

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Embbeded Jetty web application Batch Toolkit #

This project shows how to build a WAR-less Java web application with Jetty.

Only a single JVM is required to start the web app. No web container or JEE server is required.

Instead of building a war file, an auto-executable JAR file is built with Maven (ie. jetty-webapp-1.0.0-SNAPSHOT.jar)

This JAR contains all resources required by a web application: web.xml, index.jsp, images, js, css...
The JettyServer class provides both a start and a stop method. Its main method starts the server. To stop it, you may use the Stop class.

Thanks to the [Application Assembler Maven Plugin](http://mojo.codehaus.org/appassembler/appassembler-maven-plugin/) a start.sh and a stop.sh script are available.

All JAR dependencies are available in a lib\ sub-directory.


## Try it ##

Download the code with git:
```git clone git://github.com/arey/embedded-jetty-webapp.git```

Build and package the web application

```
cd embedded-jetty-webapp
mvn clean install
```

Start the web application
```target/appassembler/bin/start.sh &```

Stop the web application
```target/appassembler/bin/stop.sh```

Browse to [http://localhost:8080/HelloWorld](http://localhost:8080/HelloWorld)

Web port could be changed at startup:
```target/appassembler/bin/start.sh 80 8090 &```

## Configuration rules ##

Compared to the [Maven Standard Directory Layout](https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html)
of a WAR, the web application sources is not put into the ```src/main/webapp``` but into the ```src/main/resources/webapp```.
Thus the webapp resources are copied into the JAR in a webapp/ sub-directory.

## Credits ##

* Uses [Maven](http://maven.apache.org/) as a build tool
* Uses [Maven Jetty plugin](https://github.com/eclipse/jetty.project) source code
1 change: 1 addition & 0 deletions src/main/config/application.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
application.name=Hello World
20 changes: 20 additions & 0 deletions src/main/java/com/javaetmoi/jetty/HelloWorldServlet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.javaetmoi.jetty;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class HelloWorldServlet extends HttpServlet {

public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<h1>Hello World</h1>");
out.close();
}

}
118 changes: 118 additions & 0 deletions src/main/java/com/javaetmoi/jetty/JettyServer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package com.javaetmoi.jetty;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.OutputStream;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URL;

/**
* Starts with Jetty an auto-executable web application packaged into a JAR file.
*/
public class JettyServer {

public static final String WEBAPP_RESOURCES_LOCATION = "webapp";
static final int DEFAULT_PORT_STOP = 8090;
static final String STOP_KEY = "stopKey";
private static final int DEFAULT_PORT_START = 8080;
private static final Logger LOGGER = LoggerFactory.getLogger(JettyServer.class);
private final int startPort;
private final int stopPort;

public JettyServer() {
this(DEFAULT_PORT_START, DEFAULT_PORT_STOP);
}

public JettyServer(int startPort, int stopPort) {
this.startPort = startPort;
this.stopPort = stopPort;
}

/**
* Stops a running web application powered with Jetty.
* <p/>
* <p/>
* Default TCP port is used to communicate with Jetty.
*/
static public void stop() {
stop(DEFAULT_PORT_STOP);
}

/**
* Stops a running web application powered with Jetty.
*
* @param stopPort TCP port used to communicate with Jetty.
*/
static public void stop(Integer stopPort) {
try {
Socket s = new Socket(InetAddress.getByName("127.0.0.1"), stopPort);
LOGGER.info("Jetty stopping...");
s.setSoLinger(false, 0);
OutputStream out = s.getOutputStream();
out.write((JettyServer.STOP_KEY + "\r\nstop\r\n").getBytes());
out.flush();
s.close();
} catch (ConnectException e) {
LOGGER.info("Jetty not running!");
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}

/**
* Start a Jetty web server with its webapp.
*
* @param args first argument is the web port, second argument is the port used to stop Jetty
* @throws Exception
*/
public static void main(String[] args) throws Exception {
JettyServer jettyServer = null;
if (args.length == 2) {
jettyServer = new JettyServer(Integer.valueOf(args[0]), Integer.valueOf(args[1]));
} else {
jettyServer = new JettyServer();
}
jettyServer.start();
}

/**
* Start a Jetty server then deploy a web application.
*
* @throws Exception If Jetty fails to start
*/
public void start() throws Exception {
Server server = new Server(startPort);
WebAppContext root = new WebAppContext();

root.setContextPath("/");
root.setDescriptor(WEBAPP_RESOURCES_LOCATION + "/WEB-INF/web.xml");

URL webAppDir = Thread.currentThread().getContextClassLoader().getResource(WEBAPP_RESOURCES_LOCATION);
if (webAppDir == null) {
throw new RuntimeException(String.format("No %s directory was found into the JAR file", WEBAPP_RESOURCES_LOCATION));
}
root.setResourceBase(webAppDir.toURI().toString());
root.setParentLoaderPriority(true);

server.setHandler(root);

server.start();

LOGGER.info("Jetty server started");
LOGGER.debug("Jetty web server port: {}", startPort);
LOGGER.debug("Port to stop Jetty with {}: {}", STOP_KEY, stopPort);

Monitor monitor = new Monitor(stopPort, STOP_KEY, new Server[]{server});
monitor.start();

server.join();

LOGGER.info("Jetty server exited");
}

}
96 changes: 96 additions & 0 deletions src/main/java/com/javaetmoi/jetty/Monitor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package com.javaetmoi.jetty;

import org.eclipse.jetty.server.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

/**
* Listens for stop commands and causes jetty to stop by stopping the server instance.
*
* @see <a href="https://github.com/eclipse/jetty.project/tree/master/jetty-maven-plugin">https://github.com/eclipse/jetty.project/tree/master/jetty-maven-plugin</a>
*/
public class Monitor extends Thread {

private static Logger LOGGER = LoggerFactory.getLogger(Monitor.class);

private String key;
private Server[] servers;
ServerSocket serverSocket;

public Monitor(int port, String key, Server[] servers) throws UnknownHostException, IOException {
if (port <= 0)
throw new IllegalStateException("Bad stop PORT");
if (key == null)
throw new IllegalStateException("Bad stop key");
this.key = key;
this.servers = servers;
setDaemon(true);
setName("StopJettyMonitor");
serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
serverSocket.setReuseAddress(true);
}

public void run() {
while (serverSocket != null) {
Socket socket = null;
try {
socket = serverSocket.accept();
socket.setSoLinger(false, 0);
LineNumberReader lin = new LineNumberReader(new InputStreamReader(
socket.getInputStream()));
String key = lin.readLine();
if (!this.key.equals(key))
continue;
String cmd = lin.readLine();
if ("stop".equals(cmd)) {
try {
socket.close();
} catch (Exception e) {
LOGGER.debug(e.getMessage(), e);
}
try {
socket.close();
} catch (Exception e) {
LOGGER.debug(e.getMessage(), e);
}
try {
serverSocket.close();
} catch (Exception e) {
LOGGER.debug(e.getMessage(), e);
}
serverSocket = null;

for (int i = 0; servers != null && i < servers.length; i++) {
try {
LOGGER.info("Stopping server " + i);
servers[i].stop();
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}

} else
LOGGER.info("Unsupported monitor operation");
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
} finally {
if (socket != null) {
try {
socket.close();
} catch (Exception e) {
LOGGER.debug(e.getMessage(), e);
}
}
socket = null;
}
}
}
}
13 changes: 13 additions & 0 deletions src/main/java/com/javaetmoi/jetty/Stop.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.javaetmoi.jetty;

public class Stop {

public static void main(String[] args) throws Exception {
if (args.length == 1) {
JettyServer.stop(Integer.valueOf(args[0]));
} else {
JettyServer.stop();
}

}
}
15 changes: 15 additions & 0 deletions src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<configuration>

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%level] [%thread] %msg%n</pattern>
</encoder>
</appender>

<logger name="com.javaetmoi.jetty" level="DEBUG"/>

<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>

</configuration>
21 changes: 21 additions & 0 deletions src/main/resources/webapp/WEB-INF/web.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">

<servlet>
<servlet-name>HelloWorldServlet</servlet-name>
<servlet-class>com.javaetmoi.jetty.HelloWorldServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>HelloWorldServlet</servlet-name>
<url-pattern>/HelloWorld</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

</web-app>
5 changes: 5 additions & 0 deletions src/main/resources/webapp/index.jsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<html>
<body>
Index page
</body>
</html>

0 comments on commit c46b3bb

Please sign in to comment.