|
Spring Semester 2002 |
We start by developing an applet.
import java.applet.*;
import java.awt.*;
import java.io.*;
import java.util.*;
public class DaytimeApplet extends Applet {
TextField httpText, httpObject, socketText, socketObject, RMIObject;
Button refresh;
public void init() {
setLayout(new BorderLayout());
Panel west = new Panel();
west.setLayout(new GridLayout(5, 1));
west.add(new Label("HTTP text: ", Label.RIGHT));
west.add(new Label("HTTP object: ", Label.RIGHT));
west.add(new Label("Socket text: ", Label.RIGHT));
west.add(new Label("Socket object: ", Label.RIGHT));
west.add(new Label("RMI object: ", Label.RIGHT));
add("West", west);
Panel center = new Panel();
center.setLayout(new GridLayout(5, 1));
httpText = new TextField();
httpText.setEditable(false);
center.add(httpText);
httpObject = new TextField();
httpObject.setEditable(false);
center.add(httpObject);
socketText = new TextField();
socketText.setEditable(false);
center.add(socketText);
socketObject = new TextField();
socketObject.setEditable(false);
center.add(socketObject);
RMIObject = new TextField();
RMIObject.setEditable(false);
center.add(RMIObject);
add("Center", center);
Panel south = new Panel();
refresh = new Button("Refresh");
south.add(refresh);
add("South", south);
}
public void start() {
refresh();
}
private void refresh() {
httpText.setText(getDateUsingHttpText());
httpObject.setText(getDateUsingHttpObject());
socketText.setText(getDateUsingSocketText());
socketObject.setText(getDateUsingSocketObject());
RMIObject.setText(getDateUsingRMIObject());
}
private String getDateUsingHttpText () {
return "unavailable (for now)";
}
private String getDateUsingHttpObject () {
return "unavailable (for now)";
}
private String getDateUsingSocketText () {
return "unavailable (for now)";
}
private String getDateUsingSocketObject () {
return "unavailable (for now)";
}
private String getDateUsingRMIObject () {
return "unavailable (for now)";
}
public boolean handleEvent(Event event) {
// when the refresh button is pushed, refresh the display
// use jdk1.0 events for maximum portability
switch (event.id) {
case Event.ACTION_EVENT:
if (event.target == refresh) {
refresh();
return true;
}
}
return false;
}
}
Here's an HTML for it:
<html>
<head><title>Daytime Applet</title></head>
<body>
<center><h1>Daytime Applet</h1></center>
<center>
<applet code=DaytimeApplet
width=300
height=180>
</applet>
</center>
</body>
</html>
We place these (both files, that is) in
That's the folder for the web application we created before.$CATALINA_HOME/webapps/one
To access the applet (which does not do much at this point) we use
Here's how the folder looks now:http://burrowww.cs.indiana.edu:36xxx/one/daytime.html
Now we need a servlet.burrowww.cs.indiana.edu% pwd /nfs/paca/home/user1/dgerman/tomcat/jakarta-tomcat-4.0.3/webapps/one burrowww.cs.indiana.edu% du -a . 3 ./DaytimeApplet.class 1 ./WEB-INF/classes/HelloWorld.java 1 ./WEB-INF/classes/HelloWorld.class 3 ./WEB-INF/classes 1 ./WEB-INF/lib 1 ./WEB-INF/web.xml 6 ./WEB-INF 3 ./DaytimeApplet.java 1 ./daytime.html 14 . burrowww.cs.indiana.edu%
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class DaytimeServlet extends HttpServlet {
public Date getDate() {
return new Date();
}
public void doGet(HttpServletRequest req,
HttpServletResponse res) throws ServletException,
IOException
{ res.setContentType("text/plain");
PrintWriter out = res.getWriter();
out.println(getDate().toString());
}
public void doPost(HttpServletRequest req,
HttpServletResponse res) throws ServletException,
IOException
{ doGet(req, res);
}
}
We place this servlet in
We compile it, then we can access it from this URL, directly$CATALINA_HOME/one/WEB-INF/classes
Our goal now is to make the applet contact the servlet.http://burrowww.cs.indiana.edu:36xxx/one/servlet/DaytimeServlet
Here's the applet, with modifications:
import java.net.URL;
import java.applet.*;
import java.awt.*;
import java.io.*;
import java.util.*;
public class DaytimeApplet extends Applet {
TextField httpText, httpObject, socketText, socketObject, RMIObject;
Button refresh;
public void init() {
setLayout(new BorderLayout());
Panel west = new Panel();
west.setLayout(new GridLayout(5, 1));
west.add(new Label("HTTP text: ", Label.RIGHT));
west.add(new Label("HTTP object: ", Label.RIGHT));
west.add(new Label("Socket text: ", Label.RIGHT));
west.add(new Label("Socket object: ", Label.RIGHT));
west.add(new Label("RMI object: ", Label.RIGHT));
add("West", west);
Panel center = new Panel();
center.setLayout(new GridLayout(5, 1));
httpText = new TextField();
httpText.setEditable(false);
center.add(httpText);
httpObject = new TextField();
httpObject.setEditable(false);
center.add(httpObject);
socketText = new TextField();
socketText.setEditable(false);
center.add(socketText);
socketObject = new TextField();
socketObject.setEditable(false);
center.add(socketObject);
RMIObject = new TextField();
RMIObject.setEditable(false);
center.add(RMIObject);
add("Center", center);
Panel south = new Panel();
refresh = new Button("Refresh");
south.add(refresh);
add("South", south);
}
public void start() {
refresh();
}
private void refresh() {
httpText.setText(getDateUsingHttpText());
httpObject.setText(getDateUsingHttpObject());
socketText.setText(getDateUsingSocketText());
socketObject.setText(getDateUsingSocketObject());
RMIObject.setText(getDateUsingRMIObject());
}
private String getDateUsingHttpText () {
try {
URL url = new URL(getCodeBase(),
"servlet/DaytimeServlet");
HttpMessage msg = new HttpMessage(url);
InputStream in = msg.sendGetMessage();
DataInputStream result =
new DataInputStream(new BufferedInputStream(in));
String date = result.readLine();
in.close();
return date;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private String getDateUsingHttpObject () {
return "unavailable (for now)";
}
private String getDateUsingSocketText () {
return "unavailable (for now)";
}
private String getDateUsingSocketObject () {
return "unavailable (for now)";
}
private String getDateUsingRMIObject () {
return "unavailable (for now)";
}
public boolean handleEvent(Event event) {
// when the refresh button is pushed, refresh the display
// use jdk1.0 events for maximum portability
switch (event.id) {
case Event.ACTION_EVENT:
if (event.target == refresh) {
refresh();
return true;
}
}
return false;
}
}
This requires a whole new abstraction, class HttpMessage, below:
import java.io.*;
import java.net.*;
import java.util.*;
public class HttpMessage {
URL servlet = null;
Hashtable headers = null;
public HttpMessage(URL servlet) {
this.servlet = servlet;
}
public InputStream sendGetMessage() throws IOException {
return sendGetMessage(null);
}
public InputStream sendGetMessage(Properties args) throws IOException {
String argString = "";
if (args != null) {
argString = "?" + toEncodedString(args);
}
URL url = new URL(servlet.toExternalForm() + argString);
URLConnection con = url.openConnection();
con.setUseCaches(false);
sendHeaders(con);
return con.getInputStream();
}
public InputStream sendPostMessage() throws IOException {
return sendPostMessage(null);
}
public InputStream sendPostMessage(Properties args) throws IOException {
String argString = "";
if (args != null) {
argString = toEncodedString(args);
}
URLConnection con = servlet.openConnection();
con.setDoInput(true);
con.setDoOutput(true);
con.setUseCaches(false);
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
sendHeaders(con);
DataOutputStream out = new DataOutputStream(con.getOutputStream());
out.writeBytes(argString);
out.flush();
out.close();
return con.getInputStream();
}
public InputStream sendPostMessage(Serializable obj) throws IOException {
URLConnection con = servlet.openConnection();
con.setDoInput(true);
con.setDoOutput(true);
con.setUseCaches(false);
con.setRequestProperty("Content-Type",
"application/x-java-serialized-object");
sendHeaders(con);
ObjectOutputStream out = new ObjectOutputStream(con.getOutputStream());
out.writeObject(obj);
out.flush();
out.close();
return con.getInputStream();
}
public void setHeader(String name, String value) {
if (headers == null) {
headers = new Hashtable();
}
headers.put(name, value);
}
private void sendHeaders(URLConnection con) {
if (headers != null) {
Enumeration enum = headers.keys();
while (enum.hasMoreElements()) {
String name = (String) enum.nextElement();
String value = (String) headers.get(name);
con.setRequestProperty(name, value);
}
}
}
private String toEncodedString(Properties args) {
StringBuffer buf = new StringBuffer();
Enumeration names = args.propertyNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
String value = args.getProperty(name);
buf.append(URLEncoder.encode(name) + "=" + URLEncoder.encode(value));
if (names.hasMoreElements()) buf.append("&");
}
return buf.toString();
}
}
At this point the applet should be able to report the time in the first field.
We now move to the second method (HTTP object) so we
We now turn our attention to
The server needs to be changed first:
Now the applet has to be changed:
For the last step we use RMI.
We already need a new port for
First we need a
The stub file and the interface will have to be placed next to the applet.
enhance the servlet:
The corresponding change in the applet looks like this:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class DaytimeServlet extends HttpServlet {
public Date getDate() {
return new Date();
}
public void doGet(HttpServletRequest req,
HttpServletResponse res) throws ServletException,
IOException
{
// if the client says "format=object" then
// return the Date as a serialized object
if ("object".equals(req.getParameter("format"))) {
ObjectOutputStream out =
new ObjectOutputStream(res.getOutputStream());
out.writeObject(getDate());
} else {
PrintWriter out = res.getWriter();
out.println(getDate().toString());
}
}
public void doPost(HttpServletRequest req,
HttpServletResponse res) throws ServletException,
IOException
{ doGet(req, res);
}
}
The applet now is able to retrieve the date in both ways. import java.net.URL;
import java.applet.*;
import java.awt.*;
import java.io.*;
import java.util.*;
public class DaytimeApplet extends Applet {
TextField httpText, httpObject, socketText, socketObject, RMIObject;
Button refresh;
public void init() {
setLayout(new BorderLayout());
Panel west = new Panel();
west.setLayout(new GridLayout(5, 1));
west.add(new Label("HTTP text: ", Label.RIGHT));
west.add(new Label("HTTP object: ", Label.RIGHT));
west.add(new Label("Socket text: ", Label.RIGHT));
west.add(new Label("Socket object: ", Label.RIGHT));
west.add(new Label("RMI object: ", Label.RIGHT));
add("West", west);
Panel center = new Panel();
center.setLayout(new GridLayout(5, 1));
httpText = new TextField();
httpText.setEditable(false);
center.add(httpText);
httpObject = new TextField();
httpObject.setEditable(false);
center.add(httpObject);
socketText = new TextField();
socketText.setEditable(false);
center.add(socketText);
socketObject = new TextField();
socketObject.setEditable(false);
center.add(socketObject);
RMIObject = new TextField();
RMIObject.setEditable(false);
center.add(RMIObject);
add("Center", center);
Panel south = new Panel();
refresh = new Button("Refresh");
south.add(refresh);
add("South", south);
}
public void start() {
refresh();
}
private void refresh() {
httpText.setText(getDateUsingHttpText());
httpObject.setText(getDateUsingHttpObject());
socketText.setText(getDateUsingSocketText());
socketObject.setText(getDateUsingSocketObject());
RMIObject.setText(getDateUsingRMIObject());
}
private String getDateUsingHttpText () {
try {
URL url = new URL(getCodeBase(),
"servlet/DaytimeServlet");
HttpMessage msg = new HttpMessage(url);
InputStream in = msg.sendGetMessage();
DataInputStream result =
new DataInputStream(new BufferedInputStream(in));
String date = result.readLine();
in.close();
return date;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private String getDateUsingHttpObject () {
try {
URL url = new URL(getCodeBase(), "servlet/DaytimeServlet");
HttpMessage msg = new HttpMessage(url);
Properties props = new Properties();
props.put("format", "object");
InputStream in = msg.sendGetMessage(props);
ObjectInputStream result = new ObjectInputStream(in);
Object obj = result.readObject();
Date date = (Date)obj;
return date.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private String getDateUsingSocketText () {
return "unavailable (for now)";
}
private String getDateUsingSocketObject () {
return "unavailable (for now)";
}
private String getDateUsingRMIObject () {
return "unavailable (for now)";
}
public boolean handleEvent(Event event) {
// when the refresh button is pushed, refresh the display
// use jdk1.0 events for maximum portability
switch (event.id) {
case Event.ACTION_EVENT:
if (event.target == refresh) {
refresh();
return true;
}
}
return false;
}
}Socket connectivity.
Changes are significant as they are based on these additional classes:
import java.io.*;
import java.net.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class DaytimeServlet extends DaemonHttpServlet {
public Date getDate() {
return new Date();
}
public void init() throws ServletException {
DEFAULT_PORT = 36600;
}
public void doGet(HttpServletRequest req,
HttpServletResponse res) throws ServletException,
IOException
{
// if the client says "format=object" then
// return the Date as a serialized object
if ("object".equals(req.getParameter("format"))) {
ObjectOutputStream out =
new ObjectOutputStream(res.getOutputStream());
out.writeObject(getDate());
} else {
PrintWriter out = res.getWriter();
out.println(getDate().toString());
}
}
public void doPost(HttpServletRequest req,
HttpServletResponse res) throws ServletException,
IOException
{ doGet(req, res);
}
public void destroy() {
super.destroy();
}
public void handleClient(Socket client) {
new DaytimeConnection(this, client).start();
}
}
class DaytimeConnection extends Thread {
DaytimeServlet servlet;
Socket client;
DaytimeConnection(DaytimeServlet servlet, Socket client) {
this.servlet = servlet;
this.client = client;
setPriority(NORM_PRIORITY - 1);
}
public void run() {
try {
// read the first line sent by the client, as Latin-1 text
BufferedReader in =
new BufferedReader
(new InputStreamReader
(client.getInputStream(), "ISO-8859-1"));
String line = in.readLine();
// if it was "object" then return the Date as a serialized object
if ("object".equals(line)) {
ObjectOutputStream out =
new ObjectOutputStream
(client.getOutputStream());
out.writeObject(servlet.getDate());
out.close();
} else { // otherwise, send the Date as a normal string
// wrap a PrintStream around the Socket's OutputStream
PrintStream out = new PrintStream(client.getOutputStream());
out.println(servlet.getDate().toString());
out.close();
}
} catch (IOException e) {
servlet.log("IOException while handling client request", e);
} catch (Exception e) {
servlet.log("Exception while handling client request");
}
}
}
It's nice to be able to factor the changes this way. import java.io.*;
import java.net.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public abstract class DaemonHttpServlet extends HttpServlet {
protected int DEFAULT_PORT = 36600; // not static or final
private Thread daemonThread;
public void init(ServletConfig config) throws ServletException {
super.init(config);
// start a daemon thread
try {
daemonThread = new Daemon(this);
daemonThread.start();
} catch (Exception e) {
this.getServletContext().log
(e, "Problem starting socket server daemon thread");
}
}
// returns the socket port on which this servlet will listen
// a servlet can specify the port in three ways:
// 1. by using the socketPort init parameter,
// 2. by setting the DEFAULT_PORT variable before calling super.init(), or
// 3. by overriding this method's implementation
protected int getSocketPort() {
try {
return Integer.parseInt(getInitParameter("socketPort"));
} catch (NumberFormatException e) {
return DEFAULT_PORT;
}
}
abstract public void handleClient(Socket client);
public void destroy() {
// stop the daemon thread
try {
daemonThread.stop();
daemonThread = null;
} catch (Exception e) {
getServletContext().log
(e, "Problem stopping server socket daemon thread");
}
}
}
// this work is broken into a helper class so that subclasses of
// DaemonHttpServlet can define their own run() methods w/out problems...
class Daemon extends Thread {
private ServerSocket serverSocket;
private DaemonHttpServlet servlet;
public Daemon(DaemonHttpServlet servlet) {
this.servlet = servlet;
}
public void run() {
// create a server socket to accept connections
try {
serverSocket = new ServerSocket(servlet.getSocketPort());
} catch (Exception e) {
servlet.getServletContext().log
(e, "Problem establishing server socket");
return;
}
try {
while (true) {
// as each connection comes in, call the servlet's
// handleClient(). Note this method is blocking. It's
// the servlet responsibility to spawn a handler thread
// for long-running connections (as DaytimeServlet)
try {
servlet.handleClient(serverSocket.accept());
} catch(IOException ioe) {
servlet.getServletContext()
.log(ioe,
"Problem accepting client's socket connection");
}
}
} catch (ThreadDeath e) {
// when the thread is killed, close the server socket
try {
serverSocket.close();
} catch (IOException ioe) {
servlet.getServletContext()
.log(ioe,
"Problem closing server socket");
}
}
}
}
We also make a change in the HTML file (to match the servlet's port) and we are done.
import java.net.Socket;
import java.net.URL;
import java.applet.*;
import java.awt.*;
import java.io.*;
import java.util.*;
public class DaytimeApplet extends Applet {
static final int DEFAULT_PORT = 36600;
private int getSocketPort() {
try {
return Integer.parseInt(getParameter("socketPort"));
} catch (NumberFormatException e) {
return DEFAULT_PORT;
}
}
TextField httpText, httpObject, socketText, socketObject, RMIObject;
Button refresh;
public void init() {
setLayout(new BorderLayout());
Panel west = new Panel();
west.setLayout(new GridLayout(5, 1));
west.add(new Label("HTTP text: ", Label.RIGHT));
west.add(new Label("HTTP object: ", Label.RIGHT));
west.add(new Label("Socket text: ", Label.RIGHT));
west.add(new Label("Socket object: ", Label.RIGHT));
west.add(new Label("RMI object: ", Label.RIGHT));
add("West", west);
Panel center = new Panel();
center.setLayout(new GridLayout(5, 1));
httpText = new TextField();
httpText.setEditable(false);
center.add(httpText);
httpObject = new TextField();
httpObject.setEditable(false);
center.add(httpObject);
socketText = new TextField();
socketText.setEditable(false);
center.add(socketText);
socketObject = new TextField();
socketObject.setEditable(false);
center.add(socketObject);
RMIObject = new TextField();
RMIObject.setEditable(false);
center.add(RMIObject);
add("Center", center);
Panel south = new Panel();
refresh = new Button("Refresh");
south.add(refresh);
add("South", south);
}
public void start() {
refresh();
}
private void refresh() {
httpText.setText(getDateUsingHttpText());
httpObject.setText(getDateUsingHttpObject());
socketText.setText(getDateUsingSocketText());
socketObject.setText(getDateUsingSocketObject());
RMIObject.setText(getDateUsingRMIObject());
}
private String getDateUsingHttpText () {
try {
URL url = new URL(getCodeBase(),
"servlet/DaytimeServlet");
HttpMessage msg = new HttpMessage(url);
InputStream in = msg.sendGetMessage();
DataInputStream result =
new DataInputStream(new BufferedInputStream(in));
String date = result.readLine();
in.close();
return date;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private String getDateUsingHttpObject () {
try {
URL url = new URL(getCodeBase(), "servlet/DaytimeServlet");
HttpMessage msg = new HttpMessage(url);
Properties props = new Properties();
props.put("format", "object");
InputStream in = msg.sendGetMessage(props);
ObjectInputStream result = new ObjectInputStream(in);
Object obj = result.readObject();
Date date = (Date)obj;
return date.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private String getDateUsingSocketText () {
Socket socket = null;
try {
// establish a socket connection with the servlet
socket = new Socket("burrowww.cs.indiana.edu", getSocketPort());
// print an empty line, indicating we want the time as plain text
PrintStream out = new PrintStream(socket.getOutputStream());
out.print("\r\n"); // since println() behaviour varies by system
out.flush();
// read the first line of the response, it should contain the current time
InputStream in = socket.getInputStream();
DataInputStream result =
new DataInputStream(new BufferedInputStream(in));
String date = result.readLine();
// return the retrieved string
return date;
} catch (Exception e) {
// if there is a problem, print to System.out
// (typically the Java console) and return null
e.printStackTrace();
return null;
} finally {
// always close the connection (this code
// executes no matter how the try block completes)
if (socket != null) {
try {
socket.close();
} catch (IOException ignored) {
}
}
}
}
private String getDateUsingSocketObject () {
Socket socket = null;
try {
// establish a socket connection with the servlet
socket = new Socket(getCodeBase().getHost(), getSocketPort());
// print a line saying "object", indicating we want
// the time as a serialized Date object
PrintStream out = new PrintStream(socket.getOutputStream());
out.print("object\r\n");
out.flush();
// create an ObjectInputStream to read the response
InputStream in = socket.getInputStream();
ObjectInputStream result =
new ObjectInputStream(new BufferedInputStream(in));
// read an object, and cast it to be a date
Object obj = result.readObject();
Date date = (Date)obj;
// return a String representation of the retrieved Date
return date.toString();
} catch (Exception e) {
// if there is a problem, print to System.out
// (typically to Java console) and return null
e.printStackTrace();
return null;
} finally {
// always close the connection (this code
// executes no matter how the try block completes)
if (socket != null) {
try {
socket.close();
} catch (IOException ignored) {
}
}
}
}
private String getDateUsingRMIObject () {
return "unavailable (for now)";
}
public boolean handleEvent(Event event) {
// when the refresh button is pushed, refresh the display
// use jdk1.0 events for maximum portability
switch (event.id) {
case Event.ACTION_EVENT:
if (event.target == refresh) {
refresh();
return true;
}
}
return false;
}
}
Four out of the five fields are now reporting the date correctly. <html>
<head><title>Daytime Applet</title></head>
<body>
<center><h1>Daytime Applet</h1></center>
<center>
<applet code=DaytimeApplet
width=300
height=180>
<param name=socketPort value=36600>
</applet>
</center>
</body>
</html>Sockets, we try to avoid needing another one for RMI. DaytimeServer interface.
Then we need to add a few things to the servlet. import java.util.Date;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface DaytimeServer extends Remote {
public Date getDate() throws RemoteException;
}
The superclass has changed, so we provide it here. import java.io.*;
import java.net.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class DaytimeServlet extends RemoteDaemonHttpServlet
implements DaytimeServer
{
public Date getDate() {
return new Date();
}
public void init() throws ServletException {
DEFAULT_PORT = 36600;
}
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
public void doGet(HttpServletRequest req,
HttpServletResponse res) throws ServletException,
IOException
{
if ("object".equals(req.getParameter("format"))) {
ObjectOutputStream out =
new ObjectOutputStream(res.getOutputStream());
out.writeObject(getDate());
} else {
PrintWriter out = res.getWriter();
out.println(getDate().toString());
}
}
public void doPost(HttpServletRequest req,
HttpServletResponse res) throws ServletException,
IOException
{ doGet(req, res);
}
public void destroy() {
// if you override destroy() you have to call super.destroy()
super.destroy();
}
public void handleClient(Socket client) {
new DaytimeConnection(this, client).start();
}
}
class DaytimeConnection extends Thread {
DaytimeServlet servlet;
Socket client;
DaytimeConnection(DaytimeServlet servlet, Socket client) {
this.servlet = servlet;
this.client = client;
setPriority(NORM_PRIORITY - 1);
}
public void run() {
try {
// read the first line sent by the client, as Latin-1 text
BufferedReader in =
new BufferedReader
(new InputStreamReader
(client.getInputStream(), "ISO-8859-1"));
String line = in.readLine();
// if it was "object" then return the Date as a serialized object
if ("object".equals(line)) {
ObjectOutputStream out =
new ObjectOutputStream
(client.getOutputStream());
out.writeObject(servlet.getDate());
out.close();
} else { // otherwise, send the Date as a normal string
// wrap a PrintStream around the Socket's OutputStream
PrintStream out = new PrintStream(client.getOutputStream());
out.println(servlet.getDate().toString());
out.close();
}
} catch (IOException e) {
servlet.log("IOException while handling client request", e);
} catch (Exception e) {
servlet.log("Exception while handling client request");
}
}
}
Compile the servlet, then use import java.io.*;
import java.net.*;
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public abstract class RemoteDaemonHttpServlet extends DaemonHttpServlet
implements Remote
{
protected Registry registry;
public void init(ServletConfig config) throws ServletException {
super.init(config);
try {
// export ourself
UnicastRemoteObject.exportObject(this);
// register ourself
bind();
} catch(RemoteException e) {
getServletContext().log(e, "Problem binding to RMI registry.");
}
}
public void destroy() {
super.destroy();
// unregister yourself
unbind();
}
// returns the name under which we are to be registered
protected String getRegistryName() {
// first name choice is the "registryName" init parameter
String name = getInitParameter("registryName");
if (name != null) return name;
// fallback choice is the name of this class followed by your username
return this.getClass().getName() + "ByDGerman";
}
// returns the port on which the registry server
// is listening (or should be listening)
protected int getRegistryPort() {
// first port choice is the "registryPort" init parameter
String name = getInitParameter("registryName");
try {
return Integer.parseInt(getInitParameter("registryPort"));
} catch (NumberFormatException e) {
// fallback choice is the default registry port (1099)
return Registry.REGISTRY_PORT;
}
}
protected void bind() {
// try to find the appropriate registry already running
try {
registry = LocateRegistry.getRegistry(getRegistryPort());
registry.list(); // verify it's alive and well
} catch (Exception e) {
// couldn't get a valid registry
registry = null;
}
// if we couldn't find it, we need to create it
// (equivalent to running "rmiregistry")
if (registry == null) {
try {
registry = LocateRegistry.createRegistry(getRegistryPort());
} catch (Exception e) {
log("Could not get or create RMI registry on port " +
getRegistryPort() + ": " + e.getMessage());
return;
}
}
// if we get here, we must have a valid registry.
// now register this servlet instance with that registry.
// "rebind" to replace any other objects using our name
try {
registry.rebind(getRegistryName(), this);
} catch (Exception e) {
log("Could not bind to RMI registry: " + e.getMessage());
return;
}
}
protected void unbind() {
try {
if (registry != null) registry.unbind(getRegistryName());
} catch (Exception e) {
getServletContext().log(e, "Problem unbinding from RMI registry");
}
}
}rmic to create the stub and the skeleton files.
The applet changes a bit, as indicated below. burrowww.cs.indiana.edu% pwd
/nfs/paca/home/user1/dgerman/tomcat/jakarta-tomcat-4.0.3/webapps/one/WEB-INF/classes
burrowww.cs.indiana.edu% javac DaytimeServlet.java
burrowww.cs.indiana.edu% rmic DaytimeServlet
burrowww.cs.indiana.edu% ls -ld Daytime*.class
-rw-r--r-- 1 dgerman faculty 1668 Mar 28 15:15 DaytimeConnection.class
-rw-r--r-- 1 dgerman faculty 247 Mar 28 15:15 DaytimeServer.class
-rw-r--r-- 1 dgerman faculty 1796 Mar 28 15:15 DaytimeServlet.class
-rw-r--r-- 1 dgerman faculty 1422 Mar 28 15:16 DaytimeServlet_Skel.class
-rw-r--r-- 1 dgerman faculty 2887 Mar 28 15:16 DaytimeServlet_Stub.class
burrowww.cs.indiana.edu% cp DaytimeServer.class ../..
burrowww.cs.indiana.edu% cp DaytimeServlet_Stub.class ../..
burrowww.cs.indiana.edu% cd ../..
burrowww.cs.indiana.edu% pwd
/nfs/paca/home/user1/dgerman/tomcat/jakarta-tomcat-4.0.3/webapps/one
burrowww.cs.indiana.edu%
And now we are done. import java.rmi.*;
import java.rmi.registry.*;
import java.net.Socket;
import java.net.URL;
import java.applet.*;
import java.awt.*;
import java.io.*;
import java.util.*;
public class DaytimeApplet extends Applet {
private String getRegistryHost() {
return getCodeBase().getHost();
}
private int getRegistryPort() {
try {
return Integer.parseInt(getParameter("registryPort"));
} catch (NumberFormatException e) {
return Registry.REGISTRY_PORT;
}
}
private String getRegistryName() {
String name = getParameter("registryName");
if (name == null) {
name = "DaytimeServlet" // default
+ "ByDGerman"; // add your username
}
return name;
}
static final int DEFAULT_PORT = 36600;
private int getSocketPort() {
try {
return Integer.parseInt(getParameter("socketPort"));
} catch (NumberFormatException e) {
return DEFAULT_PORT;
}
}
TextField httpText, httpObject, socketText, socketObject, RMIObject;
Button refresh;
public void init() {
setLayout(new BorderLayout());
Panel west = new Panel();
west.setLayout(new GridLayout(5, 1));
west.add(new Label("HTTP text: ", Label.RIGHT));
west.add(new Label("HTTP object: ", Label.RIGHT));
west.add(new Label("Socket text: ", Label.RIGHT));
west.add(new Label("Socket object: ", Label.RIGHT));
west.add(new Label("RMI object: ", Label.RIGHT));
add("West", west);
Panel center = new Panel();
center.setLayout(new GridLayout(5, 1));
httpText = new TextField();
httpText.setEditable(false);
center.add(httpText);
httpObject = new TextField();
httpObject.setEditable(false);
center.add(httpObject);
socketText = new TextField();
socketText.setEditable(false);
center.add(socketText);
socketObject = new TextField();
socketObject.setEditable(false);
center.add(socketObject);
RMIObject = new TextField();
RMIObject.setEditable(false);
center.add(RMIObject);
add("Center", center);
Panel south = new Panel();
refresh = new Button("Refresh");
south.add(refresh);
add("South", south);
}
public void start() {
refresh();
}
private void refresh() {
httpText.setText(getDateUsingHttpText());
httpObject.setText(getDateUsingHttpObject());
socketText.setText(getDateUsingSocketText());
socketObject.setText(getDateUsingSocketObject());
RMIObject.setText(getDateUsingRMIObject());
}
private String getDateUsingHttpText () {
try {
URL url = new URL(getCodeBase(),
"servlet/DaytimeServlet");
HttpMessage msg = new HttpMessage(url);
InputStream in = msg.sendGetMessage();
DataInputStream result =
new DataInputStream(new BufferedInputStream(in));
String date = result.readLine();
in.close();
return date;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private String getDateUsingHttpObject () {
try {
URL url = new URL(getCodeBase(), "servlet/DaytimeServlet");
HttpMessage msg = new HttpMessage(url);
Properties props = new Properties();
props.put("format", "object");
InputStream in = msg.sendGetMessage(props);
ObjectInputStream result = new ObjectInputStream(in);
Object obj = result.readObject();
Date date = (Date)obj;
return date.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private String getDateUsingSocketText () {
Socket socket = null;
try {
// establish a socket connection with the servlet
socket = new Socket("burrowww.cs.indiana.edu", getSocketPort());
// print an empty line, indicating we want the time as plain text
PrintStream out = new PrintStream(socket.getOutputStream());
out.print("\r\n"); // since println() behaviour varies by system
out.flush();
// read the first line of the response, it should contain the current time
InputStream in = socket.getInputStream();
DataInputStream result =
new DataInputStream(new BufferedInputStream(in));
String date = result.readLine();
// return the retrieved string
return date;
} catch (Exception e) {
// if there is a problem, print to System.out
// (typically the Java console) and return null
e.printStackTrace();
return null;
} finally {
// always close the connection (this code
// executes no matter how the try block completes)
if (socket != null) {
try {
socket.close();
} catch (IOException ignored) {
}
}
}
}
private String getDateUsingSocketObject () {
Socket socket = null;
try {
// establish a socket connection with the servlet
socket = new Socket(getCodeBase().getHost(), getSocketPort());
// print a line saying "object", indicating we want
// the time as a serialized Date object
PrintStream out = new PrintStream(socket.getOutputStream());
out.print("object\r\n");
out.flush();
// create an ObjectInputStream to read the response
InputStream in = socket.getInputStream();
ObjectInputStream result =
new ObjectInputStream(new BufferedInputStream(in));
// read an object, and cast it to be a date
Object obj = result.readObject();
Date date = (Date)obj;
// return a String representation of the retrieved Date
return date.toString();
} catch (Exception e) {
// if there is a problem, print to System.out
// (typically to Java console) and return null
e.printStackTrace();
return null;
} finally {
// always close the connection (this code
// executes no matter how the try block completes)
if (socket != null) {
try {
socket.close();
} catch (IOException ignored) {
}
}
}
}
private String getDateUsingRMIObject () {
try {
Registry registry =
LocateRegistry.getRegistry(getRegistryHost(),
getRegistryPort());
DaytimeServer daytime =
(DaytimeServer)registry.lookup(getRegistryName());
return daytime.getDate().toString();
} catch (ClassCastException e) {
System.out.println("Retrieved object was not a DaytimeServer: " +
e.getMessage());
} catch (NotBoundException e) {
System.out.println(getRegistryName() + " not bound: " + e.getMessage());
} catch (RemoteException e) {
System.out.println("Hit remote exception: " + e.getMessage());
} catch (Exception e) {
System.out.println("Problem getting DaytimeServer reference: " +
e.getClass().getName() + ":" + e.getMessage());
}
return null;
}
public boolean handleEvent(Event event) {
// when the refresh button is pushed, refresh the display
// use jdk1.0 events for maximum portability
switch (event.id) {
case Event.ACTION_EVENT:
if (event.target == refresh) {
refresh();
return true;
}
}
return false;
}
}
The applet opens up five different connections to the servlet
and obtains information in five different ways (or formats). Our next goal, next week, is
to make sure that each one of these connections could be made bidirectional, so that
information can travel both ways
As a summary, here's what we worked on today:
You should be able to describe each one of these files and its contents. burrowww.cs.indiana.edu% pwd
/nfs/paca/home/user1/dgerman/tomcat/jakarta-tomcat-4.0.3/webapps/one
burrowww.cs.indiana.edu% du -a .
6 ./DaytimeApplet.class
1 ./WEB-INF/classes/HelloWorld.java
2 ./WEB-INF/classes/DaemonHttpServlet.class
2 ./WEB-INF/classes/Daemon.class
3 ./WEB-INF/classes/DaemonHttpServlet.java
3 ./WEB-INF/classes/DaytimeServlet.java
2 ./WEB-INF/classes/DaytimeServlet.class
2 ./WEB-INF/classes/DaytimeConnection.class
1 ./WEB-INF/classes/HelloWorld.class
1 ./WEB-INF/classes/DaytimeServer.java
1 ./WEB-INF/classes/DaytimeServer.class
3 ./WEB-INF/classes/DaytimeServlet.java~
3 ./WEB-INF/classes/RemoteDaemonHttpServlet.class
3 ./WEB-INF/classes/RemoteDaemonHttpServlet.java
3 ./WEB-INF/classes/RemoteDaemonHttpServlet.java~
3 ./WEB-INF/classes/DaytimeServlet_Stub.class
2 ./WEB-INF/classes/DaytimeServlet_Skel.class
36 ./WEB-INF/classes
1 ./WEB-INF/lib
1 ./WEB-INF/web.xml
39 ./WEB-INF
4 ./HttpMessage.class
7 ./DaytimeApplet.java
3 ./DaytimeServlet_Stub.class
6 ./DaytimeApplet.java~
1 ./daytime.html
3 ./HttpMessage.java
1 ./DaytimeServer.class
71 .
burrowww.cs.indiana.edu%
Last updated on Mar 28, 2002,
by Adrian German for A348/A548