제공 : 한빛 네트워크
저자 : Sunil Patil
역자 : 이대엽
원문 : http://www.onjava.com/pub/a/onjava/2006/11/08/advanced-java-content-repository.html
☞ 이전 기사 보기
관찰
관찰은 여러분의 컨텐츠 저장소를 모니터링 하게 하는 것과 어떤 저장상태의 변경이 일어날 때 특정 비즈니스 로직을 실행할 수 있게 해준다. 예를 들어 이 예제 블로그 애플리케이션이 기업 블로그 목적으로 여러분의 회사에서 사용되며 모든 직원들이 블로그 계정을 갖게 된다고 가정해 보자. 이제 여러분 회사의 법무부서에서 단순히 블로그 내용의 법적 의미를 확인할 목적으로 각각의 새로운 블로그 엔트리가 게시될 때마다 법무팀으로 전자메일이 보내지도록 요구한다고 상상해 보라. 관찰은 이러한 기능을 가능케 해준다.
여러분은 repository.getDescriptor("OPTION_OBSERVATION_SUPPORTED")를 사용하여 저장소 디스크립터 테이블에 쿼리를 던져 여러분의 저장소가 관찰기능을 구현하고 있는지 확인할 수 있는데, 이 메소드 호출은 관찰 기능이 지원되면 true를 리턴하며 그 외의 경우 false를 리턴한다.
다음의 단계들을 따라 여러분의 예제 블로그 애플리케이션을 변경하여 새로운 블로그 항목이 추가될 때마다 이벤트 리스너가 통지받도록 해보자. 이 버전에서는 전자메일을 보내는 대신 새로운 블로그를 콘솔에 출력한다.
- 먼저 JackrabbitPlugin.init()를 아래와 같이 변경한다:
public void init(ActionServlet actionServlet, ModuleConfig moduleConfig)
throws ServletException {
System.setProperty("org.apache.jackrabbit.repository.home",
"c:/temp/Blogging");
Repository repository = new TransientRepository();
session = repository.login(new SimpleCredentials("username",
"password".toCharArray()));
NodeEventListener nodeEventListener = new NodeEventListener();
if (repository.getDescriptor(
Repository.OPTION_OBSERVATION_SUPPORTED).equals("true")){
ObservationManager observationManager =
session.getWorkspace().getObservationManager();
observationManager.addEventListener(nodeEventListener,
Event.NODE_ADDED,"/",true,null,null,false);
}
}
저장소에 접속한 다음, 이 저장소가 관찰기능을 지원하는지 확인한다. 만약 저장소가 관찰 기능을 지원하면 작업공간에 getObservationManager()를 호출하여 ObservationManager를 얻어온다. 관찰자는 저장소 수준이 아닌 작업공간 수준에서 작동함을 유념하라.
ObservationManager 클래스는 리스너 등록 및 등록해지에 사용되는 메소드를 정의한다. 여러분은 ObservationManager.addEventListener()를 호출하여 새로운 이벤트 리스너를 등록할 수 있다. 첫 번째 인자는 EventListener의 구현인데 이벤트 리스너의 onEvent()는 저장소에 의해 호출되며 이벤트에 관해 통지받는다. 다음 인자는 여러분이 듣고자(listen) 하는 이벤트이며 이 경우에는 우리는 노드 추가 이벤트에 관심이 있다. 세 번째 파라미터는 여러분이 관심 있어하는 노드의 경로이다. 네 번째 파라미터는 플래그인데, true이면 여러분은 자식 노드 계층에서 노드가 어디에 추가되는지에 상관없이 관심이 있다는 것을 의미한다. 다음의 두 파라미터는 이벤트를 필터링하는데 사용되는 것인데, 첫 번째 파라미터는 UUID의 배열을 받아 여러분이 어떤 이벤트의 연관된 부모 노드가 이 목록의 UUID 중의 하나를 갖는 이벤트에만 관심이 있다는 것을 가리킨다. 다음 파라미터는 nodeTypes의 배열을 받는데, 이 파라미터의 값이 null이 아닐 경우 여러분은 연관된 부모노드가 파라미터로 받은 노드 타입중의 하나를 가질 경우에만 통지받게 될 것이다. 마지막 파라미터는 여러분이 동일한 노드에서 일어나는 이벤트에 관심이 있는지 여부를 나타내는 플래그이다. 만약 true이면 여러분은 통지받지 않을 것이다(여러분이 직접 추가한 것뿐만 아니라 다른 누군가가 동일한 작업공간에 추가한 노드도 포함한다).
- 이제 NodeEventListener를 구현할 차례이다:
public class NodeEventListener implements EventListener {
public void onEvent(EventIterator eventIterator) {
while (eventIterator.hasNext()) {
Event event = eventIterator.nextEvent();
String eventPath = event.getPath();
int eventType = event.getType();
if (eventType == Event.NODE_ADDED) {
String nodePath = eventPath.substring(1, eventPath.length());
Session session = JackrabbitPlugin.getSession();
Node blogEntryNode = session.getRootNode().getNode(nodePath);
if(blogEntryNode.getName().equals("blogEntry")){
_logger.debug("New blog entry is added by"
+ blogEntryNode.getProperty(
JackrabbitBlogEntryDAO.PROP_BLOGAUTHOR)
.getString()
+ ", titled "
+ blogEntryNode.getProperty(
JackrabbitBlogEntryDAO.PROP_TITLE)
.getString());
}
}
}
}
저장상태에 변화가 발생하면 저장소는 통지를 받도록 등록된 각각의 리스너의 onEvent() 메소드를 호출하여 이벤트 통지를 EventIterator 객체로서 전달한다. EventIterator는 작업공간에 대한 저장상태의 변화에 대해 말해주는 이벤트 묶음(다시 한번 말하지만, 특정 리스너에 대해 걸러진)을 담고 있다. 이 경우 우리는 새로운 노드가 추가된 경우에만 관심이 있으며 따라서 EventIterator는 하나의 노드 추가 이벤트만을 갖게 될 것이다. 이벤트를 갖게 되면 우리는 event.getPath() 메소드를 호출함으로써 새로이 추가된 노드의 경로를 획득할 수 있다. 획득된 경로를 이용하여 새로이 추가된 노드를 검색하고 로거에 세부내용을 출력한다.
코드를 빌드하여 배포하고 나서 새로운 blogEntry를 추가해 보면 여러분은 Session.save() (혹은 Item.save()) 메소드가 호출되자마자 NodeEventListener의 onEvent() 메소드가 다른 쓰레드에서 호출되어 새로이 생성된 노드의 세부내용이 로그파일에 덤프되는 것을 볼 수 있을 것이다.
요약
이 기사에서 우리는 JSR-170에 정의된 두 가지 가장 유용한 고급기능에 대해 논의하였다. 우리는 JSR-170을 사용하여 버전관리와 관찰을 구현하는 방법에 관해 논하였다. 잠금과 SQL 검색의 선택기능을 이용하는 애플리케이션을 개발하는 방법에 관해서는 예제에 사용된 예제코드뿐만 아니라
아파치 잭래빗 온라인 문서도 훑어보라.
표준화 노력의 성공에 있어 가장 중요한 한가지 요인은 그러한 표준화 노력에 대한 업계의 지원이 얼마만큼이나 있느냐이다. JSR-170의 가장 멋진 점은 여분의 거리를 둠으로써 이 스펙이 좀 더 수용가능 해지도록 만든다는 것이다. 핵심기능을 레벨 1과 레벨 2 규약을 준수하는 것들로 분할하는 전략으로 인해 컨텐츠 저장소 벤더들이 어떤 레벨이 그들에게 가장 합리적이든 간에 JSR-170에 대한 지원을 시작하는 것이 용이해진다. 스펙에 있어 부차적인 위험요소는 만약 여러분이 고급기능을 정의하지 않을 경우 모든 벤더들이 그것들을 각자의 방식대로 구현하기 시작할 것이라는 것이다. JSR-170은 이러한 고급기능들을 선택사항으로 정의함으로써 멋지게 그 문제를 해결하였는데, 따라서 만약 여러분이 그러한 고급기능들을 구현하고자 결정했다면 여러분은 표준화된 방식에 의해 구현하게 될 것이다.
JSR-170 전문가 그룹리스트를 훑어보면 여러분은 JSR-170이 이미 Day Software, EMC Corporation, Filenet, Vignette, IBM, BEA, Oracle, Sun Microsystems과 같은 주요 CMS 벤더들로부터 지원을 얻고 있다는 것을 알게 될 것이다.
JSR 283하에 다음 버전의 자바 컨텐츠 저장소 API 스펙인 버전 2.0에 대한 작업은 이미 시작되었다. 이 스펙은 JSR-170에서 다루어지지 않았던 몇 가지 좀 더 고급 기능에 초점을 둘 것이다.
리소스
Sunil Patil는 5년 이상 J2EE 기술 관련 일을 해오고 있으며 관심분야는 객체 관계 매핑 도구(object relational mapping tools), UI 프레임워크 및 포털이다.