Jeeve Management and Servlet ProgrammingJeeve는 Internet Information Server로써 웹서버와같은 기능을 수행하는 서버이다. 다음의 사이트에서 Jeeve를 다운 로드 받을 수 있다. 사용환경은 Windows95/NT, Solaris이며, 두 OS에 구분없이 실행할 수 있도록 되어있다.
압축파일을 풀어주는 것만으로 설치가 끝난다.
최근에 등장하는 상용 웹서버는 환경 설정에 필요한 CGI 프로그램과
문서를 제공한다. Jeeve도 마찬가지로 환경설정에 필요한 애플릿과
문서들을 제공하는데, 이런 애플릿이 포함된 문서는, 서버를 실행 했을때
실행되는 기본 홈페이지에 있다.[그림 1]
![[그림 2] Login to Administration](login.jpg)
[그림 2] Login to Administration
Alias기능은 local 디스크에 있는 파일이나 서브릿을 외부에서 URL로 찾아갈 수 있도록한다. 다음은 File Aliasing을 등록하는 aliases.properties파일과
aliases.properties
......
/=public_html
/cgi-bin=cgi-bin
/admin=admin/html
/doc=doc
/applet=servlets
/icons=icons
/~=public_html/usr
......
서브릿은 관리자에 의해서 Jeeve서버가 실행될때
자동으로 로드할 수 있도록 환경설정을 해주어야 한다.
local에 있는 서블릿과 remote에 있는 서블릿을 로드할 수 있다.
로드 하고자 하는 서브릿의 이름과 아규먼트,
클래스 이름을 패키지 이름까지 정확하게 적고(확장자 .class를 뺀다) 등록한다.
그러면, 다음과 같이 servlets.properties이 갱신된다.등록된 서블릿을 호출하기 위해서는 다음과 같은 URL형태로 오픈한다.servlets.properties # Servlets Properties # #.codebase=URL where the code is located # .code=class name (foo or foo.class) # .initArgs=list of {name, value} pairs which can be accessed # by the servlet using the servlet API calls # # For example: # rcounter.codebase=http://www.javasoft.com/~pavani/classes/ # rcounter.code=rcounter.class # ...... # admin servlet admin.code=sun.server.http.AdminServlet ####################### Demo Servlets ############################ # local counter counter.code=Counter counter.initArgs=\ initial=0 # phone servlet phone.code=PhoneServlet phone.initArgs=\ phonelist=servlets/phonelist ......
rules.properties # Servlet rules properties # # This file specifies the translation rules for invoking servlets. # The syntax is: # #= # # where is the virtual path used to invoke the servlet, # and is the name of the servlet. Surrounding white space # is ignored. The ordering of the rules is not important, as the longest # match will always be used first. /=file /cgi-bin=cgi /imagemap=imagemap /servlet=invoker /counter.html=counter /phone.html=phone /snoop.html=snoop /finger.html=finger /fun.html=fun ......
|
|
|
| [그림 4] Jeeves File Aliasing | [그림 5] Jeeves Servlet Aliasing | [그림 6] Servlet Loading |
mime.properties
# Default Mime Type
*=text/plain
# Mime Types
java=text/plain
html=text/html
htm=text/html
body=text/html
txt=text/plain
rtx=text/richtext
ps=application/x-postscript
class=application/java
......
Jeeves 역시 ACL(Access Control Lists)에 의해서 웹페이지나
서블릿과 같은 리소스를 사용할 수 있는 사용자를 등록/삭제할 수 있다.
각 사용자는 ID와 Password를 가질 수 있고, Realm을 이용해서
같은 ID로 서로다른 접근 영역을 지정할 수 있다.
(Jeeves A1.2에서는 새로운 realm을 지정할 수 있는 기능은 없고
adminRealm, defaultRealm만 지원한다.)
특별히 사용자의 권한중에서도 앞부분의 'admin'과 같은 관리자 권한을
부여할 수 가 있는데, 만약 실수를 해서 암호를 잊어버리면 다시는
더이상 서버 관리를 할 수 없으므로 조심히 등록해야 하고
실수가 없도록 유의해야 한다.
여기 관리자 화면에서 갱신된 내용은 'admin/realms'디렉토리에
계정이 자동으로 등록된다. 이곳에는 암호화 되어 있는 파일도 있으므로
가급적 수정하지 않는 것이 좋다.
|
|
|
|
|
|
|
|
|
여기에서는 jeeve의 http 서버기능이 어떻게 구현되고, servlet 의 실행 구조에 대해서 알아본다. 특히, 자바의 독특한 특징중에서 자바 프로그램은 곧 라이브러리로써 프로그래밍에 사용할 수 있다는 점이다. 즉 Jeeve의 http internet server와 유사한 프로그램과 Servlet과 같은 프로그래밍을 할 수 있으므로, Jeeve와 Servlet의 API에 대해서 간단히 설명한다.
일반적인 Http Server(Daemon)은 실행시키면 여러개의 프로세스가 생성되어 Client가 접속하기를 기다린다. Jeeve도 마찬가지로 여러곳에서 같은 port로 접속을 처리할 수 있도록 지원하는데 다른점은 Thread로 처리된다는 것이다. 자세히 말하면, 서버는 지속적으로 Client의 접속을 기다리고 있고 접속이 시도되면 스레드를 생성해서 서비스를 하고, 다시 접속을 기다리는 형태이다.
Jeeve의 기본 기능 구현에 사용된 패키지는 다음과 같다.
위에서 설명한 바와같이 관리자에의해 등록된 서블릿은 서버가
실행 될때 자동으로 로드된다. 그밖에 서블릿은 필요시에 로드 된다.
따라서, 서블릿은 인터넷에서 자동으로 로드되어 실행 되는
애플릿과도 같은 바이트코드 형태의 객체이다.
일반적인 웹서버를 설치하면 imagemap과 같은 기본적인 CGI루틴이 존재하듯이, 서블릿 중에는 기본적인 Core Servelt이 있고, 다음과 같은 패키지 들이 있다. 패키지 중에는 위에서 간간히 설명한 패키지들도 포함되어 있다.
source code
import java.io.*;
import java.servlet.*;
import sun.server.html.*;
public class SimpleServlet extends Servlet {
public void service(ServletRequest req, ServletResponse res)
throws Exception
{
res.setContentType("text/html");
res.writeHeaders();
OutputStream out = res.getOutputStream();
String title = "SimpleServlet Output";
HtmlPage page = new HtmlPage(title);
page.addTagPair("H1", title);
page.addText("<P>This is output from SimpleServlet.");
page.write(out);
out.flush();
}
public String getServletInfo() {
return "A simple servlet";
}
}
HTML tag
<a href="/servlet/simpleservlet">Try it</a>
source code
import java.io.*;
import java.util.*;
import java.servlet.*;
public class SnoopServlet extends Servlet {
public void service(ServletRequest req, ServletResponse res)
throws IOException
{
res.setContentType("text/html");
res.setHeader("Pragma", "no-cache");
res.writeHeaders();
PrintStream out = new PrintStream(res.getOutputStream());
out.println("<html>");
out.println("<head><title>Snoop Servlet</title></head>");
out.println("<body>");
out.println("<h1>Request information:</h1>");
out.println("<pre>");
print(out, "Request method", req.getMethod());
print(out, "Request URI", req.getRequestURI());
print(out, "Request protocol", req.getProtocol());
print(out, "Servlet path", req.getServletPath());
print(out, "Path info", req.getPathInfo());
print(out, "Path translated", req.getPathTranslated());
print(out, "Query string", req.getQueryString());
print(out, "Content length", req.getContentLength());
print(out, "Content type", req.getContentType());
print(out, "Server name", req.getServerName());
print(out, "Server port", req.getServerPort());
print(out, "Remote user", req.getRemoteUser());
print(out, "Remote address", req.getRemoteAddr());
print(out, "Remote host", req.getRemoteHost());
print(out, "Authorization scheme", req.getAuthType());
out.println("</pre>");
/*
Hashtable params = req.getQueryParameters();
if (params.size() > 0) {
out.println("<h1>Servlet parameters:</h1>");
out.println("<pre>");
Enumeration e = params.keys();
while (e.hasMoreElements()) {
String name = (String)e.nextElement();
out.println(" " + name + " = " + (String)params.get(name));
}
out.println("</pre>");
}
*/
if (!req.getProtocol().equals("HTTP/0.9")) {
out.println("<h1>Request headers:</h1>");
out.println("<pre>");
String name;
for (int i = 0; (name = req.getHeaderName(i)) != null; i++) {
out.println(" " + name + ": " + req.getHeader(name));
}
out.println("</pre>");
}
out.println("</body></html>");
}
private void print(PrintStream out, String name, String value) {
out.print(" " + name + ": ");
out.println(value == null ? "<none>" : value);
}
private void print(PrintStream out, String name, int value) {
out.print(" " + name + ": ");
if (value == -1) {
out.println("<none>");
} else {
out.println(value);
}
}
private static final String UNKNOWN = "<unknown>";
public String getServletInfo() {
return "A servlet that shows the request headers sent by the client";
}
}
HTML tag
<a href="/snoop.html">Try it</a>
source code
import java.io.*;
import java.servlet.*;
import sun.server.html.*;
public class FunServlet extends Servlet {
public void service(ServletRequest req, ServletResponse res)
throws Exception
{
String line;
res.setContentType("text/html");
res.writeHeaders();
OutputStream out = res.getOutputStream();
DataInputStream in = new DataInputStream(req.getInputStream());
String title = "Servlet Demo";
HtmlPage page = new HtmlPage(title);
//
// Spew out html code that will make the browser load an applet.
// Setup the codebase right. Will work only in Java enabled browsers
//
page.addText("<applet code=NervousApplet.class codebase=\"../applet/\" height=200 width=1800>");
page.addText("<param name=text value=\"Jeeves can load Servlets!\">");
page.addText("</applet>");
page.write(out);
}
}
HTML tag
<a href="/fun.html">Try it</a>
source code
import java.io.*;
import java.servlet.*;
import sun.server.html.*;
public class FunServlet extends Servlet {
public void service(ServletRequest req, ServletResponse res)
throws Exception
{
String line;
res.setContentType("text/html");
res.writeHeaders();
OutputStream out = res.getOutputStream();
DataInputStream in = new DataInputStream(req.getInputStream());
String title = "Servlet Demo";
HtmlPage page = new HtmlPage(title);
//
// Spew out html code that will make the browser load an applet.
// Setup the codebase right. Will work only in Java enabled browsers
//
page.addText("<applet code=NervousApplet.class codebase=\"../applet/\" height=200 width=1800>");
page.addText("<param name=text value=\"Jeeves can load Servlets!\">");
page.addText("</applet>");
page.write(out);
}
}
HTML tag
<form action="/finger.html" method="GET">
<table>
<tr><td>Username:</td><td><input type="TEXT" name="user" size=10></td></tr>
<tr><td>Hostname:</td><td><input type="TEXT" name="hosts" size=10></td>
<td>leave blank for local host<br>
multiple hostnames may be separted by commas</td></tr>
<tr><td>Verbose:</td><td><input type="checkbox" name="verbose" value="yes" CHECKED></td></tr>
</table>
<input type="SUBMIT" value="Try it">,
</form>
|
|
| |
지금까지 웹 서버로써 Jeeve와 기존의 CGI와 비슷한 형태의 Java 응용 프로그램인 Servlet에 대해서 알아보았다. CGI 프로그램을 실행하면 새롭게 프로그램이 Load되어 실행되고 여러명의 사용자가 같은 CGI를 실행하더라도 각각의 CGI프로그램이 새롭게 로드되어 실행되는 반면 Servlet은 여러가지 장점을 가지고 있다.
Servlet은 처음 실행되면 Server가 down될때 까지 계속 실행되어, 여러명의 다른 사용자가 Servlet을 접속하면 Thread를 생성하여 서비스한다. 마치 Daemon과 같은 기능을 유지한다. 또한, Servlet은 지속적으로 실행되고 있으므로 HTTPD의 근본적인 문제인 Connection을 유지할 수 있다는 장점을 가지고 있다. 한편, Jeeve와 Servlet은 모두 자바로 개발되었기 때문의 기타 자바의 장점인 플랫폼 독립적이고(새롭게 컴파일할 필요가 없다.), 동적이며 확장성/이식성/유지보수 기능이 뛰어나며, 프로그램 사이즈가 아주 작기 때문에 시스템 부하가 작다. 아직까지 정식 버전의 Jeeve가 나오지 않았지만, 자바로 개발된 HotJava 웹 브라우저와 함께 앞으로 크게 기대된다.
그밖의 새로운 소식이나 궁금한 사항은 메일링 리스트를 통해서 얻을 수 있다.