저자: Ed Burns

Java EE 5에 새로 포함된 통합 EL(Expression Language; 표현식 언어)은 아키텍처의 무결성을 그대로 유지하면서 웹 애플리케이션 티어의 병합을 가능하게 해주는 강력하고도 유연한 수단이다. 이와 관련하여 이미 이전의 엔터프라이즈 자바 기술 관련 테크 팁들(가령, JSP 페이지에서 엔터프라이즈 빈 사용하기)에서 JSP(JavaServer Pages) 2.0의 초기 버전의 EL을 다루었던 적이 있다. 불행히도 JavaServer Faces 기술 사용자는 JSP와 JavaServer Faces 기술 프로그래밍 모델 간의 차이 때문에 해당 버전의 EL을 활용할 수 없었는데, JavaServer Faces 기술 1.0과 1.1에서는 서로 다른 버전의 EL을 제공한다. 한편, 새로운 Unified EL의 경우 JSP와 JavaServer Faces 기술 EL을 서로 조화시키는 것이 가능한데, 즉 이 말은 JSP와 JavaServer Faces 기술 사용자들이 모두 동일한 Unifed EL을 활용할 수 있게 되었다는 것을 의미한다.

본 테크팁에서는 커스텀 ELResolver를 제공하여 Unifed EL의 기능을 확장하는 방법에 대해 알아보도록 한다. 또한 독자들은 이전의 JavaServer Faces 기술에서 PropertyResolverVariableResolver의 결합으로 구현된 것과 ELResolver의 차이점에 대해서도 배우게 된다.

본 테크팁의 일부 내용은 Ed Burns와 Chris Schalk가 저술한 JavaServer Faces: The Complete Reference(영문)에서 발췌한 것이다.

Unified EL 예제

다음은 통합 EL 표현식(expression)의 예제이다.

#{sessionScope.inventory['1353465'].unitPrice}

이 표현식은 다음과 같은 의미를 가진다: "현재의 HTTP 세션에서 inventory라는 이름의 엔트리를 찾는다. inventoryMap으로 취급하고 1353465 키 아래에서 엔트리를 찾는다. 엔트리 내에서 unitPrice라는 이름의 JavaBeans 속성을 찾는다." 시스템이 unitPrice 속성으로 무엇을 하는가는 사용 문맥(usage context)에 의해 좌우된다. JavaServer Faces 기술의 경우, 사용자가 사용자 인터페이스 컴포넌트에 입력하는 값은 'postback' 프로세스가 진행되는 동안 서버 측 객체에 전달(propagate)된다. JavaBeans set 메소드는 서버 측 객체의 값을 설정하는데, 속성의 값이 요구될 경우에는 JavaBeans get 메소드가 값을 획득한다. 따라서 unitPrice 속성의 값이 JavaServer Faces 기술 형식 내에서 포스트 백(posted back)되는 경우에는 제출된 값으로 적절한 JavaBeans set 메소드가 호출된다. JSP나 JavaServer Faces 기술 페이지를 렌더링 할 때는 해당 JavaBeans get 메소드가 호출되어 값을 추출하게 된다.

Java EE 웹 티어 내에는 표현식(expression)의 첫 부분에 사용될 때 특정 의미를 가지게 되는 일련의 내장 객체(implicit objects)가 있는데, Unified EL 표현식 예제에서는 sessionScope가 바로 내장 객체이다. Unified EL의 기능을 확장하는 가장 손쉬운 방법은 커스텀 ELResolver를 제공함으로써 새로운 내장 객체를 도입하는 것이다. 가령, Unified EL을 이용하여 JNDI(Java Naming and Directory Interface) 시스템에서 레퍼런스를 손쉽게 룩업할 수 있다면 참 좋겠는데, 우연찮게도 Apache Shale Project는 바로 그런 기능을 가지고 있다(Shale JNDI Integration 참조). 하지만 아쉽게도 이 기능은 Unified EL을 사용하지 않는 Java Server Faces 1.1 기술을 위해 구현된 것이다.

그렇다면 JNDI 룩업에 사용할 수 있는 커스텀 ELResolver를 검토해보기로 하자. 하지만 그 전에, VariableResolverPropertyResolver 클래스의 배경과 이들이 Unified EL 예제 식을 평가하는 데 어떻게 이용되는지를 먼저 살펴본다.

VariableResolverPropertyResolver

JavaServer Faces 1.0 및 1.1 런타임에는 VariableResolverPropertyResolver 등 두 클래스의 기본값 싱글턴 인스턴스가 포함되어 있는데, 이 클래스들은 EL 표현식 변환을 위한 메커니즘을 제공한다. 한편 JavaServer Faces 1.2에서는 Unified EL에 javax.el.ELResolver 클래스가 도입되면서 이 두 클래스가 더 이상 중요하지 않게 되었다.

다음 예제를 보면 JavaServer Faces 기술에서 VariableResolverPropertyResolver가 맡고 있는 중심적 역할을 잘 알 수 있다. 이 예제에서는 JavaServer Faces 런타임이 myVariableResolvermyPropertyResolver 변수를 이용하여 VariableResolverPropertyResolver 클래스에 대한 레퍼런스를 유지하는 것으로 가정한다. VariableResolver 클래스는 하나의 메소드 resolveVariable()을 가지고, PropertyResolver 클래스는 getValue()를 비롯한 다수의 메소드를 가진다. 이 예제에서는 resolveVariable()getValue() 메소드에 간소화된 버전의 서명이 사용되는 것으로 가정하고, 아래의 JavaServer Faces 기술 EL 표현식을 검토해 보도록 하자.

#{requestScope.user.firstName}

이 표현식을 변환하여 해당 값을 얻기 위해 JavaServer Faces 1.0과 1.1의 EL 구현은 식을 requestScopeuser.firstName의 두 부분으로 분해한다. JavaServer Faces 런타임은 myVariableResolver.resolveVariable("requestScope")를 호출하고, 이 메소드는 인자 문자열(argument string)을 취하여 변환한다. 이 때, requestScope는 표현식의 첫 부분으로 사용될 경우 특정한 의미를 가지는 내장 객체의 하나가 되며, 이는 요청 범위(request scope) 객체의 속성에 대한 액세스를 가능하게 해주고 이름을 키로 사용하는 요청 범위 변수의 Map을 나타낸다. (이들 내장 객체에 관한 자세한 내용은 "JavaServer Faces: The Complete Reference"의 Chapter 4, Table 7을 참고할 것.) VariableResolver 인스턴스는 반드시 현재의 javax.servlet.ServletRequest에 대해 설정된 속성 세트를 래핑하는 java.util.Map 구현을 반환해야 한다. 이제 Map 구현 requestMap을 호출해 보기로 하자.

requestScoperequestMap으로 성공적으로 변환되면, JavaServer Faces 런타임은 다시 표현식의 user.firstName 부분을 개별 요소, user, 그리고 firstName으로 분리한다. 그런 다음 런타임은 myPropertyResolver.getValue(requestMap, "user")를 호출하는데, 이 메소드는 Map에서 키 사용자 아래의 값을 찾아 반환한다. requestMap이 키 user 아래에 이런 값을 가지고 있고 이 값이 UserBean의 인스턴스라고 가정하자.

표현식 평가의 마지막 단계는 myPropertyResolver.getValue(userBean, "firstName")이 호출될 때 이루어진다. UserBean이 Plain Old JavaBean인 관계로, PropertyResolver는 이름 firstName을 이용하여 JavaBeans 속성을 찾아낸 다음 getFirstName() 메소드를 호출한다. 그런 다음 메소드는 사용자의 first name을 반환한다.

어떻게 해서 표현식이 계속 여러 부분으로 분리되고 평가 단계 n의 결과가 단계 n + 1의 평가에 전달되는지 주목할 것.

ELResolver 확장하기

이제 다시 커스텀 ELResolver로 되돌아가보자. 본 팁에는 커스텀 ELResolver의 예시를 위한 예제 패키지가 첨부되어 있으며, 패키지에는 커스텀 ELResolver를 위한 소스 코드가 포함되어 있다.

제일 먼저 알아야 할 것은, 커스텀 ELResolver는 반드시 추상 클래스 javax.el.ELResolver를 확장하고 공용 무인자 생성자(public no-argument constructor)를 제공해야 한다는 점이다.

시스템은 faces-config.xml 파일의 <el-resolver> 엘리먼트에 지정된 클래스의 전체 이름을 기초로 하여 애플리케이션이 시작되는 동안 ELResolver 인스턴스를 인스턴스화하기 때문에 무인자 생성자를 필요로 한다. 이 부분에 대해서는 나중에 좀더 다루기로 한다.

ELResolver의 주요 런타임 동작은 getValue(), setValue(), getType(), 이렇게 세 가지 메소드에 지정되며, 디자인 타임 동작은 getFeatureDescriptors(), getCommonPropertyType() isReadOnly()의 나머지 세 메소드에 지정된다. 먼저 런타임 동작에 대해 살펴보기로 하자.

Java EE 5에서는 VariableResolverPropertyResolver가 더 이상 중요하지 않게 되었지만 이 클래스들은 여전히 하위 호환으로 지원된다. 또한, Java EE 5에서는 PropertyResolverVariableResolver가 Unified EL 클래스 javax.el.ELResolver로 병합되었다. 기본적으로 ELResolvergetValue() 또는 setValue() 메소드에 대한 첫 번째 인자가 null인 경우 VariableResolver의 기능을 수행하며, 그 외의 경우에는 PropertyResolver의 기능을 한다.

커스텀 ELResolver 코드를 좀더 자세히 살펴보도록 하자.

getValue() 메소드에 특히 유의할 필요가 있는데, 이는 ELResolver에서 가장 자주 호출되는 메소드이다. JNDIELResolver는 단순히 EL에 JNDI 기능을 추가할 뿐이므로, null 인자는 반드시 속성 인자의 값을 살펴보아야 한다는 것을 의미한다. 속성 인자가 "jndi" 문자열과 같을 경우, JNDIELResolver는 ELResolver의 propertyResolved 속성을 true로 설정하고, JNDI에서 InitialContext를 참조하고, 그 java:comp/env Context 값을 얻어 이를 반환한다. 한편 비 null 인자는 반드시 javax.naming.Context 타입이어야 하는데, 이 때 JNDIELResolverpropertyResolved 속성을 true로 설정하고, Context 상의 lookup() 메소드를 호출하여 그 값을 반환한다.

다음은 getType() 메소드이다.

구현에 의해 getType() 메소드가 호출되는데, 이는 계속해서 setValue()를 호출할 경우 ClassCastException이 throw되지 않고 안전하게 호출될 수 있는지 여부를 판단하기 위함이며, 이 경우 베이스가 javax.naming.Context의 인스턴스라면 어떠한 Object라도 값으로 패스가 가능하다.

다음 메소드는 setValue()이다.

setValue() 메소드는 가령 var foo = "bar"와 같은 프로그래밍 언어 배정문(assignment statement)의 "left-hand-side"에서처럼 표현식이 값을 배정받을 수 있도록 하는데 사용된다. 단, 이 경우는 기존 Context 인스턴스에 값을 설정할 때만 유효하다. 따라서 값 설정을 위해서 rebind() 메소드가 호출된다.

나머지 세 메소드, getFeatureDescriptors(), getCommonPropertyType(), isReadOnly()는 예제 코드에 나와 있기는 하지만 이에 관한 논의는 본 테크 팁에서는 다루지 않도록 하고, 상세한 논의 내용은 "JavaServer Faces: The Complete Reference"을 참고하기 바란다. 현재로서는 이 메소드들의 목적이 ELResolver로 하여금 각 기능의 디자인 타임 환경(가령 IDE)을 알릴 수 있도록 하기 위한 것임을 알고 있는 것으로도 충분하다.

ELResolver 선언하기

각자의 ELResolver를 Java EE 런타임에서 볼 수 있도록 하려면 반드시 이를 애플리케이션 구성 리소스 파일에서 선언해야 한다. Java EE 런타임은 일련의 특정한 규칙에 따라 애플리케이션 구성 리소스 파일을 인식하고 로드하는데, 본 테크 틉에서는 편의상 WEB-INF/faces-config.xml을 위치(location)로 사용하기로 한다. (애플리케이션 구성 리소스 파일을 로딩하는 규칙에 관한 상세한 내용은 "JavaServer Faces: The Complete Reference"를 참조할 것.) 단순히 다음 엘리먼트를 faces-config.xml 파일의 <application> 엘리먼트 내에 삽입한다.

예제 코드 실행하기

본 예제의 런타임 환경은 Java EE 5 SDK이며, Java EE 다운로드 페이지에서 다운로드할 수 있다. 예제 코드는 NetBeans 5.5 Beta 2 Web Application 프로젝트로 패키징되어 있으며, 사용자는 NetBeans 5.5 Beta 2에서 이 프로젝트를 열어 실행할 수 있다.

또한, 다음과 같이 명령어 라인에서 예제를 실행할 수도 있다.

  1. Java EE 5 SDK를 아직 구하지 못했다면 다운로드 받아서 설치한다. 그리고, SDK의 bin 디렉토리를 각자의 경로에 추가한다.

  2. 예제 패키지를 다운로드하여 압축을 푼다. 새로 압축이 풀린 디렉토리는 <sample_install_dir>/ttaug2006CustomELResolver로 표시되어야 하며, 이 때 <sample_install_dir>이 예제 패키지가 설치된 디렉토리이다. ttaug2006CustomELResolver 아래의 CustomELResolver 디렉토리에는 예제를 위한 소스 파일과 기타 지원 파일이 포함되어 있다.

  3. CustomELResolver 디렉토리로 이동하여 build-cli.xml 파일을 편집한 다음 javaee.home 속성을 적절히 수정한다.

  4. 다음 명령어를 실행한다.
    asant -f build-cli.xml
    dist 디렉토리에 예제 애플리케이션에 대한 exploded와 non-exploded WAR가 만들어진다.

  5. 애플리케이션 서버를 시작한다.
    $JAVAEE_HOME/bin/asadmin start-domain domain1
  6. 예제 애플리케이션을 배포한다. 사용자는 애플리케이션 서버의 관리 콘솔을 이용하거나 CustomELResolver.war 파일을 애플리케이션 서버의 autodeploy 디렉토리에 복사하는 등 다양한 방법으로 이 작업을 수행할 수 있다.

  7. 애플리케이션을 시작하고, 브라우저를 http://<host>:8080/CustomELResolver/로 연다. <host>에는 각자의 호스트 이름을 적어 넣는다(가령, localhost). 애플리케이션의 홈페이지가 표시되어야 한다.



  8. JavaServer Faces Welcome Page 링크를 클릭하면 Unified EL을 통해 세 개의 JNDI 룩업이 포함된 테이블이 표시되는 것을 알 수 있다.

다음은 테이블을 위한 JSP 소스이다.

애플리케이션을 위한 web.xml 파일에서 다음 JNDI 엔트리가 선언된다.

요약

본 테크 팁에서는 6개의 메소드(이 중에서 런타임 동작에 꼭 필요한 것은 단 3개뿐임)로 구성된 간단한 클래스로 Unified EL을 확장하는 방법에 대해 알아보았다. Unified EL 확장 방법에 관한 자세한 내용은 Ed Burns 와 Chris Schalk이 공동 저술한 JavaServer Faces: The Complete Reference를 참조하기 바란다.

저자 소개

Ed Burns는 썬 마이크로시스템즈의 수석 스태프 엔지니어로, 1994년부터 NCSA Mosaic, Mozilla, Sun Java Plugin, Jakarta Tomcat, 그리고 가장 최근에는 JavaServer Faces 기술을 비롯하여 다양한 클라이언트/서버 측 웹 기술을 연구해 왔다. 또한 Ed는 현재 JavaServer Faces 1.2 기술의 공동 스펙 리더이기도 하다.

"Java EE" 카테고리의 다른 글

2006/10/19 11:36 2006/10/19 11:36

TRACKBACK :: http://blog.sdnkorea.com/blog/trackback/157

댓글을 달아 주세요

  1. 서정주  수정/삭제  댓글쓰기

    el에 대한 좋은 팁이네요
    정말 알면 아수록 편하게 쓰고 코드도 깔끔하게 만들수 있네요

    2007/09/05 12:06
  2. 이우철  수정/삭제  댓글쓰기

    막연하던 자바에 대해 더 심층깊게 알 게 된 것 같아요
    알면 알수록 신기하고 재미있는 자바!!
    자바 세계에 풍덩 빠졌어요

    2007/09/07 20:18
  3. 김문경  수정/삭제  댓글쓰기

    열심히 보고 공부해야겠읍니다^^

    2007/09/15 21:51
  4. 박정숙  수정/삭제  댓글쓰기

    좋은 정보 감사해요~

    2007/09/19 04:11
[로그인][오픈아이디란?]

◀ Prev 1  ... 344 345 346 347 348 349 350 351 352  ... 626  Next ▶