Jeeves - Sun's Java Server


If you're familiar with the English language, you've probably read P.G. WodeHouse. Bertie Wooster was not my hero in those books, instead, it was Jeeves, the impeccable butler. He wasn't the most colorful of characters, but he was always around when his master required his assistance.

Sun wanted their server to have a personality just like that of Jeeves. They wanted it to be unobtrusive, yet resourceful and dependable, and they've really done Jeeves proud ! This is by far the best Java based server I've seen and since it's from Sun, it certainly warrants a thorough examination.

We've been into Java since it's very inception. We were there when Gamelan, the Mecca of Java programmers, comprised of only ten entries. We were around when computer professionals would stare blankly at us when we jabbered on and on about Java, the Microsoft killer. Ours was probably the very first tutorial on the Internet ( http://www.neca.com/~vmis/java.html ) about this most hyped of all computer languages.

So when Sun launched their Internet server written in Java, we immediately downloaded a copy. Upon reading the help, we were told we needed version 1.0.2 of the JDK, so we went and installed that. Apparently, the latest version of the JDK is a must, without it not even the smallest example will work. After installing the server on our C drive, we went into the directory it created, called JeevesA1. From there we ran the file httpd.exe, which resides in Bin. We were rewarded for our pains when the software promptly gave us an I/O exception error !! This error meant that the program, for some reason or the other, couldn't access a file on our disk drive. The pathname in the error referred to a subdirectory called Logs in the root directory JeevesA1. We went hunting for the said directory but didn't find it anywhere, so we created one ourselves. The error never reappeared. So, before you proceed any further, we advise you to make sure you create a subdirectory called Logs within ! JeevesA1, otherwise, nothing will work.

To test out your programs, you can either startup Netscape Navigator and type http://sonal- which is the name of our Windows NT machine, or you can type in your current IP address ( use winipcfg ) or you can directly type in your domain name.( Don't let the word "Sonal" confuse you, it's a name that appears at the bottom of this page !! )

Your address could look like one of these.

http://sonal ( http://sonal and http://localhost are interchangeable )

http://localhost

http://202.54.3.74

http://www.vmukhi.com

After the address you have to add the port number which is 8888 by default, so your address will have to be written like this.

http://sonal:8888

http://localhost:8888

http://202.54.3.74:8888

http://www.vmukhi.com:8888

All this obviously means that the server listens on Port 8888 by default. For those of you who haven't read our WinSock tutorial, a Port number is a number engraved on each TCP/IP packet, telling TCP/IP which server software to send the packet too. For example the port number of an Http server is 80. So Jeeves will only pick up those TCP/IP packets which are addressed to port 8888.

So in the end, the address should look something like this.

http://202.54.3.74:8888/servlet/s

We ran both the server ( Jeeves ) and the client ( Netscape Navigator ) on one machine, as is usually done the world over to test out software. Just to be doubly sure and for our mental satisfaction, we also tried the various examples from a machine in another cabin. We thought about going over to Delhi to try these programs out, but after long deliberation, abandoned the idea as impractical.

The minute we entered the above mentioned URL, we got an error. To understand the error and it's implications, lets write a small servlet. To do this, go into the JeevesA1 directory and then into the servlets subdirectory and there created a file called s.java.

s.java



import java.servlet.*;

import java.io.*;

public class s extends Servlet

{

  public void service(ServletRequest req,ServletResponse res) throws IOException

        {      

	res.setContentType("text/html");

                res.writeHeaders();

                PrintStream out = new PrintStream(res.getOutputStream());

                out.println("hello");

        }

}

Note : We're not here to teach you Java, so we wouldn't spend much time on explaining the code. If you want to learn Java, check out our Java tutorial at http://www.neca.com/~vmis/java.html.

Here we have two import statements, because we'll be using a lot of Java classes that have been created to help us program applets as well as servlets. We also have our own class called s. s extends Servlet, meaning that whatever functions are contained in Servlet are now also contained in s, plus some more of our own stuff. All that we have in the class right now, is one function called service. Since this function throws an exception, we have to end by saying, throws IOException. This function needs two parameters, one is an object that looks like ServletRequest, and the other is an object that looks like ServletResponse. We don't really have to bother with what these objects do right now.

Save the file and run it through the Java compiler, javac. You think you'll end up with a file called s.class in the servlets subdirectory, but all you'll get is a screenfull of angry errors messages. This is because your classpath variable is not set correctly. To correct this oversight, say, set classpath=c:\JeevesA1\Lib\classes.zip;. Compile. Now you get a .class file.

Now go to the admin subdirectory ( C:\JeevesA1\admin )and add this one line to a file there called servlet.properties.

s.code=s

What we're telling the server is that the code for the servlet is in the file s.class. After writing this line down, restart the server. The reason you have to restart your server is because that servlet.properties file is read only once, i.e. at startup. Now, from anywhere in the world, type http://name_of_your_machine:8888/servlet/s and you'll see the words Hello on your screen. If you don't, click on reload, because the page might have be cached by your browser.

This now means that we have created an HTML page on the fly. So you can now have dynamically generated data on your documents. You could have image maps and .gifs and links and everything else that HTML permits. Whenever someone writes http://name_of_your_machine:8888/servlet/s and presses enter, s.class is loaded into memory and the function service is called.

In the function service, the second variable named res looks like ServletResponse and any object that looks like ServletResponse has a function called setContentType. All HTML documents are divided into two parts, headers and data, where the headers contain important information like content type and mime types. Instead of writing these headers ourselves, we set ContentType to text/html and using res, we automatically create these headers.

In res, there is a function called getOutputStream, which returns an object. This object is given to the constructor of PrintStream. This PrintStream is like res.getOutPutStream, but it has more scope for fancy formatting. This object has a function called println, so we can use out.println("hello"); to display Hello on the screen.

Usually, when you're sitting and surfing around using your browser, you're downloading and viewing HTML files from the server. But now, I'm not bringing in an html file, I'm running a program on the server. This program could either be a C/C++ .exe, Visual Basic, Delphi, or a perl script, or it could be a .dll. You must be clear that when you say http://202.54.3.74:8888/servlet/s, you are calling a program and not directly downloading an HTML file. This program uses println to send output to the server, which passes this dynamically created html page onto the client.

To give your program an html extension, shut down your server by pressing Ctrl+C. Then go into the admin subdirectory and edit the file rules.properties. In this file, add a line saying

 /s.html=s

Now reload the server and type http://202.54.3.74:8888/s.html in the server.

Since /s.html has been initialized to s in the file rules.properties, you'll receive the same output as always.

Now, isn't this CGI programming ? We can't compare it with Microsoft's solution, but it's way better than kinky ol' Perl !! Since the program runs on the server and is entirely invisible to the user, you can create any sort of HTML document on the fly. And no one can tell if you've got a Java server.

So now, lets look at a little more code.

s.java



import java.servlet.*;

import java.io.*;

public class s extends Servlet

{

        public void service(ServletRequest req,ServletResponse res) throws IOException

        {       

	res.setContentType("text/html");

                res.writeHeaders();

                PrintStream out = new PrintStream(res.getOutputStream());

                out.println("<b>hello</b>");

        }

}

In this example, all that we've done is, add some HTML tags, like <b> and </b>, to make the Hello appear in bold. This proves, once and for all, that the file sent to the browser at the other end, is a HTML file.

Now lets look at example no. 3



s.java



import java.io.*;

import java.servlet.*;



public class s extends Servlet

{

        public void service(ServletRequest req,ServletResponse res) throws IOException

        {       

	res.setContentType("text/html");

                res.writeHeaders();

                PrintStream out = new PrintStream(res.getOutputStream());

                out.println("<b>hello</b><p>");

                out.println( "Request method : " + req.getMethod()+"<p>");

                out.println( "Request URI : "+ req.getRequestURI()+"<p>");

                out.println( "Request protocol : "+ req.getProtocol()+"<p>");

                out.println( "Servlet path : " + req.getServletPath()+"<p>");

                out.println( "Path info : " + req.getPathInfo()+"<p>");

                out.println( "Path translated : " + req.getPathTranslated()+"<p>");

                out.println( "Query string : " + req.getQueryString()+"<p>");

                out.println( "Content length : " + req.getContentLength()+"<p>");

                out.println( "Content type : " + req.getContentType()+"<p>");

                out.println( "Server name : " + req.getServerName()+"<p>");

                out.println( "Server port : " + req.getServerPort()+"<p>");

                out.println( "Remote user : " + req.getRemoteUser()+"<p>");

                out.println( "Remote address : " + req.getRemoteAddr()+"<p>");

                out.println( "Remote host : "+ req.getRemoteHost()+"<p>");

                out.println( "Authorization scheme : " + req.getAuthType()+"<p>");

        }

}



Remember to restart the server before you run this program.

The reason we have the first parameter as ServletRequest is because every CGI program gets a set of environmental variables. According to an Indian programmer named Murari, who wrote the sample programs for Purveyor, there are 24 of them.

This object, that looks like ServletRequest has a large number of functions with names similar to the list of environmental variables. This is definitely a simpler way of getting environmental variables, better than using Associative arrays, the method that Perl employs.

Refer to our other tutorials to learn more about environmental variables.

Now lets look at the next example:

s.java



import java.io.*;

import java.util.*;

import java.servlet.*;



public class s extends Servlet

{

        public void service(ServletRequest req,ServletResponse res) throws IOException

        {

                String aa = req.getQueryParameter("user");

                String bb = req.getQueryParameter("addr");

                res.setContentType("text/html");

                res.writeHeaders();

                PrintStream out = new PrintStream(res.getOutputStream());

                out.println(aa+"<p>");

                out.println(bb+"<p>");

        }

}





a1.html



<html>
<b>Test</b>
<form action=/servlet/s method=get>


<input type=text name=user>
<input type=text name=addr>
<input type=submit value="Click...">


</form>
</html>

First load on the HTML file, which will display a form with one button and two text boxes which use the GET method to send data. So when you click on the button, the servlet, s.class will be executed.

To find out what the user keyed into the text boxes, we have a function in ServletRequest called getQueryParameter. In the form, the textboxes have been christened 'user' and 'addr' and using getQueryParameter we can determine their contents.

We're using println to send a copy of the data back to the user.

Now lets take a look at Sockets programming using Java.

import java.servlet.*;

import java.io.*;

import java.net.*;

public

class y extends Servlet {

URL u;URLConnection c;InputStream n;DataInputStream d;String s;

public void service(ServletRequest req, ServletResponse res) throws IOException

    {

	res.setContentType("text/html");

	res.writeHeaders();

	PrintStream out = new PrintStream(res.getOutputStream());

	out.println("<html>");

	out.println("<head><title>Hello World</title></head>");

	out.println("<body>");

	out.println("<h1>Hello World</h1>");

	try

	{

	u=new URL("http://www.neca.com/~vmis/java.html");

	c = u.openConnection();

	n = c.getInputStream();

	d=new DataInputStream(n);

	while ((s=d.readLine()) != null )

	out.println(s);

	n.close();

	}

	catch(Exception x){}

	out.println("</body></html>");

    }

}

I suggest that you go ahead and read the WinSock tutorial we have up on our site (http://www.neca.com/~vmis ) to learn more about how you can make Internet ready software.

In this program, you have to clearly state the new URL you wish to access, which in this case, is "http://www.neca.com/~vmis/java.html ". After typing in the URL of our Java tutorial, we use u.openConnection to create a TCP/IP connection between our machine and the neca.com server. u.OpenConnection will return an object that looks like UrlConnection. To get the data ( the HTML file ) from the server, we use the function named getInputStream in UrlConnection and store the data in n. D is an object created by saying new DataInputStream, of the InputStream n.

At the moment we don't need an OutputStream because we're not going to send any data to the other end. The function readline will give us the data one line at a time and is a lot like the receive function in WinSock programming.

s.java



import java.io.*;

import java.net.*;

import java.servlet.*;



public class s extends Servlet

{

        URL u;URLConnection c;InputStream n;DataInputStream d;String s;

        public void service(ServletRequest req,ServletResponse res) throws IOException

        {

                String aa = req.getQueryParameter("url");

                res.setContentType("text/html");

                res.writeHeaders();

                PrintStream out = new PrintStream(res.getOutputStream());

                out.println("<html>");

                out.println("<body>");

                out.println("URL:"+aa+"<p>");

                try

                {

                u=new URL(aa);

                c = u.openConnection();

                n = c.getInputStream();

                d=new DataInputStream(n);

                while ((s=d.readLine()) != null )

                out.println(s);

                n.close();

                }

                catch(Exception x){}

                out.println("</body>");

                out.println("</html>");

        }

}



a1.html

 

<html>
<b>Test</b>
<form action=/servlet/s method=get>


Enter the URL:<p>
<input type=text size=30 name=url><p>
<input type=submit value="Click...">


</form>
</html>

Here we go one step further, using req.getQueryParameters with the URL, so whatever is typed into the edit box is sent to the page when the user clicks on the submit button.

zzz.java



import java.io.*;

import java.net.*;

public class zzz {

    public static void main(String[] args) {

        Socket S = null;

        PrintStream os = null;

        DataInputStream is = null;

        try {

        System.out.println("Before Socket");

        S = new Socket("giasbm01.vsnl.net.in", 25);

        System.out.println("Before PrintStream");

        os = new PrintStream(S.getOutputStream());

        System.out.println("Before DataInputStream");

        is = new DataInputStream(S.getInputStream());

        } 

        catch (UnknownHostException e) {

            System.err.println("Don't know about host: taranis");

        } 

        catch (IOException e) {

            System.err.println("Couldn't get I/O for the connection to: taranis");

        }

        try 

        {

        StringBuffer buf = new StringBuffer(50);

        int c;

        String s;

        s = is.readLine();

        System.out.println(s);

        os.println("HELO sonal.com");

        s = is.readLine();

        System.out.println(s);

        os.println("MAIL FROM:<vmukhi@giasbm01.vsnl.net.in>");

        s = is.readLine();

        System.out.println(s);

        os.println("RCPT TO:<vijay1@giasbm01.vsnl.net.in>");

        s = is.readLine();

        System.out.println(s);

        os.println("DATA");

        s = is.readLine();

        System.out.println(s);

        os.println("To: aaa.com");

        os.println("From sonal@stupid.com");

        os.println("DATE: 10 Jan 95 13:24 PST ");

        os.println("Message_ID: 4320");

        os.println("Good");

        os.println("Bad");

        os.println(".");

        s = is.readLine();

        System.out.println(s);

        os.println("QUIT");

        s = is.readLine();

        System.out.println(s);

        os.close();

        is.close();

        S.close();

        } catch (UnknownHostException e) {

                System.err.println("Trying to connect to unknown host: " + e);

            } catch (IOException e) {

                System.err.println("IOException:  " + e);

            }

        }

}



This is a simple program that sends email. It's workings are self evident and don't really need any additional explanation. If you want, you can add some more code and turn this into a working, generic mailing program.

To learn more about servlets and native code, read our tutorial on Natives.

Why a servlet ?

An applet can come over to your machine from any site on the Internet. Since you can't be sure who it is who is writing the code, applets have a lot of security restrictions. They can't write to your disk and they can't even call stuff from any other machine, save the one they came from.

Like the applet runs on your browser, the servlet runs on the server, but because the server administration has taken charge of this servlet and is responsible for it, you can be sure that it doesn't contain malicious code. A servlet is hindered by almost none of the restrictions that apply to applets. They can call code from other machines and be called by other machines too. If they are called from another server, then the normal security restrictions apply. Finally, because they don't have to be downloaded, they don't slow you down !

Since security restrictions on a servlet are a little lax, I can call what is named native code. These are Java functions, written in C, that can be called from a servlet. To learn more about them, read our tutorial on Natives.

In the next round of this tutorial, we're going to use both C and Java together to write a Ping program, along with other stuff like a Traceroute program. You've already seen a program ( Program 6 ) that downloads an HTML page. We're going to be writing more programs like that plus applications which send mail using SMTP ( Program 7 ) and receive it using POP3 ( will be put up soon ). We'll even teach you how to access different search engines directly, bypassing their pages.

The good thing about all this is that we're using virtually the same code everywhere. That means that by just changing a couple of lines, deleting some and adding some more, you can change an ActiveX mail reader into a LiveConnect Object, or you use Perl or anything else. If your basics are clear, then you can apply the same ideas to different languages and compilers, simply changing the syntax.

However, when you're sitting on your machine and running these programs, you won't be able to tell the difference between a Java servlet, a C/C++ program or an ActiveX Object. You won't be able to make out whether this program is on the client's side or on the server's. This means that now you can use whatever language you're comfortable with, knowing that the user will not be able to notice any difference between a Perl script or a LiveConnect Object. The choice of technology is finally, yours.


The above tutorial is a joint effort of

Mr. Vijay Mukhi
Ms. Sonal Kotecha
Mr. Arsalan Zaidi


Visit the top magazine devoted exclusively to Java: JavaWorld .They offer tutorials, tips and tricks,news, how-to's, and more. If you have any suggestions, comments, ideas, cracked code, feedback, feel free to get in touch with us.

Move back to the Vijay Mukhi's Technology Cornucopia Page to learn more about the other new Internet Technologies.


Vijay Mukhi's Computer Institute
VMCI, B-13, Everest Building, Tardeo, Bombay 400 034, India
E-mail:vmukhi@giasbm01.vsnl.net.in Tel : 91-22-496 4335 /6/7/8/9 Fax : 91-22-307 28 59
http://www.neca.com/~vmis