Main Page | Packages | Class Hierarchy | Class List | Directories | File List | Class Members | Related Pages

WebServerConnection.java

00001 /*
00002  * OpenMobileIS - a free Java(TM) Framework for mobile applications Java(TM)
00003  * Copyright (C) 2004-2006 Philippe Delrieu
00004  * All rights reserved.
00005  * Contact: pdelrieu@openmobileis.org
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
00020  * USA
00021  *
00022  *  Author : Philippe Delrieu
00023  *  
00024  *  Modifications :
00025  *  2004 Creation P.Delrieu
00026  *  2004 Modified by Romain Beaugrand
00027  * 
00028  */
00029 
00030 package org.openmobileis.embedded.webserver;
00031 
00032 import java.io.BufferedReader;
00033 import java.io.IOException;
00034 import java.io.InputStreamReader;
00035 import java.io.OutputStreamWriter;
00036 import java.io.PrintWriter;
00037 import java.io.UnsupportedEncodingException;
00038 import java.net.InetAddress;
00039 import java.net.Socket;
00040 import java.security.Principal;
00041 import java.text.SimpleDateFormat;
00042 import java.util.Date;
00043 import java.util.Enumeration;
00044 import java.util.Hashtable;
00045 import java.util.Locale;
00046 import java.util.StringTokenizer;
00047 import java.util.Vector;
00048 
00049 import javax.servlet.RequestDispatcher;
00050 import javax.servlet.ServletException;
00051 import javax.servlet.ServletInputStream;
00052 import javax.servlet.ServletOutputStream;
00053 import javax.servlet.ServletRequest;
00054 import javax.servlet.ServletResponse;
00055 import javax.servlet.SingleThreadModel;
00056 import javax.servlet.http.Cookie;
00057 import javax.servlet.http.HttpServlet;
00058 import javax.servlet.http.HttpServletRequest;
00059 import javax.servlet.http.HttpServletResponse;
00060 import javax.servlet.http.HttpSession;
00061 import javax.servlet.http.HttpUtils;
00062 
00063 import org.openmobileis.common.context.SessionContext;
00064 import org.openmobileis.common.context.SessionContextManager;
00065 import org.openmobileis.common.util.log.LogManager;
00066 import org.openmobileis.common.util.log.LogServices;
00067 
00068 
00069 public class WebServerConnection implements HttpServletRequest, HttpServletResponse {
00070 
00071     public final static String WWWFORMURLENCODE = "application/x-www-form-urlencoded";
00072     public final static String TRANSFERENCODING = "Transfer-Encoding";
00073     public final static String CHUNKED = "chunked";
00074     public final static String CONTENTLENGTH = "Content-Length";
00075     public final static String CONTENTTYPE = "Content-Type";
00076 
00077     private Socket socket;
00078     private WebServer webserver;
00079 
00080     private String reqMethod; // == null by default
00081 
00082     private String reqUriPath;
00083 
00084     private boolean oneOne; // HTTP/1.1 or better
00085 
00086     String reqQuery = null;
00087 
00088     private Vector reqHeaderNames = new Vector();
00089     private Vector reqHeaderValues = new Vector();
00090     private Locale locale; // = java.util.Locale.getDefault();
00091 
00092     private int uriLen;
00093     private static final Hashtable EMPTYHASHTABLE = new Hashtable();
00094 
00095     protected long connexionLifeTime = 0;
00096 
00097     private ServletInputStream in;
00098 
00099     private ServletOutputStream out;
00100 
00101     private boolean reqMime;
00102 
00103     private String reqProtocol;
00104     private String reqCharEncoding;
00105 
00106     private Hashtable formParameters;
00107 
00108     private Hashtable attributes = new Hashtable();
00109 
00110     private int resCode = -1;
00111 
00112     private String resMessage = null;
00113 
00114     private Hashtable resHeaderNames = new Hashtable();
00115 
00116     private boolean headersWritten = false;
00117 
00118     protected static final SimpleDateFormat expdatefmt = new SimpleDateFormat(
00119             "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'");
00120 
00121     protected static final SimpleDateFormat headerdateformat = new SimpleDateFormat(
00122             "EEE, dd MMM yyyy HH:mm:ss z");
00123     
00124     private PrintWriter printWriter = null;
00125     
00126     public void init(WebServer webserver, Socket socket)        {
00127     // Save arguments.
00128     this.webserver = webserver;
00129     this.socket = socket;
00130     out = null;
00131     in = null;
00132     oneOne = false;
00133     reqMethod = null;
00134     reqUriPath = null;
00135     reqQuery = null;
00136     reqProtocol = null;
00137     reqCharEncoding = null;
00138     reqHeaderNames = new Vector();
00139     reqHeaderValues = new Vector();
00140     formParameters = null;
00141     attributes = new Hashtable();
00142     locale = null;
00143     uriLen = -1;
00144     resCode = -1;
00145     connexionLifeTime = 0;
00146     reqMime = false;
00147     resMessage = "";
00148     resHeaderNames = new Hashtable();
00149     headersWritten = false;
00150     printWriter = null;
00151   }
00152 
00153     // Methods from Runnable.
00154     public void run() {
00155       SessionContextManager.getManager().joinSessionContext("OPENMOBILEISSESSION");
00156         try {
00157             // Get the streams.
00158             in = new ServeInputStream(socket.getInputStream());
00159             out = new ServeOutputStream(socket.getOutputStream(), this);
00160         } catch (IOException e) {
00161             problem("Getting streams: " + e.getMessage(), SC_BAD_REQUEST);
00162             LogManager.traceError(0, e);
00163         }
00164 
00165         // parse the request
00166         parseRequest();
00167 
00168  //       LogManager.traceDebug(LogServices.WEBSERVICE, socket.getInetAddress().toString()
00169  //              + ' ' + reqMethod + ' ' + reqUriPath + ' ' + resCode
00170         /*
00171          * + (serve.isShowReferer() ? "| " + getHeader("Referer") : "") +
00172          * (serve.isShowUserAgent() ? "| " + getHeader("User-Agent") : "")
00173          */
00174  //       );
00175 
00176         try {
00177             this.execURI(this.reqUriPath);
00178         } catch (Exception e) {
00179             problem("Getting streams: " + e.getMessage(), SC_BAD_REQUEST);
00180             LogManager.traceError(0, e);
00181         } finally {
00182             try {
00183                 //socket.getOutputStream().write(byteOut.toByteArray());
00184                 socket.close();
00185             } catch (IOException e) {
00186                 org.openmobileis.common.util.log.LogManager
00187                         .traceError(
00188                                 org.openmobileis.common.util.log.LogServices.WEBSERVICE,
00189                                 "Impossible to close socket : WebServerConnection");
00190                 org.openmobileis.common.util.log.LogManager
00191                         .traceError(
00192                                 org.openmobileis.common.util.log.LogServices.WEBSERVICE,
00193                                 e);
00194             }
00195         }
00196     }
00197 
00198     private void parseRequest() {
00199         byte[] lineBytes = new byte[4096];
00200         int len;
00201         String line;
00202 
00203         try {
00204             // Read the first line of the request.
00205             len = in.readLine(lineBytes, 0, lineBytes.length);
00206             if (len == -1 || len == 0) {
00207                 problem("Empty request", SC_BAD_REQUEST);
00208                 return;
00209             }
00210             line = new String(lineBytes, 0, len);
00211             StringTokenizer ust = new StringTokenizer(line);
00212             reqProtocol = null;
00213             if (ust.hasMoreTokens()) {
00214                 reqMethod = ust.nextToken();
00215                 if (ust.hasMoreTokens()) {
00216                     reqUriPath = Acme.Utils.urlDecoder(ust.nextToken());
00217                     if (ust.hasMoreTokens()) {
00218                         reqProtocol = ust.nextToken();
00219                         oneOne = !reqProtocol.toUpperCase().equals("HTTP/1.0");
00220                         reqMime = true;
00221                         // Read the rest of the lines.
00222                         String s;
00223                         while ((s = ((ServeInputStream) in).readLine()) != null) {
00224                             if (s.length() == 0)
00225                                 break;
00226 
00227                             int c = s.indexOf(':', 0);
00228                             if (c > 0) {
00229                                 String key = s.substring(0, c).trim();
00230                                 String value = s.substring(c + 1, s.length())
00231                                         .trim();
00232                                 reqHeaderNames.addElement(key.toLowerCase());
00233                                 reqHeaderValues.addElement(value);
00234                             } else {
00235                                 LogManager.traceError(LogServices.WEBSERVICE, "header field without ':'");
00236                             }
00237                         }
00238                     } else {
00239                         reqProtocol = "HTTP/0.9";
00240                         oneOne = false;
00241                         reqMime = false;
00242                     }
00243                 }
00244             }
00245             if (reqProtocol == null) {
00246                 problem("Malformed request line", SC_BAD_REQUEST);
00247                 return;
00248             }
00249             // Check Host: header in HTTP/1.1 requests.
00250             if (oneOne) {
00251                 String host = getHeader("host");
00252                 if (host == null) {
00253                     problem("Host header missing on HTTP/1.1 request",
00254                             SC_BAD_REQUEST);
00255                     return;
00256                 }
00257             }
00258 
00259             // Decode %-sequences.
00260             //reqUriPath = decode( reqUriPath );
00261             // Split off query string, if any.
00262             int qmark = reqUriPath.indexOf('?');
00263             if (qmark > -1) {
00264                 reqQuery = reqUriPath.substring(qmark + 1);
00265                 reqUriPath = reqUriPath.substring(0, qmark);
00266             }
00267             if (CHUNKED.equals(getHeader(TRANSFERENCODING))) {
00268                 setHeader(CONTENTLENGTH, null);
00269                 ((ServeInputStream) in).chunking(true);
00270             }
00271 
00272         } catch (IOException e) {
00273             problem("Reading request: " + e.getMessage(), SC_BAD_REQUEST);
00274         }
00275     }
00276 
00277     private void execURI(String URI) throws ServletException {
00278         //manage /index for index servlet
00279         if (URI.equals("/index")) {
00280             URI = "/services/index";
00281             reqUriPath = URI;
00282         }
00283         Object[] os = webserver.getServletByURLorClassName(URI);
00284         if (os[0] == null) {
00285             os = webserver.getServletByURLorClassName("defaultServlet");
00286             if (os[0] == null) {
00287                 throw new ServletException(
00288                         "WebServerConnection::execUri Unable to find file servlet");
00289             }
00290             //uriLen = ((Integer) os[1]).intValue();
00291             uriLen = 0;
00292             runServlet((HttpServlet) os[0]);
00293         } else {
00294             uriLen = ((Integer) os[1]).intValue();
00295             runServlet((HttpServlet) os[0]);
00296         }
00297     }
00298 
00300     // output stream.
00301     // @exception IOException if an I/O error has occurred
00302     void writeHeaders() throws IOException {
00303         synchronized (this) {
00304             if (headersWritten)
00305                 return;
00306 
00307             headersWritten = true;
00308         }
00309         if (reqMime) {
00310             //boolean chunked_out = false;
00311             out.println(reqProtocol + " " + resCode + " " + resMessage);
00312 
00313             Enumeration he = resHeaderNames.keys();
00314             while (he.hasMoreElements()) {
00315                 String name = (String) he.nextElement();
00316                 Object o = resHeaderNames.get(name);
00317                 if (o instanceof String) {
00318                     String value = (String) o;
00319                     if (value != null) // just in case
00320                         out.println(name + ": " + value);
00321                     /*
00322                      * moved to servlet if (TRANSFERENCODING.equals(name) &&
00323                      * CHUNKED.equals(value)) chunked_out = true;
00324                      */
00325                 } else if (o instanceof String[]) {
00326                     String[] values = (String[]) o;
00327                     out.println(name + ": " + values[0]);
00328                     for (int i = 0; i < values.length; i++)
00329                         out.print("," + values[i]);
00330                     out.println();
00331                 }
00332             }
00333             //add specific header to remove page from cache
00334             out.println("Pragma: no-cache");
00335                         out.println("Cache-Control: no-cache, must-revalidate");
00336                         out.println("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
00337                         out.println("Date: Mon, 26 Jul 1997 05:00:00 GMT");
00338                         
00339                         out.println("Last-Modified: Mon, 26 Jul 1997 05:00:00 GMT");
00340                         out.println("Connection: close" );
00341             // Marks the beginning of body-content.
00342             out.println();
00343             out.flush();
00344             //if (chunked_out) ((ServeOutputStream)out).setChunked(true);
00345         }
00346     }
00347 
00348     private void runServlet(HttpServlet servlete) {
00349         // Set default response fields.
00350         setStatus(SC_OK);
00351         /*
00352          * setDateHeader("Date", System.currentTimeMillis());
00353          * setHeader("Server", Serve.Identification.serverName + "/" +
00354          * Serve.Identification.serverVersion); setHeader("MIME-Version",
00355          * "1.0");
00356          */
00357         try {
00358                 authenticate();
00359             if (servlete instanceof SingleThreadModel)
00360                 synchronized (servlete) {
00361                     servlete.service((ServletRequest) this,
00362                             (ServletResponse) this);
00363                 }
00364             else {
00365                 servlete.service((ServletRequest) this, (ServletResponse) this);
00366             }
00367             if (((ServeOutputStream)out).isReturnedAsWriter() && printWriter != null) {
00368                 printWriter.flush();
00369             } else {
00370                 out.flush();
00371             }
00372         } catch (IOException e) {
00373             e.printStackTrace();
00374             problem("IO problem running servlet: " + e.toString(),
00375                     SC_BAD_REQUEST);
00376         } catch (ServletException e) {
00377             e.printStackTrace();
00378             problem("problem running servlet: " + e.toString(), SC_BAD_REQUEST);
00379         } catch (Exception e) {
00380             e.printStackTrace();
00381             problem("unexpected problem running servlet: " + e.toString(),
00382                     SC_INTERNAL_SERVER_ERROR);
00383         }
00384     }
00385     
00386     private boolean authenticate() throws IOException {
00387         // We don't use any authentification
00388         return true;
00389     }
00390     
00391     // send an error page
00392     private void problem(String logMessage, int resCode) {
00393         LogManager.traceError(LogServices.WEBSERVICE, logMessage);
00394         try {
00395           sendError(resCode);
00396         } catch (IllegalStateException e) { /* ignore */
00397         } catch (IOException e) { /* ignore */
00398         }
00399     }
00400 
00401     private Hashtable getParametersFromRequest() {
00402         Hashtable result = null;
00403         //System.out.println("Req:"+reqMethod+" con:"+getContentType()+" eq
00404         // "+WWWFORMURLENCODE.equals(getContentType()));
00405         if ("GET".equals(reqMethod)) {
00406             if (reqQuery != null)
00407                 try {
00408                     result = HttpUtils.parseQueryString(reqQuery);
00409                 } catch (IllegalArgumentException ex) {
00410                 }
00411         } else if ("POST".equals(reqMethod))
00412             if (WWWFORMURLENCODE.equals(getContentType()))
00413                 try {
00414                     result = HttpUtils.parsePostData(getContentLength(), getInputStream());
00415                     if (reqQuery != null && reqQuery.length() > 0) {
00416                         Acme.Utils.putAll(result, HttpUtils.parseQueryString(reqQuery));
00417                     }
00418                 } catch (Exception ex) {
00419                     LogManager.traceError(0, ex);
00420                     LogManager.traceError(LogServices.WEBSERVICE, "Exception " + ex + " at parsing post data of length " + getContentLength());
00421                 }
00422             else
00423                 try {
00424                     if (reqQuery != null)
00425                         result = HttpUtils.parseQueryString(reqQuery);
00426                 } catch (Exception ex) {
00427                 }
00428         return result != null ? result : EMPTYHASHTABLE;
00429     }
00430     
00431     private void realSendError() throws IOException {
00432         if (isCommitted())
00433             throw new IllegalStateException(
00434                     "Can not send error, headers have been already written");
00435         synchronized (out) {
00436             // no more out after error
00437             ((ServeOutputStream) out).setReturnedAsStream(true);
00438             ((ServeOutputStream) out).setReturnedAsWriter(true);
00439         }
00440         setContentType("text/html");
00441         StringBuffer sb = new StringBuffer(100);
00442         sb.append("<HTML><HEAD>").append(
00443                 "<TITLE>" + resCode + " " + resMessage + "</TITLE>").append(
00444                 "</HEAD><BODY BGCOLOR=\"#F1D0F2\">").append(
00445                 "<H2>" + resCode + " " + resMessage + "</H2>").append("<HR>");
00446         Identification.writeAddress(sb);
00447         sb.append("</BODY></HTML>");
00448         setContentLength(sb.length());
00449         out.print(sb.toString());
00450         out.flush();
00451     }
00452 
00453 
00454 
00455 
00456      
00457      
00458      
00459      
00460      
00461      
00462      
00463      
00464      
00465      
00466      
00467      
00468      
00469      
00470      
00471      
00472      
00473      
00474      // HttpServletRequest METHODS
00475      // ***************************************************************************************************************
00476     
00478     // the attribute does not exist. This method allows access to request
00479     // information not already provided by the other methods in this interface.
00480     public Object getAttribute(String name) {
00481         return attributes.get(name);
00482     }
00483 
00484     // from ServletRequest
00485     public Enumeration getAttributeNames() {
00486         return attributes.keys();
00487     }
00488      
00489      public String getAuthType() {
00490          //return HttpServletRequest.BASIC_AUTH;
00491          return null;
00492      }
00493      
00495      // Same as the CGI variable CONTENT_LENGTH.
00496      public int getContentLength() {
00497          try {
00498              return this.getIntHeader(CONTENTLENGTH);
00499          } catch (Exception ex) {
00500              return -1;
00501          }
00502      }
00503      
00505      // not known.
00506      // Same as the CGI variable CONTENT_TYPE.
00507      public String getContentType() {
00508          return getHeader(CONTENTTYPE);
00509      }
00510      
00511      public String getContextPath() {
00512          return "";
00513      }
00514      
00515      public Cookie[] getCookies() {
00516          // We don't use cookies
00517          return null;
00518      }
00519      
00520      public long getDateHeader(String name) {
00521          String val = getHeader(name);
00522          if (val == null)
00523              return 0;
00524          try {
00525              return headerdateformat.parse(val).getTime();
00526          } catch (Exception e) {
00527              throw new IllegalArgumentException("Value " + val
00528                      + " can't be converted to Date using "
00529                      + headerdateformat.toPattern());
00530          }
00531      }
00532      
00533      public String getHeader(String name) {
00534          int i = reqHeaderNames.indexOf(name.toLowerCase());
00535          if (i == -1)
00536              return null;
00537          return (String) reqHeaderValues.elementAt(i);
00538      }
00539      
00540      public Enumeration getHeaderNames() {
00541          return reqHeaderNames.elements();
00542      }
00543      
00544      public Enumeration getHeaders(String header) {
00545          Vector result = new Vector();
00546          int i = -1;
00547          while ((i = reqHeaderNames.indexOf(header.toLowerCase(), i + 1)) >= 0)
00548              result.addElement(reqHeaderValues.elementAt(i));
00549          return result.elements();
00550      }
00551      
00553      // @exception IllegalStateException if getReader has already been called
00554      // @exception IOException on other I/O-related errors
00555      public ServletInputStream getInputStream() throws IOException {
00556          synchronized (in) {
00557              if (((ServeInputStream) in).isReturnedAsReader())
00558                  throw new IllegalStateException("Already returned as a reader.");
00559              ((ServeInputStream) in).setReturnedAsReader(true);
00560          }
00561          return in;
00562      }
00563 
00565      // @param name the header field name
00566      public int getIntHeader(String name) {
00567          String val = getHeader(name);
00568          if (val == null)
00569              return -1;
00570          
00571          // We don't use any try catch, as this method must return
00572          // a NumberFormatException in case of problem
00573          // (According to the Servlet 2.4 specifications)
00574          return Integer.parseInt(val);
00575      }
00576      
00587      public String getLocalAddr() {
00588        return null; // TODO:
00589      }
00590      
00591      // should decide about supported locales and charsets, no a good decision yet
00592      public Enumeration getLocales() {
00593        // TODO: get locales from Accept-Language (RFC 2616)
00594        //Locale.getAvailableLocales() 
00595        return null;
00596      }
00597      
00607      public String getLocalName() {
00608        return null; // TODO: get bind address
00609      }
00610      
00619      public int getLocalPort() {
00620          return webserver.port;
00621      }
00622      
00623      public String getMethod() {
00624          return reqMethod;
00625      }
00626      
00628      // if not found.
00629      // @param name the parameter name
00630      public String getParameter(String name) {
00631          String[] params = getParameterValues(name);
00632          if (params == null || params.length == 0)
00633              return null;
00634 
00635          return params[0];
00636      }
00637      
00647      public java.util.Map getParameterMap() {
00648        return (java.util.Map) formParameters;
00649      }
00650      
00652      public Enumeration getParameterNames() {
00653          if (formParameters == null)
00654              formParameters = getParametersFromRequest();
00655          return formParameters.keys();
00656      }
00657      
00659      // array of strings, or null if the named parameter does not exist.
00660      public String[] getParameterValues(String name) {
00661          if (formParameters == null)
00662              getParameterNames();
00663 
00664          return (String[]) formParameters.get(name);
00665      }
00666      
00667      public String getPathInfo() {
00668          // In this server, the entire path is regexp-matched against the
00669          // servlet pattern, so there's no good way to distinguish which
00670          // part refers to the servlet.
00671          return uriLen >= reqUriPath.length() ? null : reqUriPath.substring(uriLen);
00672      }
00673      
00674      public String getPathTranslated() {
00675          // In this server, the entire path is regexp-matched against the
00676          // servlet pattern, so there's no good way to distinguish which
00677          // part refers to the servlet.
00678          return getRealPath(getPathInfo());
00679      }
00680      
00682      // the form <protocol>/<major version>.<minor version>.
00683      // Same as the CGI variable SERVER_PROTOCOL.
00684      public String getProtocol() {
00685        return reqProtocol;
00686      }
00687      
00688      // Returns the query string part of the servlet URI, or null if not known.
00689      // Same as the CGI variable QUERY_STRING.
00690      public String getQueryString() {
00691          return reqQuery;
00692      }
00693      
00695      // @exception UnsupportedEncodingException if the character set encoding isn't supported
00696      // @exception IllegalStateException if getInputStream has already been called
00697      // @exception IOException on other I/O-related errors
00698      public BufferedReader getReader() throws IOException {
00699        synchronized (in) {
00700          if (((ServeInputStream) in).isReturnedAsStream())
00701            throw new IllegalStateException("Already returned as a stream.");
00702          ((ServeInputStream) in).setReturnedAsStream(true);
00703        }
00704        if (reqCharEncoding != null)
00705          try {
00706            return new BufferedReader(new InputStreamReader(in, reqCharEncoding));
00707          } catch (UnsupportedEncodingException uee) {
00708          }
00709        return new BufferedReader(new InputStreamReader(in));
00710      }
00711      
00713      // corresponding real path, or null if the translation can not be
00714      // performed for any reason.  For example, an HTTP servlet would
00715      // resolve the path using the virtual docroot, if virtual hosting is
00716      // enabled, and with the default docroot otherwise.  Calling this
00717      // method with the string "/" as an argument returns the document root.
00718      public String getRealPath(String path) {
00719        return webserver.getRealPath(path);
00720      }
00721      
00723      // Same as the CGI variable REMOTE_ADDR.
00724      public String getRemoteAddr() {
00725        return socket.getInetAddress().getHostAddress().toString();
00726      }
00727 
00729      // request.
00730      // Same as the CGI variable REMOTE_HOST.
00731      public String getRemoteHost() {
00732        String result = socket.getInetAddress().getHostName();
00733        return result != null ? result : getRemoteAddr();
00734      }
00735      
00744      public int getRemotePort() {
00745          // TODO : Actually returns local port
00746          return webserver.port;
00747      }
00748      
00750      // Same as the CGI variable REMOTE_USER.
00751      public String getRemoteUser() {
00752          // We don't use user authentification.
00753          return null;
00754      }
00755      
00756      public RequestDispatcher getRequestDispatcher(String urlpath) {
00757          // TODO: calculate dispacter relatively the current path
00758          return null; // we don't provide resource dispatching in this way
00759        }
00760      
00761      public String getRequestedSessionId() {
00762          // This WEB server only handles one session.
00763          return this.getSession().getId();
00764      }
00765      
00766      public String getRequestURI() {
00767          return reqUriPath;
00768      }
00769 
00770      public StringBuffer getRequestURL() {
00771          return new StringBuffer().append(getScheme()).append("://").append(this.getServerName())
00772                         .append(webserver.port == 80 ? "" : ":"+String.valueOf(webserver.port)).append(getRequestURI());
00773      }
00774      
00776      // "http", "https", or "ftp".  Different schemes have different rules
00777      // for constructing URLs, as noted in RFC 1738.  The URL used to create
00778      // a request may be reconstructed using this scheme, the server name
00779      // and port, and additional information such as URIs.
00780      public String getScheme() {
00781        if (socket.getClass().getName().toUpperCase().indexOf("SSL") < 0)
00782          return "http";
00783        else
00784          return "https";
00785      }
00786      
00788      // the request URI.
00789      // Same as the CGI variable SERVER_NAME.
00790      public String getServerName() {
00791        String serverName;
00792        int serverPort = 80;
00793        serverName = getHeader("Host");
00794        if (serverName != null && serverName.length() > 0) {
00795          int colon = serverName.indexOf(':');
00796          if (colon >= 0) {
00797            if (colon < serverName.length())
00798              serverPort = Integer.parseInt(serverName.substring(colon + 1));
00799            serverName = serverName.substring(0, colon);
00800          }
00801        }
00802 
00803        if (serverName == null) {
00804          try {
00805            serverName = InetAddress.getLocalHost().getHostName();
00806          } catch (java.net.UnknownHostException ignore) {
00807            serverName = "127.0.0.0";
00808          }
00809        }
00810 
00811        int slash = serverName.indexOf("/");
00812        if (slash >= 0)
00813          serverName = serverName.substring(slash + 1);
00814        return serverName;
00815      }
00816 
00818      // the <port> part of the request URI.
00819      // Same as the CGI variable SERVER_PORT.
00820      public int getServerPort() {
00821        return socket.getLocalPort();
00822      }
00823      
00824      public String getServletPath() {
00825          // In this server, the entire path is regexp-matched against the
00826          // servlet pattern, so there's no good way to distinguish which
00827          // part refers to the servlet.
00828          return uriLen > 0 ? reqUriPath.substring(0, uriLen) : "";
00829      }
00830      
00831      public HttpSession getSession() {
00832          return this.getSession(true);
00833      }
00834 
00835      public HttpSession getSession(boolean create) {
00836          // Only one seesion context
00837        SessionContext session = SessionContextManager.getManager().getSessionContext("OPENMOBILEISSESSION");
00838        if (session == null)  {
00839          synchronized (SessionContextManager.getManager()) {
00840            session = SessionContextManager.getManager().getSessionContext("OPENMOBILEISSESSION");
00841            if (session == null)  {
00842              session = SessionContextManager.getManager().createSessionContext("OPENMOBILEISSESSION");
00843            }
00844          }
00845        }
00846        SessionContextManager.getManager().joinSessionContext(session.getId());
00847        return SessionContextManager.getManager().getSessionContext();
00848      }
00849      
00850      public Principal getUserPrincipal() {
00851          // We don't use user authentification.
00852          return null;
00853      }
00854      
00855      public boolean isRequestedSessionIdFromCookie() {
00856          // We don't use cookies.
00857          return false;
00858      }
00859      
00860      public boolean isRequestedSessionIdFromURL() {
00861          // We only use on session for this web browser.
00862          return false;
00863      }
00864 
00865      public boolean isRequestedSessionIdFromUrl() {
00866          // We only use on session for this web browser.
00867          return false;
00868      }
00869      
00870      public boolean isRequestedSessionIdValid() {
00871          HttpSession session = this.getSession();
00872          if (session != null) {
00873              return true;
00874          }
00875          return false;
00876      }
00877      
00878      public boolean isSecure() {
00879          return false;
00880        }
00881      
00882      public boolean isUserInRole(String arg0) {
00883          // We don't use authentification.
00884          return false;
00885      }
00886      
00887      public void removeAttribute(String name) {
00888          // Do nothing
00889      }
00890      
00891      public void setAttribute(String key, Object o) {
00892          attributes.put(key, o);
00893        }
00894      
00902      public void setCharacterEncoding(String _enc) {
00903        reqCharEncoding = _enc;
00904      }
00905      
00906      
00907      
00908      
00909      
00910      
00911      
00912      
00913      
00914      
00915      
00916      
00917      
00918      
00919      
00920      // HttpServletRequest AND HttpServletResponse METHODS
00921      // ***************************************************************************************************************
00922      
00924      // character encoding is either the one specified in the assigned
00925      // content type, or one which the client understands. If no content
00926      // type has yet been assigned, it is implicitly set to text/plain.
00927      public String getCharacterEncoding() {
00928          String ct = (String) resHeaderNames.get(CONTENTTYPE);
00929          if (ct != null) {
00930              int scp = ct.indexOf(';');
00931              if (scp > 0) {
00932                  scp = ct.toLowerCase().indexOf("charset=", scp);
00933                  if (scp >= 0) {
00934                      ct = ct.substring(scp + 8);
00935                      scp = ct.indexOf(' ');
00936                      if (scp > 0)
00937                          ct = ct.substring(0, scp);
00938                      scp = ct.indexOf(';');
00939                      if (scp > 0)
00940                          ct = ct.substring(0, scp);
00941                      return ct;
00942                  }
00943              }
00944          }
00945          return null;
00946      }
00947      
00948      public Locale getLocale() {
00949          return locale;
00950      }
00951       
00952 
00953      
00954      
00955      
00956      
00957      
00958      
00959      
00960      
00961      
00962      
00963      
00964      
00965      
00966      
00967      
00968      
00969      
00970      
00971      
00972      
00973      
00974      
00975      
00976      
00977      
00978      
00979      
00980      // HttpServletResponse METHODS
00981      // ***************************************************************************************************************
00982      
00984      // multiple times to set more than one cookie.
00985      public void addCookie(Cookie cookie) {
00986          // We don't use cookies.
00987      }
00988      
00989      public void addDateHeader(String header, long date) {
00990          addHeader(header, expdatefmt.format(new Date(date)));
00991      }
00992      
00993      public void addHeader(String header, String value) {
00994          Object o = resHeaderNames.get(header);
00995          if (o == null)
00996              setHeader(header, value);
00997          else {
00998              if (o instanceof String[]) {
00999                  String[] oldVal = (String[]) o;
01000                  String[] newVal = new String[oldVal.length + 1];
01001                  System.arraycopy(oldVal, 0, newVal, 0, oldVal.length);
01002                  newVal[oldVal.length] = value;
01003                  resHeaderNames.put(header, newVal);
01004              } else if (o instanceof String) {
01005                  String[] newVal = new String[2];
01006                  newVal[0] = (String) o;
01007                  newVal[1] = value;
01008                  resHeaderNames.put(header, newVal);
01009              } else
01010                  throw new RuntimeException("Invalid content of header hash - "
01011                          + o.getClass().getName());
01012          }
01013      }
01014      
01015      public void addIntHeader(String header, int value) {
01016          addHeader(header, Integer.toString(value));
01017      }
01018      
01020      // specified name.
01021      public boolean containsHeader(String name) {
01022          return resHeaderNames.contains(name);
01023      }
01024      
01026      // encoding is not needed, returns the URL unchanged. The
01027      // implementation of this method should include the logic to determine
01028      // whether the session ID needs to be encoded in the URL. Because the
01029      // rules for making this determination differ from those used to
01030      // decide whether to encode a normal link, this method is seperate
01031      // from the encodeUrl method.
01032      // <P>
01033      // All URLs sent to the HttpServletResponse.sendRedirect method should be
01034      // run through this method. Otherwise, URL rewriting cannot be used with
01035      // browsers which do not support cookies.
01036      public String encodeRedirectUrl(String url) {
01037          return url;
01038      }
01039      
01040      public String encodeRedirectURL(String url) {
01041          return url; // as is
01042      }
01043      
01044      // URL session-encoding stuff. Not implemented, but the API is here
01045      // for compatibility.
01046 
01048      // encoding is not needed, returns the URL unchanged. The
01049      // implementation of this method should include the logic to determine
01050      // whether the session ID needs to be encoded in the URL. For example,
01051      // if the browser supports cookies, or session tracking is turned off,
01052      // URL encoding is unnecessary.
01053      // <P>
01054      // All URLs emitted by a Servlet should be run through this method.
01055      // Otherwise, URL rewriting cannot be used with browsers which do not
01056      // support cookies.
01057      public String encodeUrl(String url) {
01058          return url;
01059      }
01060      
01061      // JSDK 2.1 extension
01062      public String encodeURL(String url) {
01063          return url; // as is
01064      }
01065      
01066      // 2.2
01067      // do not use buffer
01068      public void flushBuffer() {
01069      }
01070      
01071         public int getBufferSize() {
01072          return 0;
01073         }
01074         
01076     public ServletOutputStream getOutputStream() throws IOException {
01077       synchronized (out) {
01078         if (((ServeOutputStream) out).isReturnedAsWriter())
01079           throw new IllegalStateException("Already returned as a writer");
01080         ((ServeOutputStream) out).setReturnedAsStream(true);
01081       }
01082       return out;
01083     }
01084     
01086     // the response will be modified, if necessary, to reflect the character
01087     // encoding used, through the charset=... property.  This means that the
01088     // content type must be set before calling this method.
01089     // @exception UnsupportedEncodingException if no such encoding can be provided
01090     // @exception IllegalStateException if getOutputStream has been called
01091     // @exception IOException on other I/O errors
01092     public PrintWriter getWriter() throws IOException {
01093       synchronized (out) {
01094         if (((ServeOutputStream) out).isReturnedAsStream())
01095           throw new IllegalStateException("Already was returned as servlet output stream");
01096         ((ServeOutputStream) out).setReturnedAsWriter(true);
01097       }
01098       String encoding = getCharacterEncoding();
01099       if (encoding != null) {
01100         //return new PrintWriter(new OutputStreamWriter(out, encoding));
01101           printWriter = new PrintWriter(new OutputStreamWriter(out, encoding));
01102       } else {
01103         //return new PrintWriter(out);
01104           printWriter = new PrintWriter(out);
01105       }
01106       return printWriter;
01107     }
01108     
01117      // a caller should think about syncronization 
01118      public boolean isCommitted() {
01119        return headersWritten;
01120      }
01121      
01128      public void reset() {
01129        if (!isCommitted()) {
01130          resHeaderNames.clear();
01131        } else
01132          throw new IllegalStateException("Header have already been committed.");
01133      }
01134      
01135      public void resetBuffer() {
01136          throw new IllegalStateException("The method not implemented");
01137      }
01138         
01140      // @param resCode the status code
01141      // @param resMessage the status message
01142      // @exception IOException if an I/O error has occurred
01143      public void sendError(int resCode, String resMessage) throws IOException {
01144          setStatus(resCode, resMessage);
01145          realSendError();
01146      }
01147 
01149      // message.
01150      // @param resCode the status code
01151      // @exception IOException if an I/O error has occurred
01152      public void sendError(int resCode) throws IOException {
01153          setStatus(resCode);
01154          realSendError();
01155      }
01156 
01158      // location URL.
01159      // @param location the redirect location URL
01160      // @exception IOException if an I/O error has occurred
01161      public void sendRedirect(String location) throws IOException {
01162          if (isCommitted())
01163              throw new IllegalStateException(
01164                      "Can not redirect, headers have been already written");
01165          synchronized (out) {
01166              // no more out after redirect
01167              ((ServeOutputStream) out).setReturnedAsStream(true);
01168              ((ServeOutputStream) out).setReturnedAsWriter(true);
01169          }
01170          setHeader("Location", location);
01171          setStatus(SC_MOVED_TEMPORARILY);
01172          setContentType("text/html");
01173          StringBuffer sb = new StringBuffer(200);
01174          sb.append("<HTML><HEAD>" + "<TITLE>" + SC_MOVED_TEMPORARILY
01175                  + " Moved</TITLE>" + "</HEAD><BODY BGCOLOR=\"#F1D0F2\">"
01176                  + "<H2>" + SC_MOVED_TEMPORARILY + " Moved</H2>"
01177                  + "This document has moved <a href=" + location + ">here.<HR>");
01178          Identification.writeAddress(sb);
01179          sb.append("</BODY></HTML>");
01180          setContentLength(sb.length());
01181          // to avoid further out
01182          out.print(sb.toString());
01183          out.flush();
01184      }
01185      
01186      // 2.2
01187      // do not use buffer
01188      public void setBufferSize(int size) {
01189      }
01190      
01192      // @param length the content length
01193      public void setContentLength(int length) {
01194        setIntHeader(CONTENTLENGTH, length);
01195      }
01196      
01198      // @param type the content type
01199      public void setContentType(String type) {
01200        setHeader(CONTENTTYPE, type != null ? type : "Unknown");
01201      }
01202      
01204      // @param name the header field name
01205      // @param value the header field date value
01206      public void setDateHeader(String name, long value) {
01207          setHeader(name, expdatefmt.format(new Date(value)));
01208      }
01209      
01211      // @param name the header field name
01212      // @param value the header field value
01213      public void setHeader(String name, String value) {
01214          resHeaderNames.put(name, value);
01215      }
01216      
01218      // @param name the header field name
01219      // @param value the header field integer value
01220      public void setIntHeader(String name, int value) {
01221          setHeader(name, Integer.toString(value));
01222      }
01223      
01232      public void setLocale(Locale locale) {
01233        this.locale = locale;
01234      }
01235      
01237      // @param resCode the status code
01238      public void setStatus(int resCode) {
01239          switch (resCode) {
01240          case SC_CONTINUE:
01241              setStatus(resCode, "Continue");
01242              break;
01243          case SC_SWITCHING_PROTOCOLS:
01244              setStatus(resCode, "Switching protocols");
01245              break;
01246          case SC_OK:
01247              setStatus(resCode, "Ok");
01248              break;
01249          case SC_CREATED:
01250              setStatus(resCode, "Created");
01251              break;
01252          case SC_ACCEPTED:
01253              setStatus(resCode, "Accepted");
01254              break;
01255          case SC_NON_AUTHORITATIVE_INFORMATION:
01256              setStatus(resCode, "Non-authoritative");
01257              break;
01258          case SC_NO_CONTENT:
01259              setStatus(resCode, "No content");
01260              break;
01261          case SC_RESET_CONTENT:
01262              setStatus(resCode, "Reset content");
01263              break;
01264          case SC_PARTIAL_CONTENT:
01265              setStatus(resCode, "Partial content");
01266              break;
01267          case SC_MULTIPLE_CHOICES:
01268              setStatus(resCode, "Multiple choices");
01269              break;
01270          case SC_MOVED_PERMANENTLY:
01271              setStatus(resCode, "Moved permanentently");
01272              break;
01273          case SC_MOVED_TEMPORARILY:
01274              setStatus(resCode, "Moved temporarily");
01275              break;
01276          case SC_SEE_OTHER:
01277              setStatus(resCode, "See other");
01278              break;
01279          case SC_NOT_MODIFIED:
01280              setStatus(resCode, "Not modified");
01281              break;
01282          case SC_USE_PROXY:
01283              setStatus(resCode, "Use proxy");
01284              break;
01285          case SC_BAD_REQUEST:
01286              setStatus(resCode, "Bad request");
01287              break;
01288          case SC_UNAUTHORIZED:
01289              setStatus(resCode, "Unauthorized");
01290              break;
01291          case SC_PAYMENT_REQUIRED:
01292              setStatus(resCode, "Payment required");
01293              break;
01294          case SC_FORBIDDEN:
01295              setStatus(resCode, "Forbidden");
01296              break;
01297          case SC_NOT_FOUND:
01298              setStatus(resCode, "Not found");
01299              break;
01300          case SC_METHOD_NOT_ALLOWED:
01301              setStatus(resCode, "Method not allowed");
01302              break;
01303          case SC_NOT_ACCEPTABLE:
01304              setStatus(resCode, "Not acceptable");
01305              break;
01306          case SC_PROXY_AUTHENTICATION_REQUIRED:
01307              setStatus(resCode, "Proxy auth required");
01308              break;
01309          case SC_REQUEST_TIMEOUT:
01310              setStatus(resCode, "Request timeout");
01311              break;
01312          case SC_CONFLICT:
01313              setStatus(resCode, "Conflict");
01314              break;
01315          case SC_GONE:
01316              setStatus(resCode, "Gone");
01317              break;
01318          case SC_LENGTH_REQUIRED:
01319              setStatus(resCode, "Length required");
01320              break;
01321          case SC_PRECONDITION_FAILED:
01322              setStatus(resCode, "Precondition failed");
01323              break;
01324          case SC_REQUEST_ENTITY_TOO_LARGE:
01325              setStatus(resCode, "Request entity too large");
01326              break;
01327          case SC_REQUEST_URI_TOO_LONG:
01328              setStatus(resCode, "Request URI too large");
01329              break;
01330          case SC_UNSUPPORTED_MEDIA_TYPE:
01331              setStatus(resCode, "Unsupported media type");
01332              break;
01333          case SC_INTERNAL_SERVER_ERROR:
01334              setStatus(resCode, "Internal server error");
01335              break;
01336          case SC_NOT_IMPLEMENTED:
01337              setStatus(resCode, "Not implemented");
01338              break;
01339          case SC_BAD_GATEWAY:
01340              setStatus(resCode, "Bad gateway");
01341              break;
01342          case SC_SERVICE_UNAVAILABLE:
01343              setStatus(resCode, "Service unavailable");
01344              break;
01345          case SC_GATEWAY_TIMEOUT:
01346              setStatus(resCode, "Gateway timeout");
01347              break;
01348          case SC_HTTP_VERSION_NOT_SUPPORTED:
01349              setStatus(resCode, "HTTP version not supported");
01350              break;
01351          default:
01352              setStatus(resCode, "");
01353              break;
01354          }
01355      }
01356      
01358      // @param resCode the status code
01359      // @param resMessage the status message
01360      public void setStatus(int resCode, String resMessage) {
01361          //     if (this.resCode > 0 && this.resCode != SC_OK)
01362          //             throw new IllegalStateException("Result code "+this.resCode+" was
01363          // already set.");
01364          this.resCode = resCode;
01365          this.resMessage = resMessage;
01366      }
01367 
01368 
01369      
01370      
01371 }

Generated on Mon Jul 10 10:29:33 2006 for OpenMobileIS by  doxygen 1.4.4