Skip to content

Instantly share code, notes, and snippets.

@mathieuancelin
Created January 13, 2012 09:25
Show Gist options
  • Save mathieuancelin/1605266 to your computer and use it in GitHub Desktop.
Save mathieuancelin/1605266 to your computer and use it in GitHub Desktop.
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello ${name}!</h1>
</body>
</html>
package foo.bar;
import com.sun.net.httpserver.HttpExchange;
import java.net.URI;
public class MyResource implements WebServer.Resource {
public static void main(String... args) {
WebServer.create("0.0.0.0", 9000).addResource(new MyResource()).run();
}
@Override
public boolean valid(URI uri, String httpMethod) {
return (uri.toString().equals("/") && httpMethod.equals("GET"));
}
@Override
public void render(HttpExchange he) {
WebServer.renderTemplate("index.html", WebServer.params("name", "mathieu").get(), he);
}
}
package foo.bar;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class WebServer {
private static final int BUFFER_SIZE = 1024;
private static final Pattern VAR = Pattern.compile("\\$\\{.*\\}");
private final List<Resource> resources = new ArrayList<Resource>();
private final ExecutorService service = Executors.newCachedThreadPool();
private final File staticFolder = new File("static");
private final HttpServer server;
private WebServer(String host, int port) {
try {
this.server = HttpServer.create(new InetSocketAddress(host, port), 0);
this.server.setExecutor(service);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
public static WebServer create(String host, int port) {
return new WebServer(host, port);
}
public WebServer addResource(Resource res) {
resources.add(res);
return this;
}
public WebServer run() {
if (!staticFolder.exists()) {
staticFolder.mkdirs();
}
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
server.stop(0);
service.shutdownNow();
}
});
server.createContext("/", new HttpHandler() {
public void handle(HttpExchange he) throws IOException {
try {
for (Resource r : resources) {
if (r.valid(he.getRequestURI(), he.getRequestMethod())) {
r.render(he);
return;
}
}
writeContent("<html><body style=\"background-color: #b22222;\"><h1>Error 404 : resource not found</h1></body></html>", "text/html", 404, he);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
});
server.createContext("/static/", new HttpHandler() {
@Override
public void handle(HttpExchange he) throws IOException {
String res = he.getRequestURI().toString().replace("/static/", "");
File resFile = new File(staticFolder, res);
if (resFile.exists()) {
he.getResponseHeaders().add("Content-Length", String.valueOf(resFile.length()));
he.sendResponseHeaders(200, resFile.length());
copyStream(he, new FileInputStream(resFile));
he.getResponseBody().flush();
he.getResponseBody().close();
} else {
try {
writeContent("<html><body style=\"background-color: #b22222;\"><h1>Error 404 : resource '/static/" + res + "' not found</h1></body></html>", "text/html", 404, he);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
}
});
server.start();
return this;
}
public WebServer stop() {
server.stop(0);
service.shutdownNow();
return this;
}
// Templates utils
public static void renderTemplate(String name, Map<String, Object> params, HttpExchange he) {
try {
String content = readFileAsString(new File(name));
Matcher matcher = VAR.matcher(content);
while(matcher.find()) {
String group = matcher.group();
String var = group.replace("${", "").replace("}", "");
Object o = params.get(var);
if (o == null) {
o = "null";
}
content = content.replace(group, o.toString());
}
writeContent(content, "text/html", 200, he);
} catch (Throwable e) {
throw new RuntimeException("Error ", e);
}
}
public static void renderText(String text, HttpExchange he) {
try {
writeContent(text, "text/plain", 200, he);
} catch (Throwable e) {
throw new RuntimeException("Error ", e);
}
}
public static void renderJSON(String text, HttpExchange he) {
try {
writeContent(text, "application/JSON", 200, he);
} catch (Throwable e) {
throw new RuntimeException("Error ", e);
}
}
public static void renderXML(String text, HttpExchange he) {
try {
writeContent(text, "application/xml", 200, he);
} catch (Throwable e) {
throw new RuntimeException("Error ", e);
}
}
private static void writeContent(String code, String contentType, int httpCode, HttpExchange he) throws Throwable {
byte[] bytes = code.getBytes("UTF-8");
he.sendResponseHeaders(httpCode, bytes.length);
he.getResponseHeaders().add("Content-Length", String.valueOf(bytes.length));
he.getResponseHeaders().add("Content-Type", contentType + ";charset=utf-8");
he.getResponseBody().write(bytes);
he.getResponseBody().flush();
he.getResponseBody().close();
}
public static Param params(String name, Object value) {
final Map<String, Object> params = new HashMap<String, Object>();
params.put(name, value);
return new Param() {
@Override
public Param param(String name, Object value) {
params.put(name, value);
return this;
}
@Override
public Map<String, Object> get() {
return params;
}
};
}
public static interface Param {
Param param(String name, Object value);
Map<String, Object> get();
}
public static interface Resource {
boolean valid(URI uri, String httpMethod);
void render(HttpExchange he);
}
// IO utils
private static String readFileAsString(File file) {
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
StringBuilder data = readFromBufferedReader(reader);
reader.close();
return new String(data.toString().getBytes(), "utf-8");
} catch (IOException ex) {
throw new RuntimeException("File " + file + " not found.");
}
}
private static StringBuilder readFromBufferedReader(BufferedReader reader) throws IOException {
StringBuilder builder = new StringBuilder();
char[] buffer = new char[BUFFER_SIZE];
int numRead = 0;
while((numRead = reader.read(buffer)) != -1) {
builder.append(String.valueOf(buffer, 0, numRead));
buffer = new char[BUFFER_SIZE];
}
return builder;
}
private static void copyStream(HttpExchange he, InputStream is) throws IOException {
OutputStream os = he.getResponseBody();
byte[] buffer = new byte[8096];
int read = 0;
while ((read = is.read(buffer)) > 0) {
os.write(buffer, 0, read);
}
os.flush();
is.close();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment