Source Code Cross Referenced for HTTPQueryHandler.java in  » Web-Services » xins » org » xins » common » servlet » container » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Services » xins » org.xins.common.servlet.container 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $Id: HTTPQueryHandler.java,v 1.4 2007/09/18 08:45:08 agoubard Exp $
003:         *
004:         * Copyright 2003-2007 Orange Nederland Breedband B.V.
005:         * See the COPYRIGHT file for redistribution and use restrictions.
006:         */
007:        package org.xins.common.servlet.container;
008:
009:        import java.io.BufferedReader;
010:        import java.io.ByteArrayOutputStream;
011:        import java.io.IOException;
012:        import java.io.InputStream;
013:        import java.io.InputStreamReader;
014:        import java.io.OutputStream;
015:        import java.net.FileNameMap;
016:        import java.net.Socket;
017:        import java.net.URLConnection;
018:        import java.util.HashMap;
019:        import java.util.Iterator;
020:        import java.util.Map;
021:
022:        import org.apache.commons.httpclient.HttpStatus;
023:
024:        import org.xins.common.MandatoryArgumentChecker;
025:        import org.xins.common.Utils;
026:        import org.xins.common.collections.PropertyReader;
027:        import org.xins.common.text.ParseException;
028:
029:        /**
030:         * HTTP query received to be handled by the servlet.
031:         *
032:         * @version $Revision: 1.4 $ $Date: 2007/09/18 08:45:08 $
033:         * @author <a href="mailto:anthony.goubard@japplis.com">Anthony Goubard</a>
034:         * @author <a href="mailto:ernst@ernstdehaan.com">Ernst de Haan</a>
035:         */
036:        class HTTPQueryHandler extends Thread {
037:
038:            /**
039:             * The encoding of the request.
040:             */
041:            private static final String REQUEST_ENCODING = "ISO-8859-1";
042:
043:            /**
044:             * The map containing the MIME type information. Never <code>null</code>
045:             */
046:            private static final FileNameMap MIME_TYPES_MAP = URLConnection
047:                    .getFileNameMap();
048:
049:            /**
050:             * The line separator used by the HTTP protocol.
051:             */
052:            private static final String CRLF = "\r\n";
053:
054:            /**
055:             * The instance number for this created query.
056:             */
057:            private static int _instanceNumber = 0;
058:
059:            /**
060:             * The socket of the HTTP query.
061:             */
062:            private final Socket _client;
063:
064:            /**
065:             * Mapping between the path and the servlet.
066:             */
067:            private final Map _servlets;
068:
069:            /**
070:             * Creates a new HTTPQueryHandler to handle the HTTP query sent by the client.
071:             *
072:             * @param client
073:             *    the connection with the client, cannot be <code>null</code>.
074:             *
075:             * @param servlets
076:             *    the mapping between the path and the servlets, cannot be <code>null</code>.
077:             *
078:             * @throws IllegalArgumentException
079:             *    if <code>client == null || servlets == null</code>.
080:             */
081:            public HTTPQueryHandler(Socket client, Map servlets)
082:                    throws IllegalArgumentException {
083:
084:                // Check argument
085:                MandatoryArgumentChecker.check("client", client, "servlets",
086:                        servlets);
087:
088:                _client = client;
089:                _servlets = servlets;
090:                synchronized (servlets) {
091:                    _instanceNumber++;
092:                }
093:                setName("XINS Query handler #" + _instanceNumber);
094:            }
095:
096:            public void run() {
097:                try {
098:                    serviceClient(_client);
099:                } catch (Exception ex) {
100:
101:                    // If anything goes wrong still continue accepting clients
102:                    Utils.logIgnoredException(ex);
103:                } finally {
104:                    try {
105:                        _client.close();
106:                    } catch (Throwable exception) {
107:                        // ignore
108:                    }
109:                }
110:            }
111:
112:            /**
113:             * This method is invoked when a client connects to the server.
114:             *
115:             * @param client
116:             *    the connection with the client, cannot be <code>null</code>.
117:             *
118:             * @throws IllegalArgumentException
119:             *    if <code>client == null</code>.
120:             *
121:             * @throws IOException
122:             *    if the query is not handled correctly.
123:             */
124:            public void serviceClient(Socket client)
125:                    throws IllegalArgumentException, IOException {
126:
127:                // Check argument
128:                MandatoryArgumentChecker.check("client", client);
129:
130:                InputStream inbound = client.getInputStream();
131:                OutputStream outbound = client.getOutputStream();
132:
133:                // Delegate to httpQuery in a way it does not have to bother with
134:                // closing the streams
135:                try {
136:                    httpQuery(inbound, outbound);
137:
138:                    // Clean up for httpQuery, if necessary
139:                } finally {
140:                    if (inbound != null) {
141:                        try {
142:                            inbound.close();
143:                        } catch (Throwable exception) {
144:                            Utils.logIgnoredException(exception);
145:                        }
146:                    }
147:                    if (outbound != null) {
148:                        try {
149:                            outbound.close();
150:                        } catch (Throwable exception) {
151:                            Utils.logIgnoredException(exception);
152:                        }
153:                    }
154:                }
155:            }
156:
157:            /**
158:             * This method parses the data sent from the client to get the input
159:             * parameters and format the result as a compatible HTTP result.
160:             * This method will used the servlet associated with the passed virtual
161:             * path. If no servlet is associated with the virtual path, the servlet with
162:             * the virtual path "/" is used as default. If there is no servlet then with
163:             * the virtual path "/" is found then HTTP 404 is returned.
164:             *
165:             * @param in
166:             *    the input byte stream that contains the request sent by the client.
167:             *
168:             * @param out
169:             *    the output byte stream that must be fed the response towards the
170:             *    client.
171:             *
172:             * @throws IOException
173:             *    if the query is not handled correctly.
174:             *
175:             * @since XINS 1.5.0.
176:             */
177:            public void httpQuery(InputStream in, OutputStream out)
178:                    throws IOException {
179:
180:                // Read the input
181:                // XXX: Buffer size determines maximum request size
182:                char[] buffer = new char[16384];
183:                BufferedReader inReader = new BufferedReader(
184:                        new InputStreamReader(in, REQUEST_ENCODING));
185:                int lengthRead = inReader.read(buffer);
186:                if (lengthRead < 0) {
187:                    sendBadRequest(out);
188:                    return;
189:                }
190:                String request = new String(buffer, 0, lengthRead);
191:                //byte[] requestBytes = IOReader.readFullyAsBytes(in);
192:                //String request = new String(requestBytes, 0, requestBytes.length, REQUEST_ENCODING);
193:
194:                // Read the first line
195:                int eolIndex = request.indexOf(CRLF);
196:                if (eolIndex < 0) {
197:                    sendBadRequest(out);
198:                    return;
199:                }
200:
201:                // The first line must end with "HTTP/1.0" or "HTTP/1.1"
202:                String line = request.substring(0, eolIndex);
203:                request = request.substring(eolIndex + 2);
204:                if (!(line.endsWith(" HTTP/1.1") || line.endsWith(" HTTP/1.0"))) {
205:                    sendBadRequest(out);
206:                    return;
207:                }
208:
209:                // Cut off the last part
210:                line = line.substring(0, line.length() - 9);
211:
212:                // Find the space
213:                int spaceIndex = line.indexOf(' ');
214:                if (spaceIndex < 1) {
215:                    sendBadRequest(out);
216:                    return;
217:                }
218:
219:                // Determine the method
220:                String method = line.substring(0, spaceIndex);
221:
222:                // Determine the query string
223:                String url = line.substring(spaceIndex + 1);
224:                if ("".equals(url)) {
225:                    sendBadRequest(out);
226:                    return;
227:                } else if ("GET".equals(method) || "HEAD".equals(method)
228:                        || "OPTIONS".equals(method)) {
229:                    url = url.replace(',', '&');
230:                }
231:
232:                // Normalize the query string
233:                if ("GET".equals(method) && url.endsWith("/")
234:                        && getClass().getResource(url + "index.html") != null) {
235:                    url += "index.html";
236:                }
237:
238:                // Read the headers
239:                HashMap inHeaders = new HashMap();
240:                boolean done = false;
241:                while (!done) {
242:                    int nextEOL = request.indexOf(CRLF);
243:                    if (nextEOL <= 0) {
244:                        done = true;
245:                    } else {
246:                        try {
247:                            parseHeader(inHeaders, request
248:                                    .substring(0, nextEOL));
249:                        } catch (ParseException exception) {
250:                            sendBadRequest(out);
251:                            return;
252:                        }
253:                        request = request.substring(nextEOL + 2);
254:                    }
255:                }
256:
257:                // Determine the body contents
258:                String body = "".equals(request) ? "" : request.substring(2);
259:
260:                // Response encoding defaults to request encoding
261:                String responseEncoding = REQUEST_ENCODING;
262:
263:                // Handle the case that a web page is requested
264:                boolean getMethod = method.equals("GET")
265:                        || method.equals("HEAD");
266:                String httpResult;
267:                if (getMethod && url.indexOf('?') == -1 && !url.endsWith("/")
268:                        && !"*".equals(url)) {
269:                    httpResult = readWebPage(url);
270:
271:                    // No web page requested
272:                } else {
273:
274:                    // Determine the content type
275:                    String inContentType = getHeader(inHeaders, "Content-Type");
276:
277:                    // If www-form encoded, then append the body to the query string
278:                    if ((inContentType == null || inContentType
279:                            .startsWith("application/x-www-form-urlencoded"))
280:                            && body.length() > 0) {
281:                        // XXX: What if the URL already contains a question mark?
282:                        url += '?' + body;
283:                        body = null;
284:                    }
285:
286:                    // Locate the path of the URL
287:                    String virtualPath = url;
288:                    if (virtualPath.indexOf('?') != -1) {
289:                        virtualPath = virtualPath
290:                                .substring(0, url.indexOf('?'));
291:                    }
292:                    if (virtualPath.endsWith("/") && virtualPath.length() > 1) {
293:                        virtualPath = virtualPath.substring(0, virtualPath
294:                                .length() - 1);
295:                    }
296:
297:                    // Get the Servlet according to the path
298:                    LocalServletHandler servlet = findServlet(virtualPath);
299:
300:                    // If no servlet is found return 404
301:                    if (servlet == null) {
302:                        sendError(out, "404 Not Found");
303:                        return;
304:                    } else {
305:
306:                        // Query the Servlet
307:                        XINSServletResponse response = servlet.query(method,
308:                                url, body, inHeaders);
309:
310:                        // Create the HTTP answer
311:                        StringBuffer sbHttpResult = new StringBuffer();
312:                        sbHttpResult.append("HTTP/1.1 "
313:                                + response.getStatus()
314:                                + " "
315:                                + HttpStatus
316:                                        .getStatusText(response.getStatus())
317:                                + CRLF);
318:                        PropertyReader outHeaders = response.getHeaders();
319:                        Iterator itHeaderNames = outHeaders.getNames();
320:                        while (itHeaderNames.hasNext()) {
321:                            String nextHeader = (String) itHeaderNames.next();
322:                            String headerValue = outHeaders.get(nextHeader);
323:                            if (headerValue != null) {
324:                                sbHttpResult.append(nextHeader + ": "
325:                                        + headerValue + "\r\n");
326:                            }
327:                        }
328:
329:                        String result = response.getResult();
330:                        if (result != null) {
331:                            responseEncoding = response.getCharacterEncoding();
332:                            int length = response.getContentLength();
333:                            if (length < 0) {
334:                                length = result.getBytes(responseEncoding).length;
335:                            }
336:                            sbHttpResult.append("Content-Length: " + length
337:                                    + "\r\n");
338:                            sbHttpResult.append("Connection: close\r\n");
339:                            sbHttpResult.append("\r\n");
340:                            sbHttpResult.append(result);
341:                        }
342:                        httpResult = sbHttpResult.toString();
343:                    }
344:                }
345:
346:                byte[] bytes = httpResult.getBytes(responseEncoding);
347:                out.write(bytes, 0, bytes.length);
348:                out.flush();
349:            }
350:
351:            /**
352:             * Finds the servlet that should handle a request at the specified virtual
353:             * path.
354:             *
355:             * @param path
356:             *    the virtual path, cannot be <code>null</code>.
357:             *
358:             * @return
359:             *    the servlet that was found, or <code>null</code> if none was found.
360:             *
361:             * @throws NullPointerException
362:             *    if <code>path == null</code>.
363:             */
364:            private LocalServletHandler findServlet(String path)
365:                    throws NullPointerException {
366:
367:                // Special case is path "*"
368:                if ("*".equals(path)) {
369:                    path = "/";
370:                }
371:
372:                // If the path does not end with a slash, then add one,
373:                // to avoid checking that option
374:                if (path.charAt(path.length() - 1) != '/') {
375:                    path += '/';
376:                }
377:
378:                LocalServletHandler servlet;
379:                do {
380:
381:                    // Find a servlet at this path
382:                    servlet = (LocalServletHandler) _servlets.get(path);
383:
384:                    // If not found, then strip off the last part of the path
385:                    // E.g. "/objects/boats/Cherry"  becomes "/objects/boats/"
386:                    // and  "/objects/boats/Cherry/" becomes "/objects/boats/"
387:                    if (servlet == null) {
388:
389:                        // Remove the trailing slash, if any
390:                        int lastPos = path.length() - 1;
391:                        if (path.charAt(lastPos) == '/') {
392:                            path = path.substring(0, lastPos);
393:                        }
394:
395:                        // Cut up until and including the last slash, if appropriate
396:                        if (path.length() > 0) {
397:                            int i = path.lastIndexOf('/');
398:                            path = path.substring(0, i + 1);
399:                        }
400:                    }
401:
402:                } while (servlet == null && path.length() > 0);
403:
404:                return servlet;
405:            }
406:
407:            /**
408:             * Sends an HTTP error back to the client.
409:             *
410:             * @param out
411:             *    the output stream to contact the client.
412:             *
413:             * @param status
414:             *    the HTTP error code status.
415:             *
416:             * @throws IOException
417:             *    if the error cannot be sent.
418:             */
419:            private void sendError(OutputStream out, String status)
420:                    throws IOException {
421:                String httpResult = "HTTP/1.1 " + status + CRLF + CRLF;
422:                byte[] bytes = httpResult.getBytes(REQUEST_ENCODING);
423:                out.write(bytes, 0, bytes.length);
424:                out.flush();
425:            }
426:
427:            /**
428:             * Sends an HTTP bad request back to the client.
429:             *
430:             * @param out
431:             *    the output stream to contact the client.
432:             *
433:             * @throws IOException
434:             *    if the error cannot be sent.
435:             */
436:            private void sendBadRequest(OutputStream out) throws IOException {
437:                sendError(out, "400 Bad Request");
438:            }
439:
440:            /**
441:             * Parses an HTTP header.
442:             *
443:             * @param headers
444:             *    the headers already collected.
445:             *
446:             * @param header
447:             *    the line of the header to be parsed.
448:             *
449:             * @throws ParseException
450:             *    if the header is incorrect
451:             */
452:            private static void parseHeader(HashMap headers, String header)
453:                    throws ParseException {
454:                int index = header.indexOf(':');
455:                if (index < 1) {
456:                    throw new ParseException();
457:                }
458:
459:                // Get key and value
460:                String key = header.substring(0, index);
461:                String value = header.substring(index + 1);
462:
463:                // Always convert the key to upper case
464:                key = key.toUpperCase();
465:
466:                // Always trim the value
467:                value = value.trim();
468:
469:                // XXX: Only one header supported
470:                if (headers.get(key) != null) {
471:                    throw new ParseException();
472:                }
473:
474:                // Store the key-value combo
475:                headers.put(key, value);
476:            }
477:
478:            /**
479:             * Gets a HTTP header from the request.
480:             *
481:             * @param headers
482:             *    the list of the headers.
483:             *
484:             * @param key
485:             *    the name of the header.
486:             *
487:             * @return
488:             *    the header value for the specified key or <code>null</code> if the
489:             *    key is not in the haeders.
490:             */
491:            String getHeader(HashMap headers, String key) {
492:                return (String) headers.get(key.toUpperCase());
493:            }
494:
495:            /**
496:             * Reads the content of a web page.
497:             *
498:             * @param url
499:             *    the location of the content, cannot be <code>null</code>.
500:             *
501:             * @return
502:             *    the HTTP response to return, never <code>null</code>.
503:             *
504:             * @throws IOException
505:             *    if an error occcurs when reading the URL.
506:             */
507:            private String readWebPage(String url) throws IOException {
508:                String httpResult;
509:                if (getClass().getResource(url) != null) {
510:                    InputStream urlInputStream = getClass()
511:                            .getResourceAsStream(url);
512:                    ByteArrayOutputStream contentOutputStream = new ByteArrayOutputStream();
513:                    byte[] buf = new byte[8192];
514:                    int len;
515:                    while ((len = urlInputStream.read(buf)) > 0) {
516:                        contentOutputStream.write(buf, 0, len);
517:                    }
518:                    contentOutputStream.close();
519:                    urlInputStream.close();
520:                    String content = contentOutputStream.toString("ISO-8859-1");
521:
522:                    httpResult = "HTTP/1.1 200 OK\r\n";
523:                    String fileName = url.substring(url.lastIndexOf('/') + 1);
524:                    httpResult += "Content-Type: "
525:                            + MIME_TYPES_MAP.getContentTypeFor(fileName)
526:                            + "\r\n";
527:                    int length = content.getBytes("ISO-8859-1").length;
528:                    httpResult += "Content-Length: " + length + "\r\n";
529:                    httpResult += "Connection: close\r\n";
530:                    httpResult += "\r\n";
531:                    httpResult += content;
532:                } else {
533:                    httpResult = "HTTP/1.1 404 Not Found\r\n";
534:                }
535:                return httpResult;
536:            }
537:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.