001: /*
002: * $Id: XINSServletRequest.java,v 1.41 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.ByteArrayInputStream;
011: import java.io.IOException;
012: import java.io.StringReader;
013: import java.io.UnsupportedEncodingException;
014: import java.net.InetAddress;
015: import java.net.UnknownHostException;
016: import java.security.Principal;
017: import java.util.ArrayList;
018: import java.util.Collections;
019: import java.util.Enumeration;
020: import java.util.HashMap;
021: import java.util.Hashtable;
022: import java.util.Locale;
023: import java.util.Map;
024: import java.util.StringTokenizer;
025:
026: import javax.servlet.RequestDispatcher;
027: import javax.servlet.ServletInputStream;
028: import javax.servlet.http.Cookie;
029: import javax.servlet.http.HttpServletRequest;
030: import javax.servlet.http.HttpSession;
031:
032: import org.xins.common.text.FormatException;
033: import org.xins.common.text.URLEncoding;
034:
035: /**
036: * This class is an implementation of the HTTPServletRequest that can be
037: * called localy.
038: *
039: * @version $Revision: 1.41 $ $Date: 2007/09/18 08:45:08 $
040: * @author <a href="mailto:anthony.goubard@japplis.com">Anthony Goubard</a>
041: */
042: public class XINSServletRequest implements HttpServletRequest {
043:
044: /**
045: * The localhost name.
046: */
047: private static String LOCALHOST_NAME;
048:
049: /**
050: * The localhost address.
051: */
052: private static String LOCALHOST_ADDRESS;
053:
054: /**
055: * The HTTP sessions of the servlet container.
056: */
057: private static Map SESSIONS = new HashMap();
058:
059: /**
060: * The HTTP request method.
061: */
062: private final String _method;
063:
064: /**
065: * The requested URL including the optional parameters.
066: */
067: private final String _url;
068:
069: /**
070: * The parameters retrieved from the URL.
071: */
072: private HashMap _parameters = new HashMap();
073:
074: /**
075: * The date when the request was created.
076: */
077: private long _date = System.currentTimeMillis();
078:
079: /**
080: * The attributes of the request.
081: */
082: private Hashtable _attributes = new Hashtable();
083:
084: /**
085: * The HTTP headers of the request.
086: */
087: private Hashtable _headers = new Hashtable();
088:
089: /**
090: * The URL path.
091: */
092: private String _pathInfo;
093:
094: /**
095: * The URL query string.
096: */
097: private String _queryString;
098:
099: /**
100: * The content type of the query.
101: */
102: private String _contentType;
103:
104: /**
105: * The content of the HTTP POST.
106: */
107: private String _postData;
108:
109: /**
110: * The cookies of the request.
111: */
112: private Cookie[] _cookies;
113:
114: /**
115: * Flags indicating that the input stream has been used.
116: */
117: private boolean _inputStreamUsed = false;
118:
119: /**
120: * Flags indicating that the reader has been used.
121: */
122: private boolean _readerUsed = false;
123:
124: /**
125: * Flags indicating that the reader has been used.
126: */
127: private String _characterEncoding;
128:
129: static {
130: try {
131: LOCALHOST_ADDRESS = InetAddress.getLocalHost()
132: .getHostAddress();
133: } catch (UnknownHostException exception) {
134: LOCALHOST_ADDRESS = "127.0.0.1";
135: }
136: try {
137: LOCALHOST_NAME = InetAddress.getLocalHost().getHostName();
138: } catch (UnknownHostException exception) {
139: LOCALHOST_NAME = "localhost";
140: }
141: }
142:
143: /**
144: * Creates a new Servlet request.
145: *
146: * @param url
147: * the request URL or the list of the parameters (name=value) separated
148: * with comma's. Cannot be <code>null</code>.
149: */
150: public XINSServletRequest(String url) {
151: this ("GET", url, null, null);
152: }
153:
154: /**
155: * Creates a new servlet request with the specified method.
156: *
157: * @param method
158: * the request method, cannot be <code>null</code>.
159: *
160: * @param url
161: * the request URL or the list of the parameters (name=value) separated
162: * with ampersands, cannot be <code>null</code>.
163: *
164: * @param data
165: * the content of the request, can be <code>null</code>.
166: *
167: * @param headers
168: * the HTTP headers of the request. The key and the value of the Map
169: * is a String. The keys should all be in upper case. Can be <code>null</code>.
170: *
171: * @since XINS 1.5.0
172: */
173: public XINSServletRequest(String method, String url, String data,
174: Map headers) {
175: _method = method;
176: _url = url;
177: _postData = data;
178: if (headers == null) {
179: _contentType = "application/x-www-form-urlencoded";
180: } else {
181: _headers.putAll(headers);
182: _contentType = (String) headers.get("CONTENT-TYPE");
183: }
184: parseURL(url);
185: }
186:
187: /**
188: * Parses the url to extract the parameters.
189: *
190: * @param url
191: * the request URL or the list of the parameters (name=value) separated
192: * with ampersands.
193: */
194: private void parseURL(String url) {
195:
196: // Parse the URL
197: int doubleSlashPos = url.lastIndexOf("://");
198: int startPathPos = url.indexOf("/", doubleSlashPos + 1) + 1;
199:
200: int questionMarkPos = url.lastIndexOf('?');
201: if (questionMarkPos == url.length() - 1) {
202: _queryString = "";
203: if (startPathPos < questionMarkPos) {
204: _pathInfo = url
205: .substring(startPathPos, questionMarkPos);
206: }
207: } else if (questionMarkPos != -1) {
208: _queryString = url.substring(questionMarkPos + 1);
209: if (startPathPos < questionMarkPos) {
210: _pathInfo = url
211: .substring(startPathPos, questionMarkPos);
212: }
213: } else {
214: _queryString = null;
215: if (startPathPos < url.length()) {
216: _pathInfo = url.substring(startPathPos);
217: }
218: return;
219: }
220:
221: StringTokenizer paramsParser = new StringTokenizer(
222: _queryString, "&");
223: while (paramsParser.hasMoreTokens()) {
224: String parameter = paramsParser.nextToken();
225: int equalPos = parameter.indexOf('=');
226: if (equalPos != -1) {
227: try {
228: String paramName = URLEncoding.decode(parameter
229: .substring(0, equalPos));
230: String paramValue = "";
231: if (equalPos != parameter.length() - 1) {
232: paramValue = URLEncoding.decode(parameter
233: .substring(equalPos + 1));
234: }
235: Object currValue = _parameters.get(paramName);
236: if (currValue == null) {
237: _parameters.put(paramName, paramValue);
238: } else if (currValue instanceof String) {
239: ArrayList values = new ArrayList();
240: values.add(currValue);
241: values.add(paramValue);
242: _parameters.put(paramName, values);
243: } else {
244: ArrayList values = (ArrayList) currValue;
245: values.add(paramValue);
246: }
247: } catch (FormatException fe) {
248: // Ignore parameter
249: } catch (IllegalArgumentException iae) {
250: // Ignore parameter
251: }
252: }
253: }
254: }
255:
256: public void setCharacterEncoding(String str) {
257: _characterEncoding = str;
258: }
259:
260: public String[] getParameterValues(String str) {
261: Object values = _parameters.get(str);
262: if (values == null) {
263: return null;
264: } else if (values instanceof String) {
265: return new String[] { (String) values };
266: } else {
267: ArrayList list = (ArrayList) values;
268: return (String[]) list.toArray(new String[list.size()]);
269: }
270: }
271:
272: public String getParameter(String str) {
273: String[] values = getParameterValues(str);
274: return (values == null) ? null : values[0];
275: }
276:
277: public int getIntHeader(String str) {
278: String value = getHeader(str);
279: if (value != null) {
280: try {
281: return Integer.parseInt(value);
282: } catch (NumberFormatException exception) {
283: return -1;
284: }
285: } else {
286: return -1;
287: }
288: }
289:
290: public Object getAttribute(String str) {
291: return _attributes.get(str);
292: }
293:
294: public long getDateHeader(String str) {
295: return _date;
296: }
297:
298: public String getHeader(String str) {
299: return (String) _headers.get(str.toUpperCase());
300: }
301:
302: public Enumeration getHeaders(String str) {
303: throw new UnsupportedOperationException();
304: }
305:
306: public String getRealPath(String str) {
307: throw new UnsupportedOperationException();
308: }
309:
310: public RequestDispatcher getRequestDispatcher(String str) {
311: throw new UnsupportedOperationException();
312: }
313:
314: public boolean isUserInRole(String str) {
315: return false;
316: }
317:
318: public void removeAttribute(String str) {
319: _attributes.remove(str);
320: }
321:
322: public void setAttribute(String str, Object obj) {
323: _attributes.put(str, obj);
324: }
325:
326: public String getQueryString() {
327: return _queryString;
328: }
329:
330: public String getProtocol() {
331: return "file://";
332: }
333:
334: public String getPathTranslated() {
335: // We consider that the first dir is the servlet name
336: if (_pathInfo == null) {
337: return null;
338: }
339: int firstSlashPos = _pathInfo.indexOf("/");
340: if (firstSlashPos == -1
341: || firstSlashPos == _pathInfo.length() - 1) {
342: return null;
343: }
344: return _pathInfo.substring(firstSlashPos + 1);
345: }
346:
347: public String getPathInfo() {
348: return _pathInfo;
349: }
350:
351: public Enumeration getParameterNames() {
352: return Collections.enumeration(_parameters.keySet());
353: }
354:
355: public Map getParameterMap() {
356: return _parameters;
357: }
358:
359: public String getMethod() {
360: return _method;
361: }
362:
363: public Enumeration getLocales() {
364: throw new UnsupportedOperationException();
365: }
366:
367: public Locale getLocale() {
368: throw new UnsupportedOperationException();
369: }
370:
371: public Enumeration getAttributeNames() {
372: return _attributes.keys();
373: }
374:
375: public String getAuthType() {
376: return "";
377: }
378:
379: public String getCharacterEncoding() {
380: if (_characterEncoding != null) {
381: return _characterEncoding;
382: } else if (_contentType == null) {
383: return null;
384: } else {
385: int charsetPos = _contentType.indexOf("charset=");
386: if (charsetPos == -1) {
387: return "UTF-8";
388: } else {
389: return _contentType.substring(charsetPos + 8);
390: }
391: }
392: }
393:
394: public int getContentLength() {
395: return getIntHeader("Content-Length");
396: }
397:
398: public String getContentType() {
399: return _contentType;
400: }
401:
402: public String getContextPath() {
403: throw new UnsupportedOperationException();
404: }
405:
406: public Cookie[] getCookies() {
407: if (_cookies == null && _headers.get("COOKIE") != null) {
408: String cookies = (String) _headers.get("COOKIE");
409: StringTokenizer stCookies = new StringTokenizer(cookies,
410: ";");
411: _cookies = new Cookie[stCookies.countTokens()];
412: int counter = 0;
413: while (stCookies.hasMoreTokens()) {
414: String nextCookie = stCookies.nextToken().trim();
415: int equalsPos = nextCookie.indexOf('=');
416: String cookieName = nextCookie.substring(0, equalsPos);
417: String cookieValue = nextCookie
418: .substring(equalsPos + 1);
419: _cookies[counter++] = new Cookie(cookieName,
420: cookieValue);
421: }
422: } else if (_cookies == null) {
423: _cookies = new Cookie[0];
424: }
425: return _cookies;
426: }
427:
428: public Enumeration getHeaderNames() {
429: return _headers.keys();
430: }
431:
432: public ServletInputStream getInputStream() {
433: if (_readerUsed) {
434: throw new IllegalStateException(
435: "The method getReader() has already been called on this request.");
436: }
437: _inputStreamUsed = true;
438: return new InputStream(_postData);
439: }
440:
441: public BufferedReader getReader() {
442: if (_inputStreamUsed) {
443: throw new IllegalStateException(
444: "The method getInputStream() has already been called on this request.");
445: }
446: _readerUsed = true;
447: return new BufferedReader(new StringReader(_postData));
448: }
449:
450: public String getRemoteAddr() {
451: return LOCALHOST_ADDRESS;
452: }
453:
454: public String getRemoteHost() {
455: return LOCALHOST_NAME;
456: }
457:
458: public String getRemoteUser() {
459: return "";
460: }
461:
462: public String getRequestURI() {
463: if (_url.indexOf('?') == -1) {
464: return _url;
465: } else {
466: return _url.substring(0, _url.indexOf('?'));
467: }
468: }
469:
470: public StringBuffer getRequestURL() {
471: return new StringBuffer(_url);
472: }
473:
474: public String getRequestedSessionId() {
475: throw new UnsupportedOperationException();
476: }
477:
478: public String getScheme() {
479: int separator = _url.indexOf("://");
480: if (separator != -1) {
481: return _url.substring(0, separator + 3);
482: }
483: return "file://";
484: }
485:
486: public String getServerName() {
487: try {
488: return InetAddress.getLocalHost().getHostName();
489: } catch (Exception ioe) {
490: return "localhost";
491: }
492: }
493:
494: public int getServerPort() {
495: return 8080;
496: }
497:
498: public String getServletPath() {
499: return "";
500: }
501:
502: public HttpSession getSession() {
503: return (HttpSession) SESSIONS.get(getRemoteAddr()
504: + getRemoteUser());
505: }
506:
507: public HttpSession getSession(boolean create) {
508: String sessionKey = getRemoteAddr() + getRemoteUser();
509: HttpSession session = (HttpSession) SESSIONS.get(sessionKey);
510: if (session == null) {
511: session = new XINSHttpSession();
512: SESSIONS.put(sessionKey, session);
513: }
514: return session;
515: }
516:
517: public Principal getUserPrincipal() {
518: throw new UnsupportedOperationException();
519: }
520:
521: public boolean isRequestedSessionIdFromCookie() {
522: return false;
523: }
524:
525: public boolean isRequestedSessionIdFromURL() {
526: return false;
527: }
528:
529: public boolean isRequestedSessionIdFromUrl() {
530: return false;
531: }
532:
533: public boolean isRequestedSessionIdValid() {
534: return false;
535: }
536:
537: public boolean isSecure() {
538: return false;
539: }
540:
541: /**
542: * Implementation of a <code>ServletInputStream</code> for this request.
543: *
544: * <p>This implementation is <strong>not thread-safe</strong>.
545: *
546: * @version $Revision: 1.41 $ $Date: 2007/09/18 08:45:08 $
547: * @author <a href="mailto:ernst@ernstdehaan.com">Ernst de Haan</a>
548: * @author <a href="mailto:anthony.goubard@japplis.com">Anthony Goubard</a>
549: */
550: private static class InputStream extends ServletInputStream {
551: /**
552: * Constructs a new <code>InputStream</code> instance for the specified
553: * data.
554: *
555: * @param data
556: * the data, as a string, can be <code>null</code>.
557: */
558: private InputStream(String data) {
559: String encoding = "ISO-8859-1";
560: try {
561: byte[] dataAsByte = data.getBytes(encoding);
562: _stream = new ByteArrayInputStream(dataAsByte);
563: } catch (UnsupportedEncodingException exception) {
564: throw new RuntimeException(
565: "Failed to convert characters to bytes using encoding \""
566: + encoding + "\".");
567: }
568: }
569:
570: /**
571: * The data. Is <code>null</code> if there is no data.
572: */
573: private final ByteArrayInputStream _stream;
574:
575: public int read() throws IOException {
576: return _stream.read();
577: }
578:
579: public int read(byte[] b) throws IOException {
580: return _stream.read(b);
581: }
582:
583: public int read(byte[] b, int off, int len) throws IOException {
584: return _stream.read(b, off, len);
585: }
586:
587: public boolean markSupported() {
588: return _stream.markSupported();
589: }
590:
591: public void mark(int readlimit) {
592: _stream.mark(readlimit);
593: }
594:
595: public long skip(long n) throws IOException {
596: return _stream.skip(n);
597: }
598:
599: public void reset() throws IOException {
600: _stream.reset();
601: }
602:
603: public void close() throws IOException {
604: _stream.close();
605: }
606: }
607: }
|