Model Facade 사용하기

Java EE 2006/12/22 18:30 Posted by Sun
Model Facade 사용하기

글쓴이: Sean Brydon, Yutaka Yoshida 위의 테크 팁을 비롯한 최근의 여러 테크 팁들을 통해서 Java Persistence API의 다양한 측면을 살펴보았다. 중요한 것은, 사용자가 Java Persistence API를 이용하여 Java EE 5 애플리케이션의 도메인 모델에 포함된 퍼시스턴스를 관리하고 J2EE 플랫폼에서는 제공되지 않았던 추가 기능을 활용할 수 있다는 사실이다.

하지만 Java Persistence를 사용할 때는 고려해야 할 점이 상당 부분 있다.
이를 테면, 서블릿, JSP 페이지, JSF 매니지드 빈과 같은 Java Persistence 클라이언트는
모델 내의 엔티티를 액세스하기 위해 다양한 종류의 API에 액세스해야 할 수도 있다.
(본 팁에서 "클라이언트"라는 용어는 Java Persistence 엔티티 오브젝트 상의 메소드를 호출하는 JSF 매니지드 빈, 서블릿, JSP 페이지 등의 웹 구성요소를 가리킨다.) 이러한 API에는 JTA(Java Transaction API), EntityManager API, 그리고 Java Persistence API가 포함된다. 또한, 클라이언트 코드는 각 엔티티마다 API가 다르고 트랜잭션과 엔티티 매니저 연산에 대한 요구사항이 다른 몇 개의 엔티티와 상호작용해야 할 수도 있는데, 이처럼 다양한 종류의 API에 액세스해야 할 필요성과 트랜잭션 및 엔티티 매니저 연산의 복합성으로 인해
클라이언트 코드가 상당히 복잡해질 우려가 있다.

애플리케이션이 증가함에 따라 사용자는 복수의 엔티티에 액세스하기 위해 동일 코드를 반복해야 할 수도 있고, 또한 여기에는 각 서블릿, 또는 엔티티에 액세스할 필요가 있는 매니지드 빈에 유사한 데이터 액세스 로직을 복사해야 하는 작업이 수반될 수 있다. 이러한 반복 코드는 관리하기 어려울 뿐 아니라 코드를 엔티티 모델에 단단히 결합시키는 역할을 하기도 한다.

Model Facade는 Java Persistence 클라이언트 코드를 간소화시키는 효과적인 방법이라 할 수 있다.

Model Facade란 무엇인가?

Model Facade(또는 "Facade"로 약칭)는 일종의 설계 패턴으로, Java Persistence 클라이언트와 엔티티간의 인터랙션과
Java Persistence API의 연산을 인캡슐레이트(encapsulate)하고 집중화(centralize)하는 상위 레벨의 클래스를 정의한다.
이 패턴은 일련의 엔티티 상에서 수행되는 연산에 대해 단일 인터페이스를 제공하는데,
Facade 패턴을 사용하면 Java Persistence 클라이언트의 코드를 훨씬 간결하게 만들 수 있다.
Facade를 이용하여 모델 티어에 액세스하는 웹 컴포넌트의 경우, 각 엔티티에 대한 API의 세부사항을 모두 알아야 할 필요가 없으며, 또한 엔티티 매니저나 트랜잭션 매니저 액세스 시 사용중인 퍼시스턴스 메커니즘에 대해서도 알 필요가 없다. 뿐만 아니라, 호출 클라이언트와 모델 티어의 엔티티간에 Facade를 추가하면 코드가 더 느슨하게 결합되어 관리하기가 용이해진다.

Facade의 용도는 Java Persistence에만 국한되지 않으며 JDBC와 같은 다른 퍼시스턴스 기술에도 유용하게 사용할 수 있다.

Facade 설계 및 코딩하기

Facade를 이용할 때 코드가 얼마나 간결해지는지 알아보기 위해 'Before'와 'After' 예제를 살펴보기로 하자.
"Before" 예제는 모델 티어의 엔티티를 액세스하는 서블릿을 위한 코드를 보여주고,
"After" 예제는 Facade를 사용한 서블릿 코드를 보여준다.

다음은 "Before" 코드이다.


public class MyWebClient ... {

...
public void doGet(HttpServletRequest request,
HttpServletResponse response)
{
...
//processing a web request to
//add a new Item to the database
if (selectedURL.equals("additem.do")) {
String desc = request.getParameter("item_desc");
String name = request.getParameter("item_name");
...
Item item = new Item();
item.setName(name);
item.setDescription(desc);
//now access entities in model tier
EntityManager em =
emf.createEntityManager();
try{
utx.begin();
em.joinTransaction();
em.persist(item);
utx.commit();
} catch(Exception exe){
System.out.println("Error persisting item: "+exe);
try {
utx.rollback();
} catch (Exception e) {}
} finally {
em.close();
}
}
...

다음은 "After" 코드이다.

public class MyWebClient { ...
...
public void doGet(HttpServletRequest request,
HttpServletResponse response)
{
...
//processing a web request to
//add a new Item to the database
if (selectedURL.equals("additem.do")) {
String desc = request.getParameter("item_desc");
String name = request.getParameter("item_name");
...
Item item = new Item();
item.setName(name);
item.setDescription(desc);
//now access entities in model tier
MyModelFacade myfacade = new MyModelFacade();
myfacade.addItem(item);
}
Facade 구현을 위한 우리의 전략은 웹 컴포넌트를 facade 클래스로 사용하는 것이다.
이 전략은 사용자가 웹 전용 아키텍처를 원하고 EJB 컨테이너의 사용을 원치 않을 경우에,
그리고 Facade를 웹 컨테이너에 유지하고자 할 때에 유용하다. 사용자의 애플리케이션이 웹 전용 아키텍처를 사용하고
웹 컴포넌트가 엔티티를 액세스할 경우, Facade를 이용하면 코드를 간결하게 만들 수 있다.
본 팁에서는 EJB 티어를 사용하지 않는 웹 전용 애플리케이션, 즉 EJB 컨테이너나 서비스를 사용하지 않는
Java EE 애플리케이션을 위한 Facade 구현에 특히 초점을 맞추고 있다는 점에 유의할 것.

웹 전용 애플리케이션을 위한 예제 Facade

Facade를 위한 코드를 살펴보기로 하자. Facade를 위한 소스 코드와 본 팁의 다른 예제 코드는 본 팁에 첨부된 예제 애플리케이션 패키지에 수록되어 있다.

public class CatalogFacade implements ServletContextListener {
@PersistenceUnit(unitName="CatalogPu")
private EntityManagerFactory emf;
@Resource UserTransaction utx;

public CatalogFacade(){}

public void contextDestroyed(ServletContextEvent sce) {
if (emf != null && emf.isOpen()) {
emf.close();
}
}
public void contextInitialized(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
context.setAttribute("CatalogFacade", this);
}
public void addItem(Item item) throws InvalidItemException {
EntityManager em = emf.createEntityManager();
if(item.getName().length() == 0)
throw new InvalidItemException("The item" +
" name cannot be empty. Please specify a name for the item. ");
try {
utx.begin();
em.joinTransaction();
em.persist(item);
utx.commit();
} catch(Exception exe){
System.err.println(exe);
try {
utx.rollback();
} catch (Exception e){
e.initCause(exe);
throw new RuntimeException(e);
}
throw new RuntimeException(exe);
} finally {
if (em != null) {
em.close();
}
}
}

public Item getItem(int itemID){
EntityManager em = emf.createEntityManager();
Item item = em.find(Item.class,itemID);
em.close();
return item;
}


public List<Item> getAllItems(){
EntityManager em = emf.createEntityManager();
List<Item> items = em.createQuery()
"SELECT OBJECT(i) FROM Item i").getResultList();
em.close();
return items;
}
}
CatalogFacade 예제에는 몇 가지 주목할 만한 설계 옵션이 있다.

* Facade는 ServletContextListener 인터페이스를 구현하는데, 이 경우 Java Persistence 엔티티와 Java EE 플랫폼의 관련 서비스 액세스에 유용한 주석을 사용할 수 있게 된다. Facade가 주석과 의존성 주입(dependency injection)을 사용하기를 원할 경우에는 Facade가 반드시 웹 컴포넌트여야 한다. 한편, POJO(Plain-Old Java Objects)는 Java EE 5 의존성 주입을 사용할 수 없다.

* Facade는 호출 클라이언트를 퍼시스턴스 관련 예외에 노출시키지 않는다. 예제 Facade는 Java Persistence와 Java Transaction API로부터 예외를 catch하고 그 대신 런타임 예외를 throw한다.

* Facade는 모든 트랜잭션 코드와 엔티티 매니저 인터랙션을 처리한다.

* Facade는 여분의 인터페이스를(Facade 자체 인터페이스 외에) 추가하지 않는다.
여분의 인터페이스는 코드를 엔티티와 모델 티어로부터 더 느슨하게 결합되도록 할 수 있지만, 이 경우 여분의 클래스가 필요하다. 하지만 사용자는 좀더 복잡한 상황에서 여분의 인터페이스 추가를 고려할 수도 있다.

* Facade는 클라이언트 코드가 POJO로 사용할 Java Persistence 오브젝트를 리턴하며, 데이터 전송 오브젝트나
Java Persistence 엔티티의 사본인 값 오브젝트는 리턴하지 않는다. Java Persistence 엔티티는 엔티티 매니저에 의해 관리되며 모델 오브젝트로 사용될 수 있다. 또한 엔티티는 POJO로도 사용될 수 있다.
Facade는 분리 방식(detached mode)으로 Java Persistence 엔티티를 리턴하는데, 코드를 엔티티와 모델 티어로부터 더 느슨하게 결합시키고 싶은 경우에는 클라이언트에 맞는 오브젝트를 추가하고 엔티티 오브젝트 대신 이들을 리턴하면 된다.

* Facade는 thread-safe하며, 안전하게 캐시될 수 있는 오브젝트만을 저장한다. stateful 오브젝트는 캐시하지 않는다.
Facade는 EntityManagerFactory 및 UserTransaction 오브젝트만을 보관하는데, 이 둘은 모두 thread-safe하며 후속 요청을 위해 보관 및 캐시될 수 있다. 따라서 이 경우, Fasade의 캐시 및 공유가 가능해진다.
웹 컴포넌트가 EntityManager를 보관하는 것은 thread-safe하지 않으므로 이는 삼가해야 한다는 점에 유의할 것.

addItem 메소드에서 엔티티에 액세스하려면 트랜잭션 구분(demarcation)을 위한 JTA API가 필요하다는 점 또한 유의할 것.
아울러, 데이터베이스에 새로운 Item을 저장하려면 EntityManager API가 필요하다.
이 코드를 Facade 클래스의 특정 장소에 위치시키는 것이 오히려 엔티티에 액세스할 필요가 있을 때마다
애플리케이션에서 코드를 반복하는 것보다 더 효과적이다.

Facade 사용하기

이제 서블릿과 같은 웹 컴포넌트가 예제 Facade를 어떻게 사용하는지 살펴보기로 하자.

public class CatalogServlet extends HttpServlet {
private CatalogFacade cf;
private ServletContext context;
private Map nameSpace;

public void init(ServletConfig config)
throws ServletException {

context = config.getServletContext();
cf = (CatalogFacade)context.getAttribute("CatalogFacade");
initPathMapping();
}

...

public void doGet(HttpServletRequest request,

HttpServletResponse response)
throws ServletException, IOException {
...
try {
if (selectedURL.equals("additem.do")) {
//get values from request and set in a
//new Item to then add to database
String desc = request.getParameter("item_desc");
String name = request.getParameter("item_name");
...
Item item = new Item();
item.setName(name);
item.setDescription(desc);
...
cf.addItem(item); //now call Facade
...
}
}

서블릿은 init 메소드를 이용하여 Facade를 획득한 다음 Facade를 서블릿 내의 필드로 저장하여 다른 클라이언트 요청이 사용하고 공유할 수 있도록 한다.

private CatalogFacade cf;

Facade를 사용함으로써 서블릿은 엔티티의 세부사항과 엔티티에 액세스하는 데 필요한 퍼시스턴스 연산으로부터 보호된다.

예제 코드 실행하기

본 팁에는 Model Facade가 포함된 예제 패키지가 첨부되어 있다. 예제를 설치하고 실행하려면 다음의 작업 절차를 따르도록 한다.

1. Java EE 5 SDK를 아직 구하지 못했다면 Java EE 다운로드 페이지에서 다운로드 받아 설치한다.
http://java.sun.com/javaee/downloads/index.jsp
아울러 Java SE(Java Platform Standard Edition) 5 SDK가 설치되어 있는지도 확인한다.

2. 본 팁의 예제 패키지를 다운로드하여 압축을 푼다.
http://java.sun.com/mailers/techtips/en ··· cade.zip
이 때, 새로 압축이 풀린 디렉토리가 <sample_install_dir>/ttnov2006facade로 표시되어야 하는데,
여기서 <sample_install_dir>은 예제 패키지가 설치된 디렉토리를 나타낸다.
예를 들어, Windows의 C:\에 압축을 해제했다면 새로 생성된 디렉토리는 C:\ttnov2006facade가 되어야 한다.
ttnov2006facade 아래의 TechTip-Facade 디렉토리에는 예제를 위한 소스 파일과 기타 지원 파일이 포함되어 있다.

3. TechTip-Facade 디렉토리의 build.properties 파일을 편집하고 각자의 환경에 맞게 속성을 설정한다.
예를 들어, javaee.home이 각자의 Java EE 5 설치 디렉토리를 표시하도록 설정한다.

4. 다음 명령어를 입력하여 Derby 데이터베이스를 시작한다.

$JAVAEE_HOME/bin/asadmin start-database

5. 다음 명령어를 입력하여 애플리케이션 서버를 시작한다.

$JAVAEE_HOME/bin/asadmin start-domain domain1

6. TechTip-Facade 디렉토리로 이동하여 다음 명령어를 입력한다.

ant setup

이렇게 하면 데이터베이스 리소스가 설정된다.

7. 다음 명령어를 입력한다. ant run

이렇게 하면 예제 애플리케이션이 구축, 배치, 론치된다.
여기서, 애플리케이션은 Java BluePrints 솔루션 카탈로그에서 뽑아온 Java Persistence 예제 애플리케이션이다.

http://java.sun.com/mailers/techtips/en ··· age1.gif

카탈로그에서 항목을 검색하거나 추가하려면 표시된 페이지의 링크를 클릭한다.
애플리케이션 소스를 살펴보면 카탈로그에 포함된 퍼시스턴스 엔티티 상의 연산을 위한 인터페이스로
Model Facade가 사용되고 있음을 알 수 있다.

요약

Java Persistence API를 사용하는 Java EE 5 웹 애플리케이션을 구축하고 있다면 Model Facade를 도입하여 코드를 리팩토링해볼 것을 권한다.

Facade와 Java Persistence API에 관한 자세한 내용은 다음 사이트를 참조하기 바란다:

Java Petstore 2.0 Reference Application, Early Access
https://blueprints.dev.java.net/petstore/index.html

Java Persistence APIs
https://blueprints.dev.java.net/bpcatalog/ee5/persistence/

GlassFish Project - Java Persistence API 구현 홈페이지
https://glassfish.dev.java.net/javaee5/persistence/

Java BluePrints에 관한 피드백, 토론, 질문
https://blueprints.dev.java.net/feedback.html

-샘플 아카이브 다운로드 받기-

Model Facade 사용하기
http://java.sun.com/mailers/techtips/en ··· cade.zip


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

2006/12/22 18:30 2006/12/22 18:30

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

댓글을 달아 주세요

  1. 고진구  수정/삭제  댓글쓰기

    자바는 알면 알수록 재미가 있어지네요. 좋은 자료 잘 활용하겠습니다.

    2007/09/13 22:42
  2. 김문경  수정/삭제  댓글쓰기

    좋은 글 감사합니다^^

    2007/09/17 21:59
  3. 박정숙  수정/삭제  댓글쓰기

    좋은 정보 감사해요~

    2007/09/19 04:04
  4. 김복선  수정/삭제  댓글쓰기

    좋은 정보 얻고 가요~

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

◀ Prev 1  ... 323 324 325 326 327 328 329 330 331  ... 626  Next ▶