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

WebServer.java

00001 /*
00002  * OpenMobileIS - a free Java(TM) Framework for mobile applications Java(TM)
00003  * Copyright (C) 2004-2005 Philippe Delrieu
00004  * All rights reserved.
00005  * Contact: openmobileis@e-care.fr
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.DataInputStream;
00033 import java.io.File;
00034 import java.io.FileInputStream;
00035 import java.io.IOException;
00036 import java.io.InputStream;
00037 import java.net.MalformedURLException;
00038 import java.net.ServerSocket;
00039 import java.net.Socket;
00040 import java.net.URL;
00041 import java.util.Enumeration;
00042 import java.util.Hashtable;
00043 import java.util.Properties;
00044 import java.util.StringTokenizer;
00045 import java.util.Vector;
00046 
00047 import javax.servlet.RequestDispatcher;
00048 import javax.servlet.Servlet;
00049 import javax.servlet.ServletContext;
00050 import javax.servlet.ServletException;
00051 import javax.servlet.ServletRequest;
00052 import javax.servlet.ServletResponse;
00053 
00054 import org.openmobileis.common.util.PropertiesManager;
00055 import org.openmobileis.common.util.file.FileUtilities;
00056 import org.openmobileis.common.util.log.LogManager;
00057 import org.openmobileis.common.util.log.LogServices;
00058 
00059 public class WebServer implements ServletContext, RequestDispatcher {
00060     
00061     private final static int DEFAULT_PORT = 8080;
00062     
00063     private ServerThreadPool connexionPool;
00064     
00065     protected PathTreeDictionary registry;
00066     // loaded servlets : ClassName -> servlet instance
00067     private Hashtable servlets = new Hashtable();
00068     
00069     private Hashtable attributes;
00070     
00071     boolean running = true;
00072     private ServerSocket serverSocket;
00073     protected String hostName;
00074     protected int port = DEFAULT_PORT;
00075     
00076     private static Properties webserverProps;
00077     
00078     // path for properties
00079     public static String servletFile = "";
00080     public static String installPath = "";
00081 
00082     
00084     
00085     public WebServer() {
00086         this(null);
00087     }
00088     
00089     public WebServer(String pathToConfFile) {
00090         try {
00091             if (pathToConfFile != null) {
00092                 webserverProps = PropertiesManager.getManager().getPropertiesFromPath(pathToConfFile+java.io.File.separator+"properties"+java.io.File.separator+"webserver.properties");
00093             } else {
00094                 webserverProps = PropertiesManager.getManager().getPropertiesFromPath("properties"+java.io.File.separator+"webserver.properties");
00095             }
00096             
00097         } catch (Exception ex) {
00098             System.out.println("Unable to find webserver.properties !!\nexit(1)");
00099             System.exit(1);
00100         }
00101         String strPort = webserverProps.getProperty("port");
00102         if (strPort != null && strPort.length() > 0) {
00103             try {
00104                 this.port = Integer.parseInt(strPort);
00105             } catch (NumberFormatException ex) {
00106                 this.port = DEFAULT_PORT;
00107             }
00108         }
00109         
00110         WebServer.installPath = webserverProps.getProperty("installPath");
00111         servletFile = webserverProps.getProperty("servletFile");
00112         registry = new PathTreeDictionary();
00113         try {
00114             connexionPool = new ServerThreadPool();
00115         } catch (Exception ex) {
00116             LogManager.traceError(LogServices.WEBSERVICE,
00117                     "can not initialise server connexion pool");
00118             LogManager.traceError(0, ex);
00119         }
00120         attributes = new Hashtable();
00121     }
00122     
00124     // pattern, which can contain wildcards, and the class name of the Servlet
00125     // to launch when a matching URL comes in.  Patterns are checked for
00126     // matches in the order they were added, and only the first match is run.
00127     public void addServlet(String urlPat, String className) {
00128       addServlet(urlPat, className, (Hashtable) null);
00129     }
00130 
00131     public void addServlet(String urlPat, String className, Hashtable initParams) {
00132       // Check if we're allowed to make one of these.
00133       SecurityManager security = System.getSecurityManager();
00134       if (security != null) {
00135         int i = className.lastIndexOf('.');
00136         if (i != -1) {
00137           security.checkPackageAccess(className.substring(0, i));
00138           security.checkPackageDefinition(className.substring(0, i));
00139         }
00140       }
00141 
00142       // Make a new one.
00143       try {
00144         addServlet(urlPat, (Servlet) Class.forName(className).newInstance(), initParams);
00145         return;
00146       } catch (ClassNotFoundException e) {
00147         LogManager.traceError(0, e);
00148         LogManager.traceError(LogServices.WEBSERVICE, "Class not found: " + className);
00149       } catch (ClassCastException e) {
00150         LogManager.traceError(0, e);
00151         LogManager.traceError(LogServices.WEBSERVICE, "Class cast problem: " + e.getMessage());
00152       } catch (InstantiationException e) {
00153         LogManager.traceError(0, e);
00154         LogManager.traceError(LogServices.WEBSERVICE, "Instantiation problem: " + e.getMessage());
00155       } catch (IllegalAccessException e) {
00156         LogManager.traceError(0, e);
00157         LogManager.traceError(LogServices.WEBSERVICE, "Illegal class access: " + e.getMessage());
00158       } catch (Exception e) {
00159         LogManager.traceError(0, e);
00160         LogManager.traceError(LogServices.WEBSERVICE, "Unexpected problem creating servlet: " + e);
00161         LogManager.traceError(LogServices.WEBSERVICE, e);
00162       }
00163     }
00164 
00166     // which can contain wildcards, and the Servlet to
00167     // launch when a matching URL comes in.  Patterns are checked for
00168     // matches in the order they were added, and only the first match is run.
00169     public void addServlet(String urlPat, Servlet servlet) {
00170       addServlet(urlPat, servlet, (Hashtable) null);
00171     }
00172 
00173     public void addServlet(String urlPat, Servlet servlet, Hashtable initParams) {
00174       try {
00175         servlet.init(new ServeConfig((ServletContext) this, initParams, urlPat));
00176         registry.put(urlPat, servlet);
00177         servlets.put(servlet.getClass().getName(), urlPat);
00178       } catch (ServletException e) {
00179           LogManager.traceError(0, e);
00180           LogManager.traceError(LogServices.WEBSERVICE,
00181                   "Problem initializing servlet: " + e);
00182       }
00183     }
00184     
00185     public Object[] getServletByURLorClassName(String name) {
00186         Object[] servlet = new Object[2];
00187         servlet = registry.get(name);
00188         if (servlet[0] == null) {
00189             String servletUri = (String)servlets.get(name);
00190             if (servletUri != null && servletUri.trim().length() > 0) {
00191                 servlet = registry.get(servletUri);
00192             }
00193         }
00194         if (servlet[0] == null) {
00195             String newName = name;
00196             int index = newName.lastIndexOf('/');
00197             while (index != -1) {
00198                 newName = newName.substring(0, index);
00199                 servlet = registry.get(newName);
00200                 if (servlet[0] != null) {
00201                     break;
00202                 }
00203                 index = newName.lastIndexOf('/');
00204             }
00205         }
00206         return servlet;
00207     }
00208     
00209     // Run the server.  Returns only on errors.
00210     public void serve() {
00211         // Load Servlets
00212         //this.loadServlets();
00213         this.readServlets(servletFile);
00214         
00215         try {
00216             serverSocket = new ServerSocket(port, 1000);
00217         } catch (IOException e) {
00218             LogManager.traceError(0, e);
00219             LogManager.traceError(LogServices.WEBSERVICE, "Server socket: " + e);
00220             return;
00221         }
00222         hostName = serverSocket.getInetAddress().getHostName();
00223         try { // accept request from clients
00224             while (true) {
00225                 Socket socket = serverSocket.accept();
00226                 connexionPool.runServerConnexion(this, socket);
00227             } // end while
00228         } catch (IOException e) {
00229             LogManager.traceError(0, e);
00230             LogManager.traceError(LogServices.WEBSERVICE,
00231                     "IOEXception during servlet process Accept: " + e);
00232         } finally {
00233             try {
00234                 serverSocket.close();
00235             } catch (Exception e) {
00236                 LogManager.traceError(LogServices.WEBSERVICE, e);
00237             }
00238         }
00239     }
00240     
00242     public void destroyAllServlets() {
00243       Enumeration en = registry.elements();
00244       while (en.hasMoreElements()) {
00245         Servlet servlet = (Servlet) en.nextElement();
00246         servlet.destroy();
00247       }
00248       registry = new PathTreeDictionary();
00249       // invalidate all sessions?
00250     }
00251     
00252     /*
00253      * free all resources
00254      */
00255     public void freeResources() throws Exception {
00256         this.destroyAllServlets();
00257         serverSocket.close();
00258         LogManager.traceInfo(LogServices.WEBSERVICE, "Web server is stopped");
00259         System.exit(0);
00260     }
00261     
00262     private void readServlets(String cfgfile) {
00267         Hashtable servletstbl, parameterstbl;
00268         servletstbl = new Hashtable();
00269         parameterstbl = new Hashtable();
00270         if (cfgfile != null) {
00271           File file = new File(cfgfile);
00272           if (file.exists() && file.canRead()) {
00273             try {
00274               DataInputStream in = new DataInputStream(new FileInputStream(file));
00278               do {
00279                 String servletdsc = in.readLine();
00280                 if (servletdsc == null)
00281                   break;
00282                 StringTokenizer dsctokenzr = new StringTokenizer(servletdsc, ".=,", false);
00283                 if (dsctokenzr.hasMoreTokens()) {
00284                   if (!dsctokenzr.nextToken().equalsIgnoreCase("servlet")) {
00285                     System.err.println("No leading 'servlet' keyword, the sentence is skipped");
00286                     break;
00287                   }
00288                   if (dsctokenzr.hasMoreTokens()) {
00289                     String servletname = dsctokenzr.nextToken();
00290 
00291                     if (dsctokenzr.hasMoreTokens()) {
00292                       String lt = dsctokenzr.nextToken();
00293                       if (lt.equalsIgnoreCase("code")) {
00294                         if (dsctokenzr.hasMoreTokens())
00295                           servletstbl.put(servletname, dsctokenzr.nextToken("="));
00296                       } else if (lt.equalsIgnoreCase("initArgs")) {
00297                         Hashtable initparams = new Hashtable();
00298                         while (dsctokenzr.hasMoreTokens()) {
00299                           String key = dsctokenzr.nextToken("=,");
00300                           if (dsctokenzr.hasMoreTokens())
00301                             initparams.put(key, dsctokenzr.nextToken(",="));
00302                         }
00303                         parameterstbl.put(servletname, initparams);
00304                       } else
00305                         System.err.println("Unrecognized token " + lt + " in " + servletdsc + ", the line's skipped");
00306                     }
00307                   }
00308                 }
00309               }
00310               while (true);
00311             } catch (IOException e) {
00312               System.err.println("Problem reading cfg file: " + e);
00313             }
00314             Enumeration se = servletstbl.keys();
00315             String servletname;
00316             while (se.hasMoreElements()) {
00317               servletname = (String) se.nextElement();
00318               addServlet(servletname, (String) servletstbl.get(servletname), (Hashtable) parameterstbl.get(servletname));
00319             }
00320           }
00321         }
00322       }
00323     
00324 /*    protected void loadServlets() {
00325         // load servlets
00326         
00327         // add the FileServlet by default. By default, if there is no matching
00328         // with the other servlet,
00329         // the file servlet is choosen
00330         this.addServlet("/FileServlet", "org.openmobileis.services.servlet.FileServlet");
00331         
00332         java.util.Properties props = new java.util.Properties();
00333         try {
00334             props.load(new java.io.FileInputStream(servletFile));
00335             java.util.Enumeration enum = props.propertyNames();
00336             while (enum.hasMoreElements()) {
00337                 String className = (String) enum.nextElement();
00338                 String pattern = (String) props.getProperty(className);
00339                 this.addServlet(pattern, className);
00340             }
00341         } catch (IOException ex) {
00342             LogManager.traceError(0, ex);
00343         }
00344     }*/
00345     
00346     
00347     
00348     
00349     
00350     
00351     // ServletContext METHODS
00352     // ***************************************************************************************************************
00353 
00355     // null if the attribute does not exist.  This method allows access to
00356     // additional information about the service, not already provided by
00357     // the other methods in this interface.
00358     public Object getAttribute(String name) {
00359       // This server does not support attributes.
00360       return attributes.get(name);
00361     }
00362     
00363     public Enumeration getAttributeNames() {
00364         return attributes.keys();
00365         }
00366     
00367     public ServletContext getContext(String uripath) {
00368         return this; // only root context supported
00369         }
00370     
00371     // no way to specify parameters for context
00372     public String getInitParameter(String param) {
00373       return null;
00374     }
00375     
00376     public Enumeration getInitParameterNames() {
00377         return null;
00378         }
00379     
00380     public int getMajorVersion() {
00381         return 2; // support 2.x
00382         }
00383 
00385     // @param file file name whose MIME type is required
00386     public String getMimeType(String file) {
00387       file = file.toUpperCase();
00388 
00389       if (file.endsWith(".HTML") || file.endsWith(".HTM"))
00390         return "text/html";
00391       if (file.endsWith(".TXT"))
00392         return "text/plain";
00393       if (file.endsWith(".XML"))
00394         return "text/xml";
00395       if (file.endsWith(".CSS"))
00396         return "text/css";
00397       if (file.endsWith(".SGML") || file.endsWith(".SGM"))
00398         return "text/x-sgml";
00399       // Image
00400       if (file.endsWith(".GIF"))
00401         return "image/gif";
00402       if (file.endsWith(".JPG") || file.endsWith(".JPEG") || file.endsWith(".JPE"))
00403         return "image/jpeg";
00404       if (file.endsWith(".PNG"))
00405         return "image/png";
00406       if (file.endsWith(".TIF") || file.endsWith(".TIFF"))
00407         return "image/tiff";
00408       if (file.endsWith(".RGB"))
00409         return "image/x-rgb";
00410       if (file.endsWith(".XPM"))
00411         return "image/x-xpixmap";
00412       if (file.endsWith(".XBM"))
00413         return "image/x-xbitmap";
00414       if (file.endsWith(".SVG"))
00415         return "image/svg-xml ";
00416       if (file.endsWith(".SVGZ"))
00417         return "image/svg-xml ";
00418       // Audio
00419       if (file.endsWith(".AU") || file.endsWith(".SND"))
00420         return "audio/basic";
00421       if (file.endsWith(".MID") || file.endsWith(".MIDI") || file.endsWith(".RMI") || file.endsWith(".KAR"))
00422         return "audio/mid";
00423       if (file.endsWith(".MPGA") || file.endsWith(".MP2") || file.endsWith(".MP3"))
00424         return "audio/mpeg";
00425       if (file.endsWith(".WAV"))
00426         return "audio/wav";
00427       if (file.endsWith(".AIFF") || file.endsWith(".AIFC"))
00428         return "audio/aiff";
00429       if (file.endsWith(".AIF"))
00430         return "audio/x-aiff";
00431       if (file.endsWith(".RA"))
00432         return "audio/x-realaudio";
00433       if (file.endsWith(".RPM"))
00434         return "audio/x-pn-realaudio-plugin";
00435       if (file.endsWith(".RAM"))
00436         return "audio/x-pn-realaudio";
00437       if (file.endsWith(".SD2"))
00438         return "audio/x-sd2";
00439       // Application
00440       if (file.endsWith(".BIN") || file.endsWith(".DMS") || file.endsWith(".LHA") || file.endsWith(".LZH") || file.endsWith(".EXE") || file.endsWith(".CLASS"))
00441         return "application/octet-stream";
00442       if (file.endsWith(".HQX"))
00443         return "application/mac-binhex40";
00444       if (file.endsWith(".PS") || file.endsWith(".AI") || file.endsWith(".EPS"))
00445         return "application/postscript";
00446       if (file.endsWith(".PDF"))
00447         return "application/pdf";
00448       if (file.endsWith(".RTF"))
00449         return "application/rtf";
00450       if (file.endsWith(".DOC"))
00451         return "application/msword";
00452       if (file.endsWith(".PPT"))
00453         return "application/powerpoint";
00454       if (file.endsWith(".FIF"))
00455         return "application/fractals";
00456       if (file.endsWith(".P7C"))
00457         return "application/pkcs7-mime";
00458       // Application/x
00459       if (file.endsWith(".JS"))
00460         return "application/x-javascript";
00461       if (file.endsWith(".Z"))
00462         return "application/x-compress";
00463       if (file.endsWith(".GZ"))
00464         return "application/x-gzip";
00465       if (file.endsWith(".TAR"))
00466         return "application/x-tar";
00467       if (file.endsWith(".TGZ"))
00468         return "application/x-compressed";
00469       if (file.endsWith(".ZIP"))
00470         return "application/x-zip-compressed";
00471       if (file.endsWith(".DIR") || file.endsWith(".DCR") || file.endsWith(".DXR"))
00472         return "application/x-director";
00473       if (file.endsWith(".DVI"))
00474         return "application/x-dvi";
00475       if (file.endsWith(".TEX"))
00476         return "application/x-tex";
00477       if (file.endsWith(".LATEX"))
00478         return "application/x-latex";
00479       if (file.endsWith(".TCL"))
00480         return "application/x-tcl";
00481       if (file.endsWith(".CER") || file.endsWith(".CRT") || file.endsWith(".DER"))
00482         return "application/x-x509-ca-cert";
00483       // Video
00484       if (file.endsWith(".MPG") || file.endsWith(".MPE") || file.endsWith(".MPEG"))
00485         return "video/mpeg";
00486       if (file.endsWith(".QT") || file.endsWith(".MOV"))
00487         return "video/quicktime";
00488       if (file.endsWith(".AVI"))
00489         return "video/x-msvideo";
00490       if (file.endsWith(".MOVIE"))
00491         return "video/x-sgi-movie";
00492       // Chemical
00493       if (file.endsWith(".PDB") || file.endsWith(".XYZ"))
00494         return "chemical/x-pdb";
00495       // X-
00496       if (file.endsWith(".ICE"))
00497         return "x-conference/x-cooltalk";
00498       if (file.endsWith(".WRL") || file.endsWith(".VRML"))
00499         return "x-world/x-vrml";
00500       if (file.endsWith(".WML"))
00501         return "text/vnd.wap.wml";
00502       if (file.endsWith(".WMLC"))
00503         return "application/vnd.wap.wmlc";
00504       if (file.endsWith(".WMLS"))
00505         return "text/vnd.wap.wmlscript";
00506       if (file.endsWith(".WMLSC"))
00507         return "application/vnd.wap.wmlscriptc";
00508       if (file.endsWith(".WBMP"))
00509         return "image/vnd.wap.wbmp";
00510 
00511       return null;
00512     }
00513     
00514         public int getMinorVersion() {
00515             return 3; // support 2.3
00516         }
00517     
00518     public RequestDispatcher getNamedDispatcher(String name) {
00519         return this;
00520     }
00521     
00522     public String getRealPath(String path) {
00523         return installPath + FileUtilities.convertFileNameToSystem(path);
00524         //return htdocs + File.separator + FileUtilities.convertFileNameToSystem(path);
00525     }
00526     
00527     public RequestDispatcher getRequestDispatcher(String path) {
00528         return this;
00529     }
00530     
00531     // only root relative in this implementation
00532     public URL getResource(String path) throws MalformedURLException {
00533       return new URL("http", hostName, port, path);
00534     }
00535     
00536     public InputStream getResourceAsStream(String path) {
00537         return null; // we don't provide resources in this way
00538         }
00539     
00540     public java.util.Set getResourcePaths(java.lang.String path) {
00541         // TODO: implement
00542         return null;
00543         }
00544     
00546     // is running.
00547     // Same as the CGI variable SERVER_SOFTWARE.
00548     public String getServerInfo() {
00549       return Identification.serverName + " " + Identification.serverVersion + " (" + Identification.serverUrl + ")";
00550     }
00551     
00552     public Servlet getServlet(String name) {
00553         // Deprecated. As of Java Servlet API 2.1, with no direct replacement.
00554         // This method was originally defined to retrieve a servlet from a ServletContext.
00555         // In this version, this method always returns null and remains only to preserve binary compatibility.
00556         // This method will be permanently removed in a future version of the Java Servlet API.
00557 
00558         // In lieu of this method, servlets can share information using the ServletContext class
00559         // and can perform shared business logic by invoking methods on common non-servlet classes.
00560         return null;
00561     }
00562     
00569     public java.lang.String getServletContextName() {
00570       return null; //"ROOT";
00571     }
00572     
00574     // servlets that are accesible will be returned.  This enumeration always
00575     // includes the servlet itself.
00576     public Enumeration getServletNames() {
00577         // Deprecated. As of Java Servlet API 2.1, with no replacement.
00578         // This method was originally defined to return an Enumeration of all the servlet names known to this context.
00579         // In this version, this method always returns an empty Enumeration and remains only to preserve binary compatibility.
00580         // This method will be permanently removed in a future version of the Java Servlet API.
00581         return new Vector().elements();
00582         }
00583     
00584     public Enumeration getServlets() {
00585         // Deprecated. As of Java Servlet API 2.0, with no replacement.
00586         // This method was originally defined to return an Enumeration of all the servlets known to this servlet context.
00587         // In this version, this method always returns an empty enumeration and remains only to preserve binary compatibility.
00588         // This method will be permanently removed in a future version of the Java Servlet API.
00589         return new Vector().elements();
00590     }
00591     
00592     public void log(Exception exception, String msg) {
00593         LogManager.traceWarning(LogServices.WEBSERVICE, msg);
00594         LogManager.traceWarning(LogServices.WEBSERVICE, exception);
00595     }
00596     
00597     public void log(String msg) {
00598         LogManager.traceWarning(LogServices.WEBSERVICE, msg);
00599     }
00600     
00601     public void log(String message, Throwable throwable) {
00602         LogManager.traceWarning(LogServices.WEBSERVICE, message);
00603         LogManager.traceWarning(LogServices.WEBSERVICE, throwable);
00604     }
00605     
00606     public void removeAttribute(String name) {
00607         attributes.remove(name);
00608         }
00609     
00610     public void setAttribute(String name, Object object) {
00611         attributes.put(name, object);
00612         }
00613     
00614     
00615     
00616     // RequestDispatcher METHODS
00617     // ***************************************************************************************************************
00618     
00619     public void forward(ServletRequest request, ServletResponse response) {
00620     }
00621     public void include(ServletRequest request, ServletResponse response) {
00622     }
00623 }

Generated on Thu Oct 6 10:06:34 2005 for OpenMobileIS by  doxygen 1.4.3