Created
January 13, 2012 09:25
-
-
Save mathieuancelin/1605266 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title>Hello World</title> | |
</head> | |
<body> | |
<h1>Hello ${name}!</h1> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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