<font face='±¼¸²'>¡Ø Web Server ¸¸µé±â
Networking, Multi-thread programmingÀ» ÀÌÇØÇϱâ À§ÇØ Java·Î WebServer¸¦ ±¸ÇöÇÑ
programÀ» ¼Ò°³ÇÏ°íÀÚ ÇÕ´Ï´Ù.
Server applicationÀ» ±¸ÇöÇϱâ À§ÇØ Network, Stream I/O, Thread¾Ë°í ÀÖ¾î¾ßÇÏ°í,
±×¸®°í, ServerÀÇ µ¿ÀÛ ±¸Á¶¿¡ ´ëÇØ ÀÌÇظ¦ ÇÏ°í ÀÖ¾î¾ß ÇÕ´Ï´Ù. ¿©±â¼ ¼Ò°³ÇÏ°íÀÚ
ÇÏ´Â WebServer¿¡¼´Â Dynamic configuration±â´É, Logging, Thread PoolingÀÇ ±â´ÉÀ»
±¸ÇöÇØ ³õ¾Ò°í, Server programming¿¡ ´ëÇÑ ÀÌÇØ¿Í ÇÔ²² ÀÌ·± ±â´ÉÀ» ÀÀ¿ëÇÏ´Â
¹æ¹ýÀ» ÀÌÇØÇÏ¸é µÉ°Í °°½À´Ï´Ù.
1. Dynamic Configuration
Dynamic configurationÀ̶ó´Â Àǹ̴ configurationÀÇ °ªµéÀÇ hard codingÀ» ÇÇÇؼ
runtime¿¡ °áÁ¤ÇÏÀÚ´Â ¶æÀÔ´Ï´Ù. ÀÌ·± ±â´ÉÀÇ ¿¹·Î´Â AppletÀÇ param tag, ServletÀÇ
InitParameter, EJBÀÇ Environment EntryµîÀÌ ÀÖ½À´Ï´Ù.
Áï º¯°æµÉ °¡´É¼ºÀÌ ÀÖ´Â °ªµéÀ» hard codingÇÏ°Ô µÇ¸é, °ªÀÌ º¯°æµÉ¶§ ¸¶´Ù
Àç compileÇØ¾ß ÇÑ´Ù´Â ¹ø°Å·¯¿òÀÌ ÀÖÁÒ. ±×·¡¼, configuration file¿¡ name/value°ªµéÀ»
¼³Á¤ÇÏ°í, programmingÇÒ¶§ nameÀÇ °ª¿¡ ÇØ´çÇÏ´Â value°ªÀ» ÀÐ¾î º¯¼ö¿¡ ÀúÀåÇØ
»ç¿ëÇÏ°Ô µÇ¸é, °ªÀÌ º¯°æµÉ¶§ ¸¸´Ù Àç compileÇÏ´Â ¹ø°Å·¯¿òÀº ¾ø¾îÁö´Â °ÍÀÌÁÒ.
±×¸®°í, runtime¿¡ °ªÀÇ º¯°æÀ» Áö±Ý ½ÇÇà ÁßÀÎ ÇÁ·Î¼¼½º¿¡ ¹Ý¿µÇÒ¼öµµ ÀÖ°ÚÁÒ.
web server¿¡¼´Â httpd.conf file¿¡ web serverÀÇ configurationÀ» ´ÙÀ½°ú °°ÀÌ
¼³Á¤ÇØ ³õ¾Ò½À´Ï´Ù.
## HttpWebServer Configuration file : httpd.conf
DocumentRoot=d:
handler=5
timeout=10000
port=8080
verbose=true
buffer.size=2048
mime.file=mime.txt
¢º httpd.conf
httpd.conf fileÀÇ ³»¿ëÀ» Àоî program¿¡¼ ÀÌ °ªµéÀ» accessÇϱâ À§ÇÑ °´Ã¼¸¦
Á¤ÀÇ ÇØ¾ß Çϴµ¥, ÀÌ°ÍÀ» Á¤ÀÇÇÒ¶§ java.util.Properties °´Ã¼¸¦ ÀÌ¿ëÇÏ¸é µÇ°ÚÁÒ.
Properties°´Ã¼ÀÇ ÀÌ¿ëÀº article "Properties class and properties file Example"À» Âü°íÇϼ¼¿ä.
±×¸®°í, ¾Æ·¡¿¡ PropManager´Â httpd.confÀÇ configurationÀ» Àоî Properties°´Ã¼¿¡
ÀúÀåÇÏ´Â °Í°ú runtime¿¡ configuration¿¡ ´ëÇÑ service¸¦ ÇØ ÁÖ´Â °´Ã¼ÀÔ´Ï´Ù.
load() method¿¡¼ httpd.conf fileÀÇ ³»¿ëÀ» Àоî Properties°´Ã¼¿¡ ÀúÀåÀ» Çϴµ¥,
PROPERTIES_FILEÀÇ httpd.conf fileÀº CLASSPATH°æ·Î À§Ä¡¿¡¼ ã°Ô µË´Ï´Ù.
package com.specular.util;
import java.util.*;
import java.io.*;
/*
* PropManager.java : Configuration Properties management.
* 2001.05.15
* written by Jeon HongSeong
*/
public class PropManager {
//Singleton
private static PropManager instance;
private Properties prop;
private static String PROPERTIES_FILE="httpd.conf";
static
{
instance=new PropManager();
}
private PropManager()
{
prop = new Properties();
try {
load();
} catch(IOException e) {
e.printStackTrace();
}
}
public static PropManager getInstance()
{
if(instance==null) {
instance=new PropManager();
}
return instance;
}
public synchronized void load()
throws IOException
{
InputStreamReader isr=null;
BufferedReader br=null;
ClassLoader cl = getClass().getClassLoader();
InputStream in= cl.getResourceAsStream(PROPERTIES_FILE);
if(in==null) {
throw new FileNotFoundException("The configuration file is not found.");
}
try {
isr = new InputStreamReader(in);
br = new BufferedReader(isr);
String line=null;
while(true) {
line=br.readLine();
if(line==null) break;
if(line.startsWith("#")) continue;
parseLine(line);
}
} catch(IOException e) {
throw e;
} finally {
try {
if(br!=null) br.close();
if(isr!=null) isr.close();
if(in!=null) in.close();
} catch(IOException e) { e.printStackTrace(); }
}
}
public synchronized void store(String header)
throws IOException
{
FileOutputStream fo = null;
OutputStreamWriter osw = null;
BufferedWriter awriter = null;
try {
fo = new FileOutputStream(PROPERTIES_FILE);
osw = new OutputStreamWriter(fo);
awriter = new BufferedWriter(osw);
if (header != null)
writeln(awriter, "# " + header);
writeln(awriter, "# " + new Date().toString());
Enumeration e = prop.keys();
while(e.hasMoreElements()) {
String key = (String)e.nextElement();
String val = (String)prop.get(key);
writeln(awriter, key + "=" + val);
}
awriter.flush();
} catch(IOException e) {
throw e;
} finally {
try {
if(awriter!=null) awriter.close();
if(osw!=null) osw.close();
if(fo!=null) fo.close();
} catch(IOException e) { e.printStackTrace(); }
}
}
public String getProperty(String name)
{
return prop.getProperty(name);
}
public String getProperty(String name,String defaultValue)
{
return prop.getProperty(name,defaultValue);
}
public void setProperty(String name,String value)
{
prop.setProperty(name,value);
}
public Enumeration propertyNames()
{
return prop.propertyNames();
}
public void list() {
System.out.println("--"+PROPERTIES_FILE+" configuration --");
prop.list(System.out);
System.out.println("------------------------");
}
private void parseLine(String line)
{
if(line.indexOf("=") != -1 ) {
int idx=line.indexOf("=");
prop.put(line.substring(0,idx),line.substring(idx+1));
}
}
private void writeln(BufferedWriter bw, String s)
throws IOException
{
bw.write(s);
bw.newLine();
}
}
¢º PropManager.java
//PropManager Test Application
import com.specular.util.*;
import java.io.*;
public class PropMgrEx {
public static void main(String args[])
throws IOException
{
PropManager pMgr = PropManager.getInstance("httpd.conf");
pMgr.list();
System.out.println(pMgr.getProperty("DocumentRoot"));
}
}
¢º PropMgrEx.java
´ÙÀ½Àº web server¿¡¼ ÀÌ¿ëÇÏ°Ô µÉ MIME Type¿¡ ´ëÇÑ data¸¦ ÀÌ¿ëÇϱâ À§ÇØ
±¸ÇöÇÑ Äڵ带 º¸°Ú½À´Ï´Ù. MIME Typeµµ configuration°ú À¯»çÇÏ°Ô ÀÌ¿ëµÉ¼ö ÀÖÁö¸¸,
µÇ°Ô read onlyÀÇ ¼º°ÝÀÇ data·Î º¼¼ö°¡ ÀÖ½À´Ï´Ù. ±×·¡¼ PropManager¸¦ ÀÌ¿ëÇϱ⠺¸´Ù´Â
read onlyÀÇ ¼º°ÝÀ» °®°íÀÖ´Â class¸¦ µû·Î Á¤ÀÇ ÇßÁÒ.
¸ÕÀú mime.txt fileÀÇ ³»¿ëÀÔ´Ï´Ù.
# MIME TYPE : mime.txt file
.uu=application/octet-stream
.exe=application/octet-stream
.ps=application/postscript
.zip=application/zip
.sh=application/x-shar
.tar=application/x-tar
.snd=audio/basic
.au=audio/basic
.wav=audio/x-wav
.gif=image/gif
.jpg=image/jpeg
.jpeg=image/jpeg
.htm=text/html
.html=text/html
.text=text/plain
.c=text/plain
.cc=text/plain
.c++=text/plain
.h=text/plain
.pl=text/plain
.txt=text/plain
.java=text/plain
¢º mime.txt
mime.txt fileÀÇ ³»¿ëÀ» loadingÇؼ runtime¿¡ MIME TYPE¿¡ ´ëÇØ serviceÇØ ÁÖ´Â classÀÔ´Ï´Ù.
package com.specular.http;
import java.io.*;
import java.util.*;
import com.specular.util.*;
/*
* MimeDB.java : MIME TYPE data loading,service
* 2001.05.15
* written by Jeon HongSeong
*/
public class MimeDB implements Serializable {
private static Properties db;
static
{
db = new Properties();
String mimeFile=PropManager.getInstance().getProperty("mime.file","mime.txt");
ClassLoader cl = MimeDB.class.getClassLoader();
InputStream is= cl.getResourceAsStream(mimeFile);
try {
if(is==null)
throw new FileNotFoundException("The configuration file is not found.");
db.load(is);
} catch(IOException e) {
LogManager.log(e,"MIME Configuration file is not loaded.");
} finally {
try {
if(is!=null) is.close();
} catch(IOException e) { e.printStackTrace(); }
}
}
private MimeDB() {}
public static String get(String name)
{
return db.getProperty(name,"unknown/unknown");
}
private static void set(String name,String value)
{
if(db!=null) db.setProperty(name,value);
}
public static void list() {
System.out.println("-- mime.txt configuration --");
db.list(System.out);
System.out.println("-------------------------");
}
}
¢º MimeDB.java
À§ÀÇ PropManager´Â configuration peroperties¸¦ dynamicÇÏ°Ô ¹Ý¿µÇÏ´Â °ÍÀº ±¸ÇöµÇ¾î
ÀÖÁö ¾ÊÀºµ¥, ÀÌ°ÍÀº Thread¸¦ ÀÌ¿ëÇØ configuration fileÀÇ modified timeÀ» ÁÖ±âÀûÀ¸·Î
checkÇؼ loadingÇÏ°Ô²û ±¸ÇöÇϸé, µÇ°ÚÁÒ.
2001.05.17 written by Jeon HongSeong |