views:

74

answers:

2

I have a VERY simple web server that does accepts client connections, retrieves static web pages and services servlets.

I wrote the web server in Java and I'm using the tomcat library for servlets. I tested all my code by running it in the eclipse IDE and everything works fine, but when I run my code through the command line it starts the main correctly, but as soon as I try to access a web page through the browser (http://localhost/hello.html) then the application crashes, here is a sample output:

p1>java p1Solution.WebServer 80
Waiting for a connection.
Servicing the connection.
Closing the connection and shutting down the executor.
Exception in thread "main" java.lang.NoClassDefFoundError: javax/servlet/Servlet
Exception
        at p1Solution.WebServer.main(WebServer.java:54)
Caused by: java.lang.ClassNotFoundException: javax.servlet.ServletException
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClassInternal(Unknown Source)
        ... 1 more

Here is my WebServer

public class WebServer {
    private static final ExecutorService executor = Executors.newCachedThreadPool();

    public static void main(String[] args) throws Exception {
        int port = (args.length > 0) ? Integer.parseInt(args[0]) : 80;

        // listen for clients on the port specified as a command line argument
        ServerSocket serverSocket = new ServerSocket(port);
        Socket connection = null;
        try {
            while (true) {
                try {
                    System.out.println("Waiting for a connection.");
                    // Wait for an in bound client connection
                    connection = serverSocket.accept();

                    System.out.println("Servicing the connection.");
                    // Handle the client connection in a separate thread
                    executor.execute(new ConnectionHandler(connection));
                } catch (Exception e) {
                    // Never crash the server
                    e.printStackTrace();
                }
            }
        }finally {
            System.out.println("Closing the connection and shutting down the executor.");
            connection = null;
            serverSocket.close();
            executor.shutdown();
            executor.awaitTermination(3, TimeUnit.SECONDS);
        }
    }
}

I've been googling my exception and some people have been mentioning things about the classpath, but I have not found a definitive answer yet. When I run the program in eclipse everything works fine!

Here is the directory of my project (where my project resides):

p1>ls
.classpath  bin           hello.html  p1Solution.jar
.project    coreservlets  p1Solution  testsuite

Here is the directory contents of my p1Solution (where the code resides):

p1>ls p1Solution
ConnectionHandler.class           MyHttpServletRequest.class
ConnectionHandler.java            MyHttpServletRequest.java
HttpServletRequestAdapter.class   MyHttpServletResponse.class
HttpServletRequestAdapter.java    MyHttpServletResponse.java
HttpServletResponseAdapter.class  WebServer.class
HttpServletResponseAdapter.java   WebServer.java

Can anybody help me resolve this issue? Has anybody seen this problem before?

P.S. And yes, I do have the 'ls' command in Windows and it's not magic! Google "ls for windows" if you don't believe me.

+2  A: 

You have a satisfied compile time dependency on javax.servlet.Servlet which is however not there at runtime, hence the NoClassDefFoundError. So you need to put an implementation of this class on the classpath (provided by Tomcat's servlet-api.jar). To do so, the recommended way would be to use the -cp option:

p1>java -cp c:\path\to\servlet-api.jar;. p1Solution.WebServer 80

Don't forget the "." (the current directory) in "-cp C:\path\to\servlet-api.jar;.". Also note that I'm not sure how spaces in path names are handled (I'm not under windows, can't test). So either use Windows short names 8.3 (like C:\PROGRA~1\) or don't use spaces in path names or move this library somewhere else.

Pascal Thivent
As I mentioned it might be an issue with my classpaths, here are some things I tried:"This program utilizes 2 packages that are provided by Apache: javax.servlet and javax.servlet.http. Ifyou use a simple Java environment such as the DOS-based Java SE or TextPad, then in order to facilitate easy use of the Apache Tomcat packages, you should create an environment variable called CLASSPATH.This environment variable needs to include the following path:%CATALINA_HOME%\common\lib\servlet-api.jar;.where %CATALINA_HOME% is the root directory for Tomcat (e.g., c:\apache-tomcat-6.0.14)."No luck!
Lirik
If you are under windows, please provide the output of `echo %CLASSPATH%` and `echo %CATALINA_HOME%`. By the way, this is not the recommended way to set the classpath, you should use the `-cp` option i.e. `java -cp c:\path\to\servlet-api-jar;. p1Solution.WebServer 80`.
Pascal Thivent
Here is the otuput:>echo %CLASSPATH%C:\Program Files\Apache Software Foundation\Tomcat 6.0\common\lib\servlet-api.jar>echo %CATALINA_HOME%C:\Program Files\Apache Software Foundation\Tomcat 6.0
Lirik
I set the environment variables and after restarting windows the application fails to start:"Exception in thread "main" java.lang.NoClassDefFoundError: p1Solution/WebServerCaused by: java.lang.ClassNotFoundException: p1Solution.WebServer"I only changed the environment variables... I get the same error in eclipse.
Lirik
you need the classpath to include servlet-api.jar as well as your own code
Yoni
Do what Pascal said: use the -cp option, not CLASSPATH.
jdigital
1. you don't need to restart windows 2. I think that the space in %CATALINA_HOME% may cause problems. You should use short 8.3 file names or just put that lib somewhere else.
Pascal Thivent
Doh... OK, I'll just remove the classpaths and I'll try the -cp command, I need to run the program in command line once just to confirm that it works because my teacher will most likely run in from command line.
Lirik
BTW, I figured out why after the restart I couldn't run my app: forgot to turn on the tomcat services! DOH!
Lirik
OK, thanks Pascal... I tried setting the -cp option, but I just can't get it. Packaging everything into a jar was the simpler solution, although it wasn't as educating as your solution.
Lirik
+2  A: 

Use the "Export -> Runnable Jar" facility to create a jar file with dependent libraries included underneath and properly referenced (as you do not have servlet.jar in your runtime classpath). Then you can just run

java -jar p1solution.jar
Thorbjørn Ravn Andersen
Making it into a jar and exporting the libraries did it. Thanks for the help.
Lirik