// Copyright 2004-2014 Jim Voris
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package com.qumasoft.webserver;
import com.qumasoft.qvcslib.QVCSConstants;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* An example of a very simple, multi-threaded HTTP server.
* Implementation notes are in WebServer.html, and also
* as comments in the source code.
*/
public final class WebServer implements HttpConstants {
/** Hide this. */
private WebServer() {
}
// Create our logger object
private static final Logger LOGGER = Logger.getLogger("com.qumasoft.webserver");
private static final int DEFAULT_WEB_SERVER_PORT = 9080;
private static final int INITIAL_MAX_WORKER_THREAD_COUNT = 5;
private static final int ONE_SECOND_IN_MILLISECONDS = 1000;
private static final int DEFAULT_TIMEOUT_IN_MILLISECONDS = 5000;
private static final int MAXIMUM_NUMBER_OF_WORKER_THREADS = 25;
private static PrintStream webServerLog = null;
/**
* Where worker workerThreads stand idle
*/
private static Vector<Worker> workerThreads = new Vector<>();
/**
* the web server's virtual webServerRootDirectory
*/
private static File webServerRootDirectory;
/**
* clientTimeout on client connections
*/
private static int clientTimeout = 0;
/**
* max # worker workerThreads
*/
private static int maxWorkerThreadCount = INITIAL_MAX_WORKER_THREAD_COUNT;
/*
* print to stdout
*/
protected static void printLogMessage(String s) {
LOGGER.log(Level.INFO, s);
}
protected static int getClientTimeout() {
return clientTimeout;
}
protected static Vector<Worker> getWorkerThreads() {
return workerThreads;
}
protected static int getMaxWorkerThreadCount() {
return maxWorkerThreadCount;
}
/*
* print to the webServerLog file
*/
static void log(String s) {
synchronized (webServerLog) {
webServerLog.println(s);
webServerLog.flush();
}
}
/*
* load www-server.properties
*/
static void loadProperties() throws IOException {
String rootDirectoryName = System.getProperty("user.dir")
+ File.separator
+ QVCSConstants.QVCS_WEB_SERVER_ROOT_DIRECTORY;
String webServerLogfileName = System.getProperty("user.dir")
+ File.separator
+ QVCSConstants.QVCS_WEB_SERVER_LOGFILE;
/*
* Use these hard coded defaults
*/
webServerRootDirectory = new File(rootDirectoryName);
if (clientTimeout <= ONE_SECOND_IN_MILLISECONDS) {
clientTimeout = DEFAULT_TIMEOUT_IN_MILLISECONDS;
}
if (maxWorkerThreadCount < MAXIMUM_NUMBER_OF_WORKER_THREADS) {
maxWorkerThreadCount = INITIAL_MAX_WORKER_THREAD_COUNT;
}
// Open the file we'll webServerLog to...
printLogMessage("opening log file: " + webServerLogfileName);
webServerLog = new PrintStream(new BufferedOutputStream(new FileOutputStream(webServerLogfileName)));
}
static void printProperties() {
printLogMessage("root=" + webServerRootDirectory);
printLogMessage("timeout=" + clientTimeout);
printLogMessage("workers=" + maxWorkerThreadCount);
}
/**
* Start the very simple web server.
* @param args user directory, and port
* @throws IOException if we can't load properties.
*/
public static void start(String[] args) throws IOException {
int port = DEFAULT_WEB_SERVER_PORT;
if (args.length > 0) {
System.setProperty("user.dir", args[0]);
}
if (args.length > 1) {
try {
port = Integer.parseInt(args[1]);
} catch (NumberFormatException e) {
port = DEFAULT_WEB_SERVER_PORT;
}
}
loadProperties();
printProperties();
/*
* start worker workerThreads
*/
for (int i = 0; i < maxWorkerThreadCount; ++i) {
Worker w = new Worker();
Thread workerThread = new Thread(w, "worker #" + i);
workerThread.setDaemon(true);
workerThread.start();
workerThreads.addElement(w);
}
ServerSocket ss = new ServerSocket(port);
while (true) {
Socket s = ss.accept();
Worker worker;
synchronized (workerThreads) {
if (workerThreads.isEmpty()) {
Worker ws = new Worker();
ws.setSocket(s);
Thread workerThread = new Thread(ws, "additional worker");
workerThread.setDaemon(true);
workerThread.start();
} else {
worker = workerThreads.elementAt(0);
workerThreads.removeElementAt(0);
worker.setSocket(s);
}
}
}
}
}