'2010/01'에 해당되는 글 3건

  1. 2010/01/19 unix date 포맷 지정하기
  2. 2010/01/08 웹 어플리케이션 초기화 PlugIn 구현
  3. 2010/01/06 JNI 와 java.library.path
발생일: 2010.01.19

문제:
unix 에서 현재 날짜를 출력하려면 date 커맨드를 날리면 된다.
그렇다면 포맷은 어떻게 지정해야 할까?

해결책:
이 포스트에 굉장히 잘 정리되어 있으니 참고해보자.
간단하게, date +FORMAT 형태로 사용하면 된다.
예를 들어, 10-01-19 23:11:12 를 표시하고 싶을 경우,
date "+%y-%m-%d %T" 와 같이 표현하면 된다.




저작자 표시 비영리 변경 금지
Posted by ohgyun
발생일: 2009.01.06

문제:
진행 중인 미니 프로젝트에서 웹 어플리케이션이 로딩될 때 설정해야 할 것들이 있다.
여기서는 contextRealRoot 를 메모리에 미리 올려둘 목적으로 쓰려고 하는데,
그 외에도 리소스나, 권한 등 일반적으로도 초기화 때 설정할 사항들이 많다.

스트럿츠 프레임웍의 경우, 웹 어플리케이션의 초기 환경 설정을 위해 PlugIn 기능을 제공한다.

스트럿츠 프레임웍의 PlugIn 기능 보기



이 기능을 프레임웍이 없는 일반 서블릿 환경에서 가볍게 한 번 구현해 볼까 한다.


해결책:
스트럿츠 프레임웍을 뜯어보지는 않아서 어떻게 구현되어 있는 지는 정확히 모르겠지만,
여기서는 서블릿 컨텍스트 리스너와 옵저버 패턴을 써서 구현했으며, 개략적인 클래스 다이어그램은 아래와 같다.







PlugIn 인터페이스는 옵저버 역할을 하며, init() 메서드를 구현하도록 한다.
init() 메서드에서는 실제 초기화 할 작업을 구현하면 된다.
또한 ConcreatePlugIn 은 PlugIn 인터페이스를 구현한 실제 PlugIn 클래스라고 보면 되겠다.

옵저버 패턴 Subject 역할을 하는 것이 PlugInRepository 이며,
여기서는 PlugIn 을 담아 두고, 알려주는 역할을 한다.
PlugInRepository 의 init() 메서드를 통해 각 PlugIn 의 초기화 작업을 수행할 수 있다.

실제로 컨텍스트가 로드될 때 호출되는 것은 PlugInLoader 클래스이며 서블릿 컨텍스트 리스너이다.
web.xml 에서 <listener-class>로 등록되어 있어 컨텍스트 로드 시점에서 호출되며,
로더에서는 PlugInRepository 과 PlugIn 을 생성하여 등록하고 초기화 시킨다.


전체 코드는 아래와 같다.

전체 코드 보기



초기화 수행 시 필요한 작업들을 PlugIn 객체로 구현한 후,
코드의 PlugInLoader 의 init() 메서드에서처럼 PlugInRepository 에 등록한 후 작업을 호출해주면 된다.

PlugInRepository 의 생성자에 ServletContext 를 넘기도록 한 것은,
PlugIn 객체에서 컨텍스트에 접근할 수 있도록 하기 위해서이다.

실제로 작동시켜 보니 예상했던 대로 잘 작동한다.


몇 가지 기능을 추가로 구현하면, 가벼운 라이브러리로 쓸 수도 있을 것 같다.

#1.
여기서는 추가하려는 PlugIn 객체를 PlugInLoader 에서 직접 추가해줬다.
스트럿츠에서는 수행할 PlugIn 에 대한 정보를 struts-config.xml 에 추가해야 한다.

그렇다면 아예, 특정 인터페이스를 구현한 클래스를 찾는 ClassFinder 따위(검색해보니 좀 있다)를 구현해서,
구현 PlugIn 객체를 자동으로 찾아 호출하도록 하면 더 편리할 것 같다.

사용자 입장에서는 단지 PlugIn 인터페이스만 구현하게 말이다.

#2.
PlugInRepository 는 싱글턴으로 구현해도 괜찮을 것 같다.

#3.
컨텍스트가 종료될 때의 작업을 추가해도 괜찮겠다. (contextDestroyed 시)

#4.
그 외, 예외 처리가 필요하다. (플러그인의 초기화가 실패했을 경우, 로드 자체가 불가능 하게 할 것인가?)

#5.
여기서는 서블릿 컨텍스트 리스너를 이용해서 컨텍스트가 리로드 될 때에도 초기화가 수행된다.
만약, 서버를 올릴 때에만 초기화 하고 싶다면,
    1. 이미 로드되었는지 여부에 대한 flag 를 두어 처리하거나,
        (* 컨텍스트가 리로드 되면, 리스너 클래스 로딩를 새로 하는 모양이다.
            flag 를 static 으로 생성해도 그 값이 저장되지 않는다.)
    2. 컨텍스트 리스너 대신 servlet 의 load-on-startup 값을 1로 설정하면 되겠다.
        (PlugInLoader 를 서블릿으로 구현하고, 서블릿의 init() 메서드 부분을 구현한다.)

저작자 표시 비영리 변경 금지
Posted by ohgyun
발생일: 2010.01.05

문제:
시스템에서 Fasoo DRM 이라는 암호화 모듈을 사용하고 있다.
내부적으로는 문서 다운로드 요청이 들어왔을 때, 암호화 처리를 한 후 돌려주는 방식으로 사용하고 있는데,
얼마 전 서버를 옮긴 이후부터 클래스 패스를 찾을 수 없다는 메세지가 나온다.

javax.servlet.ServletException: no fasoopackager in java.library.path

서버는 JEUS 를 쓰는데, 업체에서 제공해준 jar 파일을
각 라이브러리 폴더(WEB-INF/lib, JEUS_HOME/lib/application 등)로 옮겨보며 테스트 해보아도 해결되지 않는다.

뭐가 문제일까...?


해결책:

javax.servlet.ServletException: no fasoopackager in java.library.path

이 메세지가 의미하는 것은 일반 자바 라이브러리의 클래스 패스를 찾지 못하겠다는 것이 아니라,
 "JVM 이 'fassopackager' 라는 네이티브 라이브러리를 찾을 수 없다" 는 것이다.
즉, 네이티브 어플리케이션을 실행하기 위한 라이브러리를 찾지 못한다는 얘기다.

위 암호화 모듈이 암호화 작업을 수행할 때, 모든 작업을 자바 라이브러리에서 수행하는 게 아니었던 것이다.
확인해보니 해당 라이브러리에서 암호화를 수행하기 위해 fasoopackager.dll 이라는 파일을 이용하고 있었다.

위와 같이, Java 에서 외부 프로그램에 접근하기 API를 JNI (Java Native Interface) 라고 한다.
해당 플랫폼에서만 실행 가능한 네이티브 코드(native code)에 접근하기 위해 만들어진 응용 프로프로그램 인터페이스로,
주로 자바만으로는 구현할 수 없거나, 다른 언어로 쓰여진 어플리케이션을 접근하려고 하는 경우에 쓰인다.
동작 환경이 해당 플랫폼에 제한된다는 단점이 있다.

JNI 를 사용하기 위해서는 사용하고자 하는 네이티브 라이브러리를 JVM 이 읽어올 수 있게 설정해줘야 한다.
native libary path 가 정상적으러 설정되어 있지 않아서 실행하고자 하는 파일을 찾을 수 없을 때,
보통 아래와 같은 예외가 발생한다.

java.lang.UnsatisfiedLinkError: no 파일명 in library path

native library path 를 설정해주는 방법은 운영체제마다 다른데,
Solaris 시스템 (Unix) 의 경우, LD_LIBRARY_PATH 에 해당 라이브러리의 경로를 설정해주면 된다.

윈도우 환경에서는 PATH 환경 변수에 해당 라이브러리 경로를 추가해주거나,
아래와 같이 자바 실행 옵션에 추가해주면 된다.(SDK 1.2 부터)

java -Djava.library.path=라이브러리 경로 클래스명


위 문제점이 발생한 환경에서는 사정 상 서버의 환경 변수를 추가할 수는 없었다.
다행히 제우스 실행 배치 파일을 확인해보니,
제우스 서버를 올릴 때 java.libarary.path 로 제우스 시스템 라이브러리(JEUS_HOME/lib/system) 폴더를 참조하고 있었다.

여기서는 해당 dll 파일을 제우스 시스템 라이브러리 폴더로 복사해주는 방법으로 해결했다~~


# 참고:

What is java.library.path?
문제 해결의 실마리를 얻은 JavaRanch 의 포럼
JNI 에 대한 위키백과 정보 (영문)

JNI 에 대한 SUN 의 튜토리얼.(영문)
HTML 버전으로 읽어보니 간편하고 좋다.
Introduction and Tutorial 부분만 읽어봤는데, 유래부터 예제까지 쉽게 잘 설명해뒀다.

저작자 표시 비영리 변경 금지
Posted by ohgyun