📄 basetunnelservlet.java
字号:
/*
* @(#)BaseTunnelServlet
*
* Copyright (c) 1998 Karl Moss. All Rights Reserved.
*
* You may study, use, modify, and distribute this software for any
* purpose provided that this copyright notice appears in all copies.
*
* This software is provided WITHOUT WARRANTY either expressed or
* implied.
*
* @author Karl Moss
* @version 1.0
* @date 17Apr98
*
*/
package javaservlets.tunnel.server;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
/**
* <p>This is the base server object used for HTTP tunneling.
*/
public abstract class BaseTunnelServlet extends HttpServlet
{
// Constant key value for getting/setting the server object
// table into the session object
static final String OBJECT_TABLE = "ObjectTable";
/**
* <p>Services the HTTP request
*
* @param req The request from the client
* @param resp The response from the servlet
*/
public void service(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, java.io.IOException
{
// Get the input stream for reading data from the client
DataInput in = _getInputStream(req.getInputStream());
// Get the session object or create one if it does not
// exist. A session will persist as long as the client
// browser maintains a connection to the server.
HttpSession session = req.getSession(true);
// Get the server object table bound to the session. This may
// be null if this is the first request. If so create a
// new object table for the session
java.util.Hashtable objectTable =
(java.util.Hashtable) session.getAttribute(OBJECT_TABLE);
// java.util.Hashtable objectTable =
// (java.util.Hashtable) session.getValue(OBJECT_TABLE);
if (objectTable == null) {
objectTable = new java.util.Hashtable();
// Add the server object to the HTTP session
session.setAttribute(OBJECT_TABLE, objectTable);
// session.putValue(OBJECT_TABLE, objectTable);
}
// We'll be sending binary data back to the client so
// set the content type appropriately
resp.setContentType("application/octet-stream");
// Data will always be written to a byte array buffer so
// that we can tell the client the length of the data
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
// Create the output stream to be used to write the
// data to our buffer
DataOutput out = _getOutputStream(byteOut);
// Read the method ordinal from the input stream. All
// request headers contain a method ordinal
int ordinal = in.readInt();
// The server object
Object serverObject;
// The object handle
int objectHandle;
// Evaluate the ordinal. -1 is reserved for initializing
// the server
switch (ordinal) {
case -1:
// Create a new instance of the server object
serverObject = _getNewInstance();
// Send the response back to the client indicating
// that the server object is ready for method
// calls.
out.writeInt(ordinal);
// Get the object handle
objectHandle = serverObject.hashCode();
// Put the object in the object table for the session
objectTable.put(new Integer(objectHandle), serverObject);
// Part of the initial object response is the object
// handle
out.writeInt(objectHandle);
break;
default:
// Read the object handle from the request header
objectHandle = in.readInt();
// Attempt to find the object in the object table for
// the session
serverObject = objectTable.get(new Integer(objectHandle));
// We have to have a server object in order to invoke
if (serverObject == null) {
throwException(out, "Invalid server object");
}
else {
try {
// The response needs to always include the ordinal
// that was invoked.
out.writeInt(ordinal);
_flush(out);
// Invoke the method for the given ordinal
_invokeMethod(serverObject, ordinal, in, out);
}
catch (Exception ex) {
// Any exceptions thrown by invoking the server
// method should be sent back to the client. Make
// sure we are working with a 'pure' output stream
// that does not contain any other data
byteOut = new ByteArrayOutputStream();
out = _getOutputStream(byteOut);
throwException(out, ex.getMessage());
}
}
}
// Flush the contents of the output stream to the
// byte array
_flush(out);
// Get the buffer that is holding our response
byte[] buf = byteOut.toByteArray();
// Notify the client how much data is being sent
resp.setContentLength(buf.length);
// Send the buffer to the client
ServletOutputStream servletOut = resp.getOutputStream();
// Wrap up
servletOut.write(buf);
servletOut.close();
}
/**
* <p>Initialize the servlet. This is called once when the
* servlet is loaded. It is guaranteed to complete before any
* requests are made to the servlet
*
* @param cfg Servlet configuration information
*/
public void init(ServletConfig cfg)
throws ServletException
{
super.init(cfg);
}
/**
* <p>Destroy the servlet. This is called once when the servlet
* is unloaded.
*/
public void destroy()
{
super.destroy();
}
/**
* <p>Sends a packet to the client that will cause
* an exception to be thrown
*
* @param out Output stream
* @param message Exception message
*/
public void throwException(DataOutput out, String message)
throws IOException
{
// -2 is reserved for exceptions
out.writeInt(-2);
out.writeUTF(message);
}
/**
* <p>Creates a new instance of the server object. This
* method must be implemented by the server.
*
* @return Instance of the server object
*/
public abstract Object _getNewInstance()
throws ServletException;
/**
* <p>Invokes the method for the ordinal given. If the method
* throws an exception it will be sent to the client. This
* method must be implemented by the server.
*
* @param Object Server object
* @param ordinal Method ordinal
* @param in Input stream to read additional parameters
* @param out Output stream to write return values
*/
public abstract void _invokeMethod(Object serverObject, int ordinal,
DataInput in, DataOutput out)
throws Exception;
/**
* <p>Creates an input stream to be used to read data
* sent from the client. This method must be implemented
* by the server
*
* @param servletInput Servlet input stream from the servlet
* request header
* @return Input stream to read data from the client
*/
public abstract DataInput _getInputStream(
ServletInputStream servletInput)
throws IOException;
/**
* <p>Closes the input stream. The default implementation does
* nothing.
*
* @param in Input stream to close
*/
public void _close(DataInput in) throws IOException
{
}
/**
* <p>Gets an output stream to be used for writing data to
* an internal buffer. The buffer will be written to the
* client. This method must be implemented by the server.
*
* @param buffer Buffer to hold the output data
* @return Output stream to write data to the buffer
*/
public abstract DataOutput _getOutputStream(
ByteArrayOutputStream buffer)
throws IOException;
/**
* <p>Flushes the any buffered data to the output stream. The
* default implementation does nothing.
*
* @param out Output stream to flush
*/
public void _flush(DataOutput out) throws IOException
{
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -