Java Network Launching Protocol (JNLP) and its reference implementation, Java Web Start 자바 네트워크 구동 프로토콜(JNLP)과 참조 구현, 자바 웹 스타트
한 승 협[tedlovesmary@hotmail.com]
자바스터디 네트워크 [http://javastudy.co.kr]
자바 프로그래밍 언어의 초창기에는 클라이언트 측 개발에 많이 강조되었다. 애플릿이나 코드의 안전한 다운로딩에 대한 자바의 지원은 웹상에서 기능을 전달하기에 이상적인 것 같았다. 그러나 실제로는 자바 프로그래밍 언어의 가장 큰 성공은 서버측에서 거둬오고 있다. 자바의 강력함과 유연함은 서버측 개발자의 사랑과 관심을 받아오고 있다. 반면에 클라이언트 측에서의 개발은 줄어들고 있다. 다루기 힘든 배치 문제가 애플릿의 사용을 제한하고 있고, 개발자들을 브라우져 기반의 "씬(thin)" 클라이언트로 가게끔 한다.
자바 네트워크 런칭 프로토콜(JNLP)은 이 모든 것을 바꿀 수 있다. 자바 커뮤니티 프로세스 JSR-56을 통해 개발된 JNLP는 클라이언트에 자바 기능을 배치하는데 있어 이전의 많은 문제를 해결한다. JNLP 클라이언트는 네트워크 상의 호스트 리소스로부터 프로그램을 실행시킬 수 있는 애플리케이션 혹은 서비스이다. 만약 JNLP과 함께 프로그램을 작성한다면 JNLP 클라이언트는 다음과 같은 것을 할 수 있다.
- 애플리케이션을 위한 자바 런타임 환경의 버젼을 탐지하거나 설치, 사용할 수 있다.
- 브라우져나 데스크탑으로부터 애플리케이션을 실행 할 수 있다.
- 가능할 때, 자동적으로 새 버젼의 애플리케이션을 다운로드할 수 있다.
- 빠른 실행을 위해 애플리케이션에 의해 사용된 클래스를 캐쉬할 수 있다.
- 애플릿이나 애플리케이션으로 모두 실행할 수 있다.
- 필요하면 네이티브 라이브러리를 다운로드할 수 있다.
- 안전한 방법으로 파일시스템 같은 로컬 리소스를 사용할 수 있다.
- 자동적으로 위치하고 외부적으로 필요한 것을 로드할 수 있다.
썬마이크로시스템즈는 자바 웹 스타트라는 JNLP의 참조 구현을 제공하고 있다. JFC 스윙을 이용하는 간단한 애플리케이션을 배치하기 위해 JNLP를 사용해보자. 이것을 하기 위해서는 http://java.sun.com/products/javawebstart에서 자바 웹 스타트를 다운로드할 필요가 있다.
다음은 애플리케이션 소스다.
//File HelloJNLP.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class HelloJNLP extends JFrame {
public HelloJNLP() {
super("Hello JNLP");
String loadedFrom = this.getClass().getClassLoader().toString();
JLabel jl = new JLabel("loaded by " + loadedFrom);
JEditorPane jtp = new JEditorPane("text/plain", "Edit this text");
getContentPane().add(jl, BorderLayout.NORTH);
getContentPane().add(jtp, BorderLayout.CENTER);
}
public static void main(String [] args) {
JFrame f = new HelloJNLP();
f.setBounds(100,100,325,250);
f.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.out.println("Shutting down...");
System.exit(0);
}
});
}
}
JNLP 핵심에 배치 목록(?)이 있다. 배치 목록은 .jnlp 확장자를 가지는 XML 파일이다( JNLP 스펙은 간단히 "JNLP 파일"이라고 부른다.). HelloJNLP 애플리케이션을 배치하기 위해서는 다음과 같은 JNLP 파일을 적어줘야 된다.
<?xml version="1.0" encoding="UTF-8"?>
<!-- file Hello.jnlp -->
<jnlp codebase="http://staff.develop.com/halloway/TechTips/May2001"
href="http://staff.develop.com/halloway/TechTips/May2001/Hello.jnlp">
<information>
<title>JDC TechTips - May 30, 2001</title>
<vendor>Tech Tips Sample May 2001</vendor>
<icon href="HelloJNLP.jpg"/>
</information>
<resources>
<j2se version="1.2+"/>
<jar href="HelloJNLP.jar"/>
</resources>
<application-desc main-class="HelloJNLP"/>
</jnlp>
이 목록 파일은 HelloJNLP 애플리케이션을 다운로드 하고 사용하기 위한 모든 정보를 담고 있다.
jnlp 요소의 codebase 속성은 애플리케이션 리소스들을 찾기 위한 최상위 URL을 나타낸다.
information 요소는 JNLP 사용자 인터페이스가 클라이언트에 표시할 정보를 나타낸다.
j2se 요소는 클라이언트가 반드시 1.2나 이후 버젼의 J2SEtm을 가지고 있어야 됨을 나타낸다. (이것은 브라우져에 설치된 VM이 뭐든간에 종종 충돌을 일으키는 애플릿 배치를 능가하는 큰 향상이다.)
jar 요소는 jnlp codebase 로부터 상대적인 애플리케이션 JAR파일의 위치를 기술한다.
application-desc 요소는 실행시키기 위한 클래스를 나타낸다. 명령어 전달인자나 시스템 변수를 기술하기 위해 서브 요소를 추가할 수도 있다.
애플리케이션을 웹서버에 배치하려면, 다음 단계들을 실행할 필요가 있다.
jnlp codebase 안의 URL을 바꾸고 href 를 해당 웹서버에 맞춰 적절한 URL로 설정해라.
- JNLP 파일을 웹서버에 올려라.
- HelloJNLP.java를 컴파일하고 jar로 묶어라. 그리고 웹서버에 올려라. 예를 들면,
jar cvf HelloJNLP.jar HelloJNLP.class HelloJNLP$1.class
- HelloJNLP.jpg 아이콘 파일을 만들고 웹서버에 올려라. 이 파일을 사용해도 된다. http://staff.develop.com/halloway/TechTips/May2001/HelloJNLP.jpg
- 웹서버의 mine-type 연결에 .jnlp를
application/x-java-jnlp-file 로 설정해라. 예를 들면, 아파치의 경우, 다음을 mime.types파일에 추가해라.application/x-java-jnlp-file jnlp
- 웹서버를 재시작해라.
클라이언트로부터 이 애플리케이션을 실행하기 위해서는 먼저 자바 웹 스타트 설치 여부를 확인해야 된다. 그런다음 간단히 브라우져에서 jnlp파일의 URL을 가리키기만 하면 된다. 자바 웹 스타트 클라이언트는 jnlp파일과 필요한 리소스들을 다운로드 하고 애플리케이션을 실행할 것이다. 에디터에 뿌려진 "Edit this text"라는 문자열을 보게 될 것이다. 만약 웹서버를 설정하는데 문제가 있거나 웹서버로 접근할 수 없다면,http://staff.develop.com/halloway/TechTips/May2001/Hello.jnlp에서 실행할 수도 있다.
HelloJNLP는 브라우져 안에서 애플릿으로 돌아가고 있는게 아니고 독립적인 애플리케이션이란 걸 알아둬라.
애플리케이션을 닫으면, HelloJNLP는 "Shutting down..." 메시지를 출력하기 위해 System.out을 사용한다. 그러나 콘솔은 보이지 않는다. console 은 자바 웹 스타트가 디폴트로 "off" 해놓는 많은 설정 중에 하나이다. 이것은 다음처럼 바꿀 수 있는 설정 중 하나다.
- 자바 웹 스타트 설치 디렉토리에 javaws.cfg 파일을 고쳐라. "javaws.cfg.forceUpdate=true"라고 한 줄을 추가해라. 이렇게 하면 자바 웹 스타트가 애플리케이션을 실행하기 전에 새 버젼을 자동으로 확인한다.
- 자바 웹 스타트 프로그램을 실행해라. File -> Preferences 에서 Advanced 탭으로 가서 "Show Java Console"을 선택해라. 또 "Log Output"를 선택하고 로그 출력 파일을 지정해라. 디버깅을 할 때나 System.out이나 System.err를 보고자 할 때 아주 유용하다.
HelloJNLP 애플리케이션은 에디터를 보여준다. 그러나 그 애플리케이션을 닫으면 에디터의 내용은 날아가 버린다. 클라이언트 하드드라이브에 에디터의 상태를 자동으로 저장하기 위해서 HelloJNLP에 다음 코드를 추가해라.
// HelloJNLP.java로 바뀐다.
import java.io.*;
import java.net.*;
import javax.jnlp.*;
// 생성자를 이 새로운 버젼으로 대체해라.
JEditorPane jtp;
public HelloJNLP() {
super("Hello JNLP, Second Version");
String loadedFrom = this.getClass().getClassLoader().toString();
JLabel jl = new JLabel("loaded by " + loadedFrom);
jtp = new JEditorPane("text/plain", "Edit this text");
readEditorContents();
getContentPane().add(jl, BorderLayout.NORTH);
getContentPane().add(jtp, BorderLayout.CENTER);
addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.out.println("Shutting down...");
try {
writeEditorContents();
}
catch (Exception ex) {
System.out.println("Yoinks!");
ex.printStackTrace();
}
System.exit(0);
}
});
}
//이 헬퍼 메소드들을 추가하라.
private void writeEditorContents() throws
UnavailableServiceException, IOException {
System.out.println("writeEditorContents");
PersistenceService ps = (PersistenceService)
ServiceManager.lookup("javax.jnlp.PersistenceService");
BasicService bs = (BasicService)
ServiceManager.lookup("javax.jnlp.BasicService");
URL baseURL = bs.getCodeBase();
System.out.println("CodeBase was " + baseURL);
URL editorURL = new URL(baseURL, "Editor");
try {
ps.create(editorURL, 1024);
}
catch (Exception e) {
e.printStackTrace();
}
FileContents fc = ps.get(editorURL);
DataOutputStream os = new DataOutputStream(
fc.getOutputStream(false));
String s = jtp.getText();
os.writeUTF(s);
os.flush();
os.close();
}
private void readEditorContents() {
try {
PersistenceService ps = (PersistenceService)
ServiceManager.lookup("javax.jnlp.PersistenceService");
BasicService bs = (BasicService)
ServiceManager.lookup("javax.jnlp.BasicService");
URL baseURL = bs.getCodeBase();
URL editorURL = new URL(baseURL, "Editor");
FileContents fc = ps.get(editorURL);
DataInputStream is = new DataInputStream(fc.getInputStream());
jtp.setText(is.readUTF());
is.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
JNLP API는 몇몇 공통적인 클라이언트 작업을 할 수 있도록 보안 샌드박스에 제약을 받지 않는 서비스 집합을 정의하고 있다. writeEditorContents 메소드에서 BasicService는 애플리케이션의 코드베이스를 찾아낸다. 그런다음, PersistenceService는 애플리케이션의 코드베이스로부터 상대적인 적당한 URL을 가지고 에디트 창의 내용을 로컬 하드에 캐쉬한다. PersistenceService에 의해 제공된 이름/값의 쌍은 브라우져의 쿠키와 비슷하다. 자바 웹 스타트는 그 쌍을 "머핀"이라고 부름으로써 예전부터 사용해 온 이 방식을 존중한다. 머핀은 큰 데이터의 저장공간으로는 적합하지 않고 클라이언트에다 작은 식별자를 임시 저장할 때 사용해야 한다. 그러면 이런 식별자들은 서버상에 존재하는 많은 정보를 찾는데 사용되어 질 수 있다.
바뀐 애플리케이션을 웹서버에 재배치해봐라. 그리고 URL로 클라이언트에서 그것을 다시 실행시켜봐라. 웹서버가 없다면 http://staff.develop.com/halloway/TechTips/May2001/Hello2.jnlp 에서 이 버젼을 실행해 볼 수도 있다. 자바 웹 스타트는 자동적으로 애플리케이션이 바뀐 것을 탐지해내고 새 버젼을 실행한다. 타이틀 바의 "Hello JNLP, Second Version"이라는 문자열을 보면 확인할 수 있다. 에디터의 창에 어떤 변화를 주고 프로그램을 닫아 봐라. 그리고 다시 실행시키면, 바뀐 내용을 볼 수 있을 것이다. (새 버젼을 처음 실행시키면, 아마 콘솔 출력으로 예외가 나올 수도 있다. 왜냐하면 readEditorContents이 처음에는 머핀을 못찾기 때문이다.)
JNLP 는 여기 보여진 것 보다 더 많은 서비스를 제공한다. 예를 들면,
- 어떻게 애플리케이션이 다운로드 되는 가를 정교하게 제어할 수 있다.
- JAR간에 의존성 관계에 대해 기술할 수 있다.
- 네이티브 코드 인스톨러를 다운로드하고 실행할 수 있다.
- 사인된 코드에 추가적인 허가를 줄 수 있다.
- 특정 버젼의 애플리케이션이나 애플릿을 요청할 수 있다.
JNLP에 대해 더 알고 싶으면, http://java.sun.com/products/javawebstart/download-spec.html JNLP 스펙을 다운받자.
자바 웹 스타트에 대한 자세한 정보는 http://java.sun.com/products/javawebstart/ 를 방문하세요.
|