Skip to content

Commit 6ff1c74

Browse files
author
Moises Trovo
committed
added common MIME extensions via properties file; changed exception handling to global within method so every request has the chance to print stacktrace friendly; added some error friendly pages support (404.html and 500.html)
1 parent 09b6c1c commit 6ff1c74

1 file changed

Lines changed: 147 additions & 80 deletions

File tree

handlebar/src/main/java/com/sampullara/mustache/Handlebar.java

Lines changed: 147 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,46 @@
11
package com.sampullara.mustache;
22

3-
import com.github.mustachejava.DefaultMustacheFactory;
4-
import com.github.mustachejava.Mustache;
5-
import com.github.mustachejava.MustacheException;
6-
import com.github.mustachejava.MustacheFactory;
7-
import com.sampullara.cli.Args;
8-
import com.sampullara.cli.Argument;
3+
import java.io.BufferedInputStream;
4+
import java.io.BufferedReader;
5+
import java.io.File;
6+
import java.io.FileInputStream;
7+
import java.io.FileNotFoundException;
8+
import java.io.IOException;
9+
import java.io.InputStream;
10+
import java.io.InputStreamReader;
11+
import java.io.OutputStream;
12+
import java.io.PrintWriter;
13+
import java.io.StringWriter;
14+
import java.io.UnsupportedEncodingException;
15+
import java.util.ArrayList;
16+
import java.util.Arrays;
17+
import java.util.HashMap;
18+
import java.util.Iterator;
19+
import java.util.List;
20+
import java.util.Map;
21+
22+
import javax.activation.FileTypeMap;
23+
import javax.activation.MimetypesFileTypeMap;
24+
import javax.servlet.ServletException;
25+
import javax.servlet.http.HttpServletRequest;
26+
import javax.servlet.http.HttpServletResponse;
27+
928
import org.codehaus.jackson.JsonFactory;
1029
import org.codehaus.jackson.JsonNode;
30+
import org.codehaus.jackson.JsonParseException;
1131
import org.codehaus.jackson.JsonParser;
32+
import org.codehaus.jackson.JsonProcessingException;
1233
import org.codehaus.jackson.map.MappingJsonFactory;
1334
import org.eclipse.jetty.server.Handler;
1435
import org.eclipse.jetty.server.Request;
1536
import org.eclipse.jetty.server.Server;
1637
import org.eclipse.jetty.server.handler.AbstractHandler;
1738

18-
import javax.servlet.ServletException;
19-
import javax.servlet.http.HttpServletRequest;
20-
import javax.servlet.http.HttpServletResponse;
21-
import java.io.*;
22-
import java.util.ArrayList;
23-
import java.util.HashMap;
24-
import java.util.Iterator;
25-
import java.util.Map;
39+
import com.github.mustachejava.DefaultMustacheFactory;
40+
import com.github.mustachejava.Mustache;
41+
import com.github.mustachejava.MustacheFactory;
42+
import com.sampullara.cli.Args;
43+
import com.sampullara.cli.Argument;
2644

2745
/**
2846
* Run a local server and merge .js and .html files using mustache.
@@ -42,17 +60,21 @@ public class Handlebar {
4260

4361
private static File rootDir;
4462

45-
private static final JsonFactory JSON_FACTORY = new MappingJsonFactory();
63+
private static final FileTypeMap FILE_TYPE_MAP;
4664

65+
private static final JsonFactory JSON_FACTORY = new MappingJsonFactory();
4766

48-
private static Map<String, String> mimeTypes = new HashMap<String, String>();
4967
static {
50-
mimeTypes.put("html", "text/html");
51-
mimeTypes.put("png", "image/png");
52-
mimeTypes.put("gif", "image/gif");
53-
mimeTypes.put("jpg", "image/jpg");
54-
mimeTypes.put("js", "text/javascript");
55-
mimeTypes.put("css", "text/css");
68+
FILE_TYPE_MAP = loadFileTypeMapFromContextSupportModule();
69+
}
70+
71+
private static FileTypeMap loadFileTypeMapFromContextSupportModule() {
72+
// see if we can find the extended mime.types from the context-support module
73+
InputStream is = ClassLoader.getSystemResourceAsStream("com/sampullara/mustache/mimes.txt");
74+
if (null != is) {
75+
return new MimetypesFileTypeMap(is);
76+
}
77+
return FileTypeMap.getDefaultFileTypeMap();
5678
}
5779

5880
public static Object toObject(final JsonNode node) {
@@ -98,70 +120,115 @@ public static void main(String[] args) throws Exception {
98120
Handler handler = new AbstractHandler() {
99121
public void handle(String s, Request r, HttpServletRequest req, HttpServletResponse res)
100122
throws IOException, ServletException {
101-
String pathInfo = req.getPathInfo();
102-
103-
if (pathInfo.endsWith("/")) pathInfo += "index.html";
104-
105-
String extension = pathInfo.substring(pathInfo.lastIndexOf(".") + 1);
106-
String base = pathInfo.substring(0, pathInfo.lastIndexOf("."));
107-
String mimeType = mimeTypes.get(extension);
108-
109-
// create a handle to the resource
110-
File staticres = new File(rootDir, pathInfo.substring(1));
111-
112-
res.setContentType(mimeType == null ? "text/html" : mimeType);
113-
res.setCharacterEncoding("utf-8");
114-
if (mimeType == null || mimeType.equals("text/html")) {
115-
// Handle like a template
116-
String filename = pathInfo.substring(1);
117-
try {
118-
MustacheFactory mc = new DefaultMustacheFactory(new File("."));
119-
Mustache mustache = mc.compile(filename);
120-
File file = new File(mocks, base + ".json");
121-
res.setStatus(HttpServletResponse.SC_OK);
122-
Map parameters = new HashMap<Object, Object>(req.getParameterMap()) {
123-
@Override
124-
public Object get(Object o) {
125-
Object result = super.get(o); // To change body of overridden methods use File |
126-
// Settings | File Templates.
127-
if (result instanceof String[]) {
128-
String[] strings = (String[]) result;
129-
if (strings.length == 1) {
130-
return strings[0];
131-
}
132-
}
133-
return result;
134-
}
135-
};
136-
137-
if (file.exists()) {
138-
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
139-
JsonParser parser = JSON_FACTORY.createJsonParser(br);
140-
JsonNode json = parser.readValueAsTree();
141-
br.close();
142-
mustache.execute(res.getWriter(), new Object[] {toObject(json), parameters});
123+
try {
124+
String pathInfo = req.getPathInfo();
125+
if (pathInfo.endsWith("/")) pathInfo += "index.html";
126+
127+
// obtain mime type
128+
String mimeType = FILE_TYPE_MAP.getContentType(pathInfo);
129+
System.out.println(String.format("%s: %s", mimeType, pathInfo));
130+
131+
// create a handle to the resource
132+
File staticres = new File(rootDir, pathInfo.substring(1));
133+
134+
res.setContentType(mimeType == null ? "text/html" : mimeType);
135+
res.setCharacterEncoding("utf-8");
136+
if (mimeType == null || mimeType.equals("text/html")) {
137+
138+
// Handle like a template
139+
String filename = pathInfo.substring(1);
140+
141+
// check if file exists
142+
if (!staticres.exists()) {
143+
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
144+
processTemplate(req, res, "404.html");
143145
} else {
144-
mustache.execute(res.getWriter(), parameters);
146+
res.setStatus(HttpServletResponse.SC_OK);
147+
processTemplate(req, res, filename);
145148
}
149+
146150
r.setHandled(true);
147-
} catch (MustacheException e) {
148-
e.printStackTrace(res.getWriter());
149-
r.setHandled(true);
150-
res.setStatus(500);
151+
} else {
152+
if (!staticres.exists()) {
153+
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
154+
return;
155+
}
156+
157+
// Handle like a file
158+
res.setStatus(HttpServletResponse.SC_OK);
159+
OutputStream os = res.getOutputStream();
160+
byte[] bytes = new byte[8192];
161+
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(staticres));
162+
int read;
163+
while ((read = bis.read(bytes)) != -1) {
164+
os.write(bytes, 0, read);
165+
}
166+
os.close();
151167
}
152-
} else {
153-
// Handle like a file
154-
res.setStatus(HttpServletResponse.SC_OK);
155-
OutputStream os = res.getOutputStream();
156-
byte[] bytes = new byte[8192];
157-
BufferedInputStream bis =
158-
new BufferedInputStream(new FileInputStream(pathInfo.substring(1)));
159-
int read;
160-
while ((read = bis.read(bytes)) != -1) {
161-
os.write(bytes, 0, read);
168+
} catch (Exception e) {
169+
// building stacktrace string
170+
StringWriter str = new StringWriter();
171+
e.printStackTrace(new PrintWriter(str));
172+
String stack = simpleEscape(str.toString());
173+
174+
// params
175+
Map<String, String> params = new HashMap<String, String>();
176+
params.put("stacktrace", stack);
177+
178+
// render template
179+
res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
180+
processTemplate(req, res, "500.html", params);
181+
182+
r.setHandled(true);
183+
}
184+
}
185+
186+
private void processTemplate(HttpServletRequest req, HttpServletResponse res,
187+
String filename, Object... scopes) throws UnsupportedEncodingException,
188+
FileNotFoundException, IOException, JsonParseException, JsonProcessingException {
189+
190+
if (!new File(rootDir, filename).exists()) {
191+
System.out.println("template not found, skipping: " + filename);
192+
return;
193+
}
194+
195+
MustacheFactory mc = new DefaultMustacheFactory(rootDir);
196+
Mustache mustache = mc.compile(filename);
197+
198+
String base = filename.substring(0, filename.lastIndexOf("."));
199+
File file = new File(mocks, base + ".json");
200+
Map parameters = new HashMap<Object, Object>(req.getParameterMap()) {
201+
@Override
202+
public Object get(Object o) {
203+
Object result = super.get(o); // To change body of overridden methods use File |
204+
// Settings | File Templates.
205+
if (result instanceof String[]) {
206+
String[] strings = (String[]) result;
207+
if (strings.length == 1) {
208+
return strings[0];
209+
}
210+
}
211+
return result;
162212
}
163-
os.close();
213+
};
214+
215+
List<Object> scs = new ArrayList<Object>();
216+
if (null != scopes) scs.addAll(Arrays.<Object>asList(scopes));
217+
scs.add(parameters);
218+
219+
if (file.exists()) {
220+
BufferedReader br =
221+
new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
222+
JsonParser parser = JSON_FACTORY.createJsonParser(br);
223+
JsonNode json = parser.readValueAsTree();
224+
br.close();
225+
scs.add(0, toObject(json));
164226
}
227+
mustache.execute(res.getWriter(), scs.toArray());
228+
}
229+
230+
private String simpleEscape(String string) {
231+
return string.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;");
165232
}
166233
};
167234

0 commit comments

Comments
 (0)