Also apply the __toString fix to UserInfo
[cacert-mgr.git] / external / ZendFramework-1.9.5 / externals / dojo / demos / offline / editor / server / org / dojo / moxie / MoxieServlet.java
1 package org.dojo.moxie;
2
3 import java.io.*;
4 import java.net.*;
5 import java.util.*;
6 import java.util.regex.*;
7 import javax.servlet.*;
8 import javax.servlet.http.*;
9
10 /**
11 Exposes a simple RESTian API for working with Moxie documents.
12 The objects we expose are Moxie documents with their filenames:
13
14 /somePageName1
15 /somePageName2
16
17 etc.
18
19 To view a page, simply do a GET on it's page name. If a page
20 does not exist you will get a 404 (Not Found); if it is an incorrect filename
21 you will get a 403 (Forbidden).
22
23 To see a list of all page's, simply do a GET on /*
24
25 If your HTTP client has sent "text/html" as one of the things
26 it accepts in it's Accept header, then a simple HTML page
27 will be returned that uses an unordered list
28 of links to point to all of our pages:
29
30 <html><body>
31 <ul>
32 <li><a href="somePageName1">somePageName1</a></li>
33 <li><a href="somePageName2">somePageName2</a></li>
34 </ul>
35 </body></html>
36
37 If your client doesn't send "text/html" but sends "text/javascript"
38 than we return this list of page names as JSON:
39
40 [
41 "somePageName1", "somePageName2"
42 ]
43
44 To create a new page or update an existing page, do a POST to
45 what the page name will be or is,
46 such as /aNewPage1 or /updateMe. The payload can either be URL encoded form
47 values or can be a simple HTML page. If it is a URL encoded
48 form value, the Content-Type header must be
49 "application/x-www-form-urlencoded"; there should be one form
50 value, with the key name 'content' and the values URL encoded.
51
52 If the payload is a simple HTML page, the Content-Type should
53 be "text/html" and the POSt content can just be plain, normal
54 HTML.
55
56 The server responds with either a 201 (Created); a
57 403 (Forbidden) if the page already exists or has a malformed name,
58 or 200 OK if the update was successful.
59
60 To delete a page, we need to simulate a DELETE request to the / URL
61 of the page name. Safari and Opera have issues with the DELETE method,
62 so we use 'X-Method-Override: DELETE' on these. The server
63 returns a 410 (Gone) request if successful,
64 404 (Not Found) if there was no page there originally, or
65 403 (Not Allowed) if the file name is mangled.
66
67 If clients can correctly send DELETE requests, you can bypass
68 having to send 'X-Method-Override' and simply do a normal DELETE
69 request as outlined above.
70
71 We also expose /download/, called with a GET, which will download
72 a JSON data structure with the contents of all of our documents.
73 This JSON structure is an array of objects, where each object
74 is an object with a 'fileName' member that has the file name
75 of that document, and a 'content' entry with the content of that
76 document. Example:
77
78 [
79 {fileName: "message1", content: "hello world"},
80 {fileName: "message2", content: "goodbye world"}
81 ]
82
83 @author Brad Neuberg, bkn3@columbia.edu
84 */
85 public class MoxieServlet extends HttpServlet{
86 private String jdbcURL, userName, password, driver;
87
88 public MoxieServlet(String jdbcURL, String userName,
89 String password, String driver){
90 this.jdbcURL = jdbcURL;
91 this.userName = userName;
92 this.password = password;
93 this.driver = driver;
94 }
95
96 public void init() throws ServletException{
97 // initialize our database and the class that allows us to
98 // gain access to our documents
99 try{
100 Documents.initialize(jdbcURL, userName, password, driver);
101 }catch(MoxieException e){
102 throw new ServletException(e);
103 }
104 }
105
106 public void doGet(HttpServletRequest req, HttpServletResponse res)
107 throws IOException, ServletException{
108 try{
109 String path = req.getPathInfo();
110 if(path == null){
111 path = "/*";
112 }
113
114 // dispatch our action
115 if(path.equals("/*")){
116 list(req, res);
117 }else if(path.equals("/download") || path.equals("/download")){
118 download(req, res);
119 }else{
120 viewItem(req, res);
121 }
122 }catch(MoxieException e){
123 e.printStackTrace();
124 throw new ServletException(e);
125 }
126 }
127
128 public void doPost(HttpServletRequest req, HttpServletResponse res)
129 throws IOException, ServletException{
130 try{
131 String methodOverride = req.getHeader("X-Method-Override");
132
133 // dispatch our action
134 if(methodOverride == null){
135 updateItem(req, res);
136 }else if(methodOverride.equals("DELETE")){
137 deleteItem(req, res);
138 }
139 }catch(MoxieException e){
140 e.printStackTrace();
141 throw new ServletException(e);
142 }
143 }
144
145 public void doDelete(HttpServletRequest req, HttpServletResponse res)
146 throws IOException, ServletException{
147 try{
148 deleteItem(req, res);
149 }catch(MoxieException e){
150 throw new ServletException(e);
151 }
152 }
153
154 private void viewItem(HttpServletRequest req, HttpServletResponse res)
155 throws IOException, ServletException, MoxieException{
156 // get the file name
157 String fileName = getFileName(req, res);
158
159 // white list the file name
160 if(Document.validFileName(fileName) == false){ // invalid file name
161 // HTTP Status Code 403
162 res.sendError(HttpServletResponse.SC_FORBIDDEN);
163 return;
164 }
165
166 // see if the file exists
167 if(Documents.exists(fileName) == false){
168 // HTTP Status Code 404
169 res.sendError(HttpServletResponse.SC_NOT_FOUND);
170 return;
171 }
172
173 // try to get it
174 Document doc = Documents.findByFileName(fileName);
175 res.setContentType("text/html");
176 PrintWriter out = res.getWriter();
177 out.write(doc.content);
178 }
179
180 private void newItem(HttpServletRequest req, HttpServletResponse res)
181 throws IOException, ServletException, MoxieException{
182 // get the file name
183 String fileName = getFileName(req, res);
184
185 // white list the file name
186 if(Document.validFileName(fileName) == false){ // invalid file name
187 // HTTP Status Code 403
188 res.sendError(HttpServletResponse.SC_FORBIDDEN);
189 return;
190 }
191
192 // populate it's Document values
193 String content = getRequestAsString(req);
194 if(content == null){
195 res.sendError(HttpServletResponse.SC_BAD_REQUEST);
196 return;
197 }
198
199 Document doc = new Document(null, fileName, new Date().getTime(), new Date().getTime(),
200 content);
201
202 // create it
203 Documents.newItem(doc);
204
205 // send back a 201 Created response with the correct
206 // return values
207 res.setStatus(HttpServletResponse.SC_CREATED);
208 res.setHeader("Location", fileName);
209 res.setContentType("text/html");
210 }
211
212 private void deleteItem(HttpServletRequest req, HttpServletResponse res)
213 throws IOException, ServletException, MoxieException{
214 // get the file name
215 String fileName = getFileName(req, res);
216
217 // white list the file name
218 if(Document.validFileName(fileName) == false){ // invalid file name
219 // HTTP Status Code 403
220 res.sendError(HttpServletResponse.SC_FORBIDDEN);
221 return;
222 }
223
224 // see if the file exists
225 if(Documents.exists(fileName) == false){
226 // HTTP Status Code 404
227 res.sendError(HttpServletResponse.SC_NOT_FOUND);
228 return;
229 }
230
231 // get the original document
232 Document doc = Documents.findByFileName(fileName);
233
234 // delete it
235 Documents.deleteItem(doc.getId());
236
237 // send back a 410 Gone response
238 res.setStatus(HttpServletResponse.SC_GONE);
239 }
240
241 private void updateItem(HttpServletRequest req, HttpServletResponse res)
242 throws IOException, ServletException, MoxieException{
243 // get the file name
244 String fileName = getFileName(req, res);
245
246 // white list the file name
247 if(Document.validFileName(fileName) == false){ // invalid file name
248 // HTTP Status Code 403
249 res.sendError(HttpServletResponse.SC_FORBIDDEN);
250 return;
251 }
252
253 // see if the file exists; if it doesn't, we
254 // will create a new document
255 if(Documents.exists(fileName) == false){
256 newItem(req, res);
257 return;
258 }
259
260 // get the original document
261 Document doc = Documents.findByFileName(fileName);
262
263 // get our new content
264 String content = getRequestAsString(req);
265 if(content == null){
266 res.sendError(HttpServletResponse.SC_BAD_REQUEST);
267 return;
268 }
269
270 // update our values
271 doc.setLastUpdated(new Date().getTime());
272 doc.setContent(content);
273
274 // save them
275 Documents.updateItem(doc);
276
277 // send back a 200 OK response with the correct
278 // return values
279 res.setStatus(HttpServletResponse.SC_OK);
280 }
281
282 private void list(HttpServletRequest req, HttpServletResponse res)
283 throws IOException, ServletException, MoxieException{
284 // get our file names
285 List<Document> allDocs = Documents.list();
286
287 // determine what kind of representation to return
288 String accepts = req.getHeader("Accept");
289 if(accepts == null
290 || accepts.indexOf("text/html") != -1){ // return HTML
291 listReturnHTML(allDocs, req, res);
292 }else{
293 listReturnJSON(allDocs, req, res);
294 }
295 }
296
297 private void download(HttpServletRequest req, HttpServletResponse res)
298 throws IOException, ServletException, MoxieException{
299 // get our file names
300 List<Document> allDocs = Documents.list();
301
302 // send our JSON response back
303 res.setContentType("text/javascript");
304 PrintWriter out = res.getWriter();
305
306 out.write("[\n");
307
308 // loop through each document
309 Iterator<Document> iter = allDocs.iterator();
310 while(iter.hasNext()){
311 Document d = iter.next();
312 out.write("{");
313
314 // FIXME: Use a real JSON serialization library
315 // write out the file name
316 out.write("fileName: \"" + d.fileName + "\", ");
317
318 // escape our double quotes
319 Pattern quotePattern = Pattern.compile("[\"]", Pattern.MULTILINE);
320 Matcher m = quotePattern.matcher(d.content);
321 String content = m.replaceAll("\\\\\"");
322
323 // escape multi line strings
324 Pattern linePattern = Pattern.compile("\n|\r", Pattern.MULTILINE);
325 m = linePattern.matcher(content);
326 content = m.replaceAll("\\\\\n");
327
328 // write out our contents
329 out.write("content: \"" + content + "\"");
330
331 out.write("}");
332
333 // add a comma if we are not the last one
334 if(iter.hasNext() == true){
335 out.write(", \n");
336 }else{
337 out.write("\n");
338 }
339 }
340
341 out.write("]\n");
342 }
343
344 private String getFileName(HttpServletRequest req, HttpServletResponse res)
345 throws MoxieException{
346 // get the file to view
347 String fileName = req.getPathInfo();
348
349 // strip off the leading slash
350 fileName = fileName.substring(1);
351
352 return fileName;
353 }
354
355 private String getRequestAsString(HttpServletRequest req)
356 throws IOException{
357 // correctly decode this value
358 String contentType = req.getHeader("Content-Type");
359 if(contentType != null && contentType.equals("text/html")){
360 // basic HTML in POST payload
361
362 // FIXME: WARNING: The combination of a wrapped InputStream being
363 // treated as a reader, with the deprecated readLine() method below
364 // might mangle i18n text
365 BufferedReader requestData = new BufferedReader(
366 new InputStreamReader(req.getInputStream()));
367 StringBuffer stringBuffer = new StringBuffer();
368 String line;
369 while ((line = requestData.readLine()) != null){
370 stringBuffer.append(line);
371 }
372
373 String content = stringBuffer.toString();
374 return content;
375 }else{ // encoded form values -- application/x-www-form-urlencoded
376 String content = req.getParameter("content");
377
378 return content;
379 }
380 }
381
382 private void listReturnHTML(List<Document> allDocs,
383 HttpServletRequest req,
384 HttpServletResponse res)
385 throws IOException, ServletException, MoxieException{
386 res.setContentType("text/html");
387 PrintWriter out = res.getWriter();
388 out.write("<html><body><ul>");
389
390 // loop through each file name and write it out as an A tag
391 Iterator<Document> iter = allDocs.iterator();
392 while(iter.hasNext()){
393 Document d = iter.next();
394 out.write("<li><a href=\"" + d.fileName + "\">"
395 + d.fileName + "</a></li>");
396 }
397 out.write("</ul></body></html>");
398 }
399
400 private void listReturnJSON(List<Document> allDocs,
401 HttpServletRequest req,
402 HttpServletResponse res)
403 throws IOException, ServletException, MoxieException{
404 res.setContentType("text/javascript");
405 PrintWriter out = res.getWriter();
406
407 out.write("[");
408
409 // loop through each file name and write it out as an A tag
410 Iterator<Document> iter = allDocs.iterator();
411 while(iter.hasNext()){
412 Document d = iter.next();
413 // FIXME: Use a real JSON serialization library
414 out.write("\"" + d.fileName + "\"");
415 if(iter.hasNext() == true){
416 out.write(", \n");
417 }
418 }
419
420 out.write("]\n");
421 }
422
423 }