Writing a web server.

i am trying to write a tiny web server, with a gui, and want the gui to be a able to stop and start the server, the server is in a separate class called web server, and i need some code to destroy the instance of the class. thx in advance.
[246 byte] By [dz0004455a] at [2007-11-27 9:58:20]
# 1
Better study about daemon threads.You might get some ideas andgo through codes where they are used by looking at google.
Adi1000a at 2007-7-13 0:29:00 > top of Java-index,Java Essentials,Java Programming...
# 2
What specific questions do you have?There is no code you can write in Java that will "destroy an instance." The GC takes care of that.
jverda at 2007-7-13 0:29:00 > top of Java-index,Java Essentials,Java Programming...
# 3
i have the web server class and i want to stop it, i'll look at daemon stuff thx, maybe that will work.
dz0004455a at 2007-7-13 0:29:00 > top of Java-index,Java Essentials,Java Programming...
# 4
Lets have a look at code you are using.Kindly send putting code tags.
Adi1000a at 2007-7-13 0:29:00 > top of Java-index,Java Essentials,Java Programming...
# 5

[nobr]web server code

package tinywebserver;

import java.io.*;

import java.net.*;

import java.util.*;

class WebServer implements HttpConstants {

/* static class data/methods */

/* print to stdout */

protected static void p(String s) {

GUI.main.append(s + "\n");

System.out.println(s);

}

/* our server's configuration information is stored

* in these properties

*/

protected static Properties props = new Properties();

/* Where worker threads stand idle */

static Vector threads = new Vector();

/* the web server's virtual root */

static File root;

/* timeout on client connections */

static int timeout = 0;

/* max # worker threads */

static int workers = 5;

//port to serve from

static int port = 8080;

/* load www-server.properties from java.home */

static void loadProps() throws IOException {

File f = new File("server.properties");

if (f.exists()) {

InputStream is =new BufferedInputStream(new

FileInputStream(f));

props.load(is);

is.close();

String r = props.getProperty("root");

if (r != null) {

root = new File(r);

if (!root.exists()) {

throw new Error(root + " doesn't exist as server root");

}

}

r = props.getProperty("timeout");

if (r != null) {

timeout = Integer.parseInt(r);

}

r = props.getProperty("workers");

if (r != null) {

workers = Integer.parseInt(r);

}

r = props.getProperty("serverPort");

if (r != null) {

port = Integer.parseInt(r);

}

}

/* if no properties were specified, choose defaults */

if (root == null) {

root = new File(System.getProperty("user.dir")+File.separator+"html");

}

if (timeout <= 1000) {

timeout = 5000;

}

if (workers < 25) {

workers = 5;

}

}

static void printProps() {

p("Tiny Web Server Starting on " + System.getProperty("os.name") +" "+System.getProperty("os.arch"));

p("root="+root);

p("timeout="+timeout);

p("workers="+workers);

p("port="+port);

}

public static void start() throws Exception{

loadProps();

printProps();

/* start worker threads */

for (int i = 0; i < workers; ++i) {

Worker w = new Worker();

(new Thread(w, "worker #"+i)).start();

threads.addElement(w);

}

ServerSocket ss = new ServerSocket(port);

while (true) {

Socket s = ss.accept();

Worker w = null;

synchronized (threads) {

if (threads.isEmpty()) {

Worker ws = new Worker();

ws.setSocket(s);

(new Thread(ws, "additional worker")).start();

}else {

w = (Worker) threads.elementAt(0);

threads.removeElementAt(0);

w.setSocket(s);

}

}

}

}

}

class Worker extends WebServer implements HttpConstants, Runnable {

final static int BUF_SIZE = 2048;

static final byte[] EOL = {(byte)'\r', (byte)'\n' };

/* buffer to use for requests */

byte[] buf;

/* Socket to client we're handling */

private Socket s;

Worker() {

buf = new byte[BUF_SIZE];

s = null;

}

synchronized void setSocket(Socket s) {

this.s = s;

notify();

}

public synchronized void run() {

while(true) {

if (s == null) {

/* nothing to do */

try {

wait();

} catch (InterruptedException e) {

/* should not happen */

continue;

}

}

try {

handleClient();

} catch (Exception e) {

e.printStackTrace();

}

/* go back in wait queue if there's fewer

* than numHandler connections.

*/

s = null;

Vector pool = WebServer.threads;

synchronized (pool) {

if (pool.size() >= WebServer.workers) {

/* too many threads, exit this one */

return;

} else {

pool.addElement(this);

}

}

}

}

void handleClient() throws IOException {

InputStream is = new BufferedInputStream(s.getInputStream());

PrintStream ps = new PrintStream(s.getOutputStream());

/* we will only block in read for this many milliseconds

* before we fail with java.io.InterruptedIOException,

* at which point we will abandon the connection.

*/

s.setSoTimeout(WebServer.timeout);

s.setTcpNoDelay(true);

/* zero out the buffer from last time */

for (int i = 0; i < BUF_SIZE; i++) {

buf[i] = 0;

}

try {

/* We only support HTTP GET/HEAD, and don't

* support any fancy HTTP options,

* so we're only interested really in

* the first line.

*/

int nread = 0, r = 0;

outerloop:

while (nread < BUF_SIZE) {

r = is.read(buf, nread, BUF_SIZE - nread);

if (r == -1) {

/* EOF */

return;

}

int i = nread;

nread += r;

for (; i < nread; i++) {

if (buf[i] == (byte)'\n' || buf[i] == (byte)'\r') {

/* read one line */

break outerloop;

}

}

}

/* are we doing a GET or just a HEAD */

boolean doingGet;

/* beginning of file name */

int index;

if (buf[0] == (byte)'G' &&

buf[1] == (byte)'E' &&

buf[2] == (byte)'T' &&

buf[3] == (byte)' ') {

doingGet = true;

index = 4;

} else if (buf[0] == (byte)'H' &&

buf[1] == (byte)'E' &&

buf[2] == (byte)'A' &&

buf[3] == (byte)'D' &&

buf[4] == (byte)' ') {

doingGet = false;

index = 5;

} else {

/* we don't support this method */

ps.print("HTTP/1.0 " + HTTP_BAD_METHOD +

" unsupported method type: ");

ps.write(buf, 0, 5);

ps.write(EOL);

ps.flush();

s.close();

return;

}

int i = 0;

/* find the file name, from:

* GET /foo/bar.html HTTP/1.0

* extract "/foo/bar.html"

*/

for (i = index; i < nread; i++) {

if (buf[i] == (byte)' ') {

break;

}

}

String fname = (new String(buf, 0, index,

i-index)).replace('/', File.separatorChar);

if (fname.startsWith(File.separator)) {

fname = fname.substring(1);

}

File targ = new File(WebServer.root, fname);

if (targ.isDirectory()) {

File ind = new File(targ, "index.html");

if (ind.exists()) {

targ = ind;

}

}

boolean OK = printHeaders(targ, ps);

if (doingGet) {

if (OK) {

sendFile(targ, ps);

} else {

send404(targ, ps);

}

}

} finally {

s.close();

}

}

boolean printHeaders(File targ, PrintStream ps) throws IOException {

boolean ret = false;

int rCode = 0;

if (!targ.exists()) {

rCode = HTTP_NOT_FOUND;

ps.print("HTTP/1.0 " + HTTP_NOT_FOUND + " not found");

ps.write(EOL);

ret = false;

} else {

rCode = HTTP_OK;

ps.print("HTTP/1.0 " + HTTP_OK+" OK");

ps.write(EOL);

ret = true;

}

p("\nRequest from " +s.getInetAddress().getHostAddress()+": GET " + targ.getAbsolutePath()+"-->"+rCode);

ps.print("Server: Simple java, Tiny Web Server");

ps.write(EOL);

ps.print("Date: " + (new Date()));

ps.write(EOL);

if (ret) {

if (!targ.isDirectory()) {

ps.print("Content-length: "+targ.length());

ps.write(EOL);

ps.print("Last Modified: " + (new

Date(targ.lastModified())));

ps.write(EOL);

String name = targ.getName();

int ind = name.lastIndexOf('.');

String ct = null;

if (ind > 0) {

ct = (String) map.get(name.substring(ind));

}

if (ct == null) {

ct = "unknown/unknown";

}

ps.print("Content-type: " + ct);

ps.write(EOL);

} else {

ps.print("Content-type: text/html");

ps.write(EOL);

}

}

return ret;

}

void send404(File targ, PrintStream ps) throws IOException {

ps.write(EOL);

ps.write(EOL);

ps.println("404 error, the requested object was not found\n\n"+

"The requested resource was not found.\n\n\nTiny Web Server has encountered an error.");

}

void sendFile(File targ, PrintStream ps) throws IOException {

InputStream is = null;

ps.write(EOL);

if (targ.isDirectory()) {

listDirectory(targ, ps);

return;

} else {

is = new FileInputStream(targ.getAbsolutePath());

}

try {

int n;

while ((n = is.read(buf)) > 0) {

ps.write(buf, 0, n);

}

} finally {

is.close();

}

}

/* mapping of file extensions to content-types */

static java.util.Hashtable map = new java.util.Hashtable();

static {

fillMap();

}

static void setSuffix(String k, String v) {

map.put(k, v);

}

static void fillMap() {

setSuffix("", "content/unknown");

setSuffix(".uu", "application/octet-stream");

setSuffix(".exe", "application/octet-stream");

setSuffix(".ps", "application/postscript");

setSuffix(".zip", "application/zip");

setSuffix(".sh", "application/x-shar");

setSuffix(".tar", "application/x-tar");

setSuffix(".snd", "audio/basic");

setSuffix(".au", "audio/basic");

setSuffix(".wav", "audio/x-wav");

setSuffix(".gif", "image/gif");

setSuffix(".jpg", "image/jpeg");

setSuffix(".jpeg", "image/jpeg");

setSuffix(".htm", "text/html");

setSuffix(".html", "text/html");

setSuffix(".text", "text/plain");

setSuffix(".c", "text/plain");

setSuffix(".cc", "text/plain");

setSuffix(".c++", "text/plain");

setSuffix(".h", "text/plain");

setSuffix(".pl", "text/plain");

setSuffix(".txt", "text/plain");

setSuffix(".java", "text/plain");

}

void listDirectory(File dir, PrintStream ps) throws IOException {

ps.println("<TITLE>Directory listing</TITLE><P>\n");

ps.println("<A HREF=\"..\">Parent Directory</A><BR>\n");

String[] list = dir.list();

for (int i = 0; list != null && i < list.length; i++) {

File f = new File(dir, list[i]);

if (f.isDirectory()) {

ps.println("<A HREF=\""+list[i]+"/\">"+list[i]+"/</A><BR>");

} else {

ps.println("<A HREF=\""+list[i]+"\">"+list[i]+"</A><BR");

}

}

ps.println("><P><HR><BR><I>Tiny Web Server on "+ port + " at " + (new Date()) + "</I>");

}

}

interface HttpConstants {

/** 2XX: generally "OK" */

public static final int HTTP_OK = 200;

public static final int HTTP_CREATED = 201;

public static final int HTTP_ACCEPTED = 202;

public static final int HTTP_NOT_AUTHORITATIVE = 203;

public static final int HTTP_NO_CONTENT = 204;

public static final int HTTP_RESET = 205;

public static final int HTTP_PARTIAL = 206;

/** 3XX: relocation/redirect */

public static final int HTTP_MULT_CHOICE = 300;

public static final int HTTP_MOVED_PERM = 301;

public static final int HTTP_MOVED_TEMP = 302;

public static final int HTTP_SEE_OTHER = 303;

public static final int HTTP_NOT_MODIFIED = 304;

public static final int HTTP_USE_PROXY = 305;

/** 4XX: client error */

public static final int HTTP_BAD_REQUEST = 400;

public static final int HTTP_UNAUTHORIZED = 401;

public static final int HTTP_PAYMENT_REQUIRED = 402;

public static final int HTTP_FORBIDDEN = 403;

public static final int HTTP_NOT_FOUND = 404;

public static final int HTTP_BAD_METHOD = 405;

public static final int HTTP_NOT_ACCEPTABLE = 406;

public static final int HTTP_PROXY_AUTH = 407;

public static final int HTTP_CLIENT_TIMEOUT = 408;

public static final int HTTP_CONFLICT = 409;

public static final int HTTP_GONE = 410;

public static final int HTTP_LENGTH_REQUIRED = 411;

public static final int HTTP_PRECON_FAILED = 412;

public static final int HTTP_ENTITY_TOO_LARGE = 413;

public static final int HTTP_REQ_TOO_LONG = 414;

public static final int HTTP_UNSUPPORTED_TYPE = 415;

/** 5XX: server error */

public static final int HTTP_SERVER_ERROR = 500;

public static final int HTTP_INTERNAL_ERROR = 501;

public static final int HTTP_BAD_GATEWAY = 502;

public static final int HTTP_UNAVAILABLE = 503;

public static final int HTTP_GATEWAY_TIMEOUT = 504;

public static final int HTTP_VERSION = 505;

}

the gui is just normal gui stuff, it contains the main method[/nobr]

dz0004455a at 2007-7-13 0:29:00 > top of Java-index,Java Essentials,Java Programming...
# 6
try using getThreadGroup() methodThread parent = currentThread();ob=parent.getThreadGroup();ob.stop();
Adi1000a at 2007-7-13 0:29:00 > top of Java-index,Java Essentials,Java Programming...
# 7
> ob.stop();ICKY BAD!Deprecated. This method is inherently unsafe. See Thread.stop() for details.
jverda at 2007-7-13 0:29:00 > top of Java-index,Java Essentials,Java Programming...
# 8
Usually the way you stop a thread is by interrupt()ing it.
jverda at 2007-7-13 0:29:00 > top of Java-index,Java Essentials,Java Programming...
# 9

> i have the web server class and i want to stop it,

> i'll look at daemon stuff thx, maybe that will work.

There's your first mistake: implementing an entire web server in a single class isn't a good idea. Implementing anything other than seriously trivial programs in a single class isn't a good idea. Forget that it's a poor way to model a system, forget that it doesn't follow any good OO principles, it forces you to think about the entire thing in one lump. Break it down into smaller, manageable chunks of functionality, each class should do exactly one thing, and no, "be a web server" isn't "one" thing

georgemca at 2007-7-13 0:29:00 > top of Java-index,Java Essentials,Java Programming...
# 10

And this doesn't bode well:

else if (buf[0] == (byte)'H' &&

buf[1] == (byte)'E' &&

buf[2] == (byte)'A' &&

buf[3] == (byte)'D' &&

buf[4] == (byte)' ') {

jverda at 2007-7-13 0:29:00 > top of Java-index,Java Essentials,Java Programming...
# 11
thanks again guys, let me try this out.
dz0004455a at 2007-7-13 0:29:00 > top of Java-index,Java Essentials,Java Programming...
# 12

Other bit of random advice:

* implements HttpConstants is evil. Don't use interfaces to save typing for constants. If you really hate to type out the class name where the constants are defined, use static imports (though personally I'm not fond of them in genral).

* You don't need so many comments. Variable names and code should be for the most part self-explanatory. If you have to comment inline, it should be to explain *why* you're doing something, not *what* you're doing.

* For one-line comments, use // rather than /* */

* Once you follow the earlier advice to break this down into smaller classes and methods, and once you learn a little about OO, you'll almost certainly want to not make everything static.

* You don't need to go through all those machinations to get default values. The Properties class already has a facility to do that. Read up on it.

* p is a horrible method name.

* You're use of bytes and byte arrays is bad. There do exist tools for going back and forth betwen String and char[] and String and byte[].

* It's good that you're closing streams in finally blocks, but I think close can throw a checked exception. You don't want finally to change how your try statement completes, so the close inside the finally should be wrapped in its own try/catch that either smothers the exception or logs it but moves on and completes normally.

jverda at 2007-7-13 0:29:00 > top of Java-index,Java Essentials,Java Programming...