중 아래 댓글들 참고

********************************************************************

이부분은 책의 내용을 그대로 발췌


ejb2.0로컬 참조와 cmr(container managed ralation)이 나타나기 전에, 엔티티 빈들은
큰단위의 도메인 객체들을 모델화 하기 위해 주로 사용되었다.

이것은 주로 원격 통신과 관련된 오버헤드 때문에, 클라이언트 티어의 객체가 엔터프라이
즈 티어에 작은 단위로 접근하는 것을 막기 위해서였다. 큰단위(coarse grained)로 된 설계의 
성능은 클라이언트 티어와 엔터프라이즈 티어 사이에 전송되는 모든 데이터를 캡슐화한
data transer object의 구현으로 한층 더 개선되었다. 비록 이것이 높은 퍼포먼스의 설계를
제공해주기는 했지만, 많은 도메인 객체를 가진 복잡한 시스템에서는 시스템 내에
dto의 과잉을 초래하였다.

또한, 이전의 ejb에서는 빈 공급자가 도메인 객체들 사이의 연관을 유지하기 위한 로직을 명시
적으로 제공해야 했다. 도메인 객체들 사이에 복잡한 관계가 있는 상황 안에서는 dto의 설계가
매우 복잡하게 되었다.

로컬 참조와 cmr의 출현은 ejb를 이용한 엔터프라지으 app 개발에 흥미진진한 새로운 길을 열었다.
여기에서 우리는 프리젠테이션 티어와 엔터프라이즈 티어 사이에서 전송될 수 있는 XML 기반의
동적인 데이터 구조를 생성하기 위한.. JAXP와 빈 인트로스펙션(refelct활용한거)을 연계하여
ejb2.0을 사용하는 강력한 길을 얻을 수 있을 것이다.

엔터프라이즈 티어에서 클라이언트 티어로 데이터를 전송하기 위한 XML의 사용은 app내에 들어
있는 다양한 티어들 사이의 느슨한 결합 구조를 가진 구현을 도와준다. 

하지만, 새로운 도메인 객체들을 엔티티 모델에 추가하려고 할때는 , 이것들을 위한 새로운 DOM
구조(예전에 한번 살펴봄..dom,sax등)를 생성할 책임이 있는 클래스를 추가할 필요가 있다.

우리는 주어진 로컬 ejb의 cmp와 cmr 필드들을 동적으로 네비게이션 할 수 있는 프레임워크를 개발
하고 ,app 내의 다양한 티어들 사이에서 전송될 수 있는 xml문서를 생성할 것이다. 이러한 방법에는
다음과 같은 이점들이 있다.

1.엔터프라이즈와 클라이언트 티어 사이에 결합을 느슨하게 한다.(스크립팅 형식이니..)
2.도메인 객체들 사이의 관계들을 관리하기가 훨씬 더 쉽다.(굿!)
3.시스템에서 복잡한 데이터 전송 객체들을 제거한다. (굿!)
4.xml이 cmp 그리고 cmr 필드들을 동적으로 네비게이션 할 수 있게 만들어졌기 때문에, 빈공급자는
새로운 객체들을 도메인 모델에 추가하려고 할대, 이들의 새로운 dom 구조를 생성할 책임이 있는
클래스를 만들 필요가 없다.

ejb2.0로컬 참조는 빈 컴포넌트들의 작은 단위 접근을 권장한다. 로컬참조를 가진 빈들은 컨테이너에
의해 관리되는 다른 빈들과의 관계에 포함될 수 있다. 예를 들면, 헬프 데스크 시스템에서, UserEJB는
ServiceRequestEJB와 일대 다의 양방향 관계를 가질수 있고, ServiceRequestEJB는 ProductEJB와
일대일의 단방향 관계를 가지고, ServiceRequestHistoryEJB와 일대 다의 양방향 관계를 가질수 있다.

UserEJB는 또한 PhoneEJB와 일대 다의 양방향 관계를 가질수 있다. 그래서 EJB 2.0 로컬 참조와
cMR을 사용하여, 연관된 엔티티들의 복잡한 집합을 설계할수 있다. cmp와 cmr 필드들은 빈클래스
안에서 추상 접근자 메소드(getter/setter)를 사용하여 정의 된다.

cmr필드들을 위한 접근자 메소드들은 관계의 기수성에 의존하여 일의 관계이면.. 빈의 로컬 인터페이스를
, 다의 관계이면 빈의 로컬 인터페이스의 컬렉션을 돌려보낸다. 이들 접근자 메소소들은 빈 컴포넌트들의 로컬 
인터페이스를 통해서 외부에 드러날 수 있다. ejb2.0의 더 깊은 범위는 이 책의 영역에서 벗어난다. 보다 상세한 
ejb2.0규약에서 제공한다. -_-;;;

효과적인 디자인 패턴은 facade 컴포넌트를 통해서 app의 큰 단위 유스케이스를 드러내며, 클라이언트 
티어로부터 엔티티 컴포넌트로의 직접적인 접근을 막는다.

이것은 비지니스 서비스를 제공하기 위해 로컬 엔티티 빈들이 협력하는 복잡한 계층 구조와
상호작용하는 리모트 세션빈 컴포넌트와 같은 facade 유스케이스의 구현에 의해 성취될 수 있다.

앞에서 언급된 헬프데스크 예제로 돌아가서 , 주어진 user의 자세한 정보를 얻기위한 하나의 유스케이스가
있다. facade 컴포넌트는 요청된 user엔티티 컴포넌트를 찾고, cmp와 cmr 필드들을 통하여 검색을 하여
필요한 데이터를 얻고, 이를 프리젠테이션 티어로 리턴한다.

데이터 전송 객체를 위한 확실한 서택은 일반 자바 빈이다. UserBean은 cmp와 cmr필드를 나타내는
특성들을 가질 수 있다. cmr 필드의 타입은 관계의 기수성에 따라 java.util.Collection 이거나, 다른 빈 컴포
넌트일수 있다. UserBean은 ServiceRequestBean과 PhoneBean 컬렉션을 가질 수 있다. 

ServiceRequestBean은 한개의 ProdctBean과 ServiceRequestHistoryBean의 컬렉션을 가질수 있다.
추가적으로 이들 빈들은 도한 cmp필드들을 표현하는 원시 타입의 어트리뷰트나 간단한 string을 가질수
있다.

이러한 선택의 중요한 단점은 엔티티 모델이 복잡해질수록 데이터 전송객체의 계층구조가 더 복잡해지는
것으로, 이것은 서비스(엔터프라이즈) 티어와 소비자(프리젠테이션)티어 사이의 결합을 단단하게 할 수 
있다는 점이다. 

관계들의 복잡한 계층 구조를 보면, 더 나은 선택은 데이터 전송 객체로서 XML,DOM 객체를 사용하는 것이다.
(세션빈에서 직접 jdbc에 연동해서 데이터를 가져올때 java.sql.resultset -> java.sql.rowset 사용하기도 함)

facade컴포넌트는 org.w3c.dom.Document 타입의 객체를 생산하고 프리젠테이션 컴포넌트는 xml을 인지하는
jsp커스텀 태크나(오옷!!) xslt(이게 xml변환하는 라이브러리였던가? 예전에 정리했었는데;;) 파일을 사용하여
그것들을 소비할 것이다.

다음과 같은 질문이 있다. cmp 로컬빈의 참조로부터 xml문서를 어떻게 생성할 수 있는가? 

우리는 dom컴포넌트의 서로 다른 타입을 생성하기 위해 팩토리(factory) 기반의 접근을 사용할 수 있다.
하지만, 이것은 팩토리 컴포넌트의 과잉을 생성하여.. 엔티티 모델을 확장할 때 새로운 팩토리 컴포넌트의
추가가 필요할 것이다. (아..하긴..) 

우리가 필요한 것은 cmr을 찾아서 동적으로 dom구조를 생성하기 위해 cmr엔티티 로컬 객체들을 인트로스펙트
(리플렉션)할수 있는 기능을 가진 유틸리티이다.

이 유틸리티는 무한 순환을 피하기 위해 양방향 관계에서 원형 참조를 조심해야하고, 또한 관계 엘리먼트
(realation ship element)들의 검색에서 환경설정이 가능한 drill-down depth (????)를 가져야 한다.

다음 섹션에서 이러한 기능을 제공하는 유틸리티 클래스를 보여준다.

package ws.business.service.util;
//jaxp
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
//dom
import org.w3c.com.Document; //오오.. 기억이 새록새록 내경운 jdom2를 썼었지..
import org.w3c.dom.Element;
//ejb
import javax.ejb.EJBLocalObject; //이거..자바ee6 받아서 설치후.. 외부 라이브러리에서 찾아야함;;
//collection
import java.util.Collection;
import java.util.ArrayList;
import java.util.Iterator;
//빈 introspection
import java.beans.Introspetor; //오.. 이런 api들이 제공되었었군.. 나는 직접 reflect 쓰는줄..
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor; 
import java.beans.IntrospectionException;
//reflection 에잉.. 추가해주네..
import java.lang.reflect.Method; //예전 생각한대로.. 조회해가며 게터,세터 찾으려는건가? 찾아서 invoke하고
import java.lang.reflect.InvocationTargetException;

public class DOMGenerator
{
  //문서 만든다.
  private Document doc;
  //사용자가 drill-down depth를 정의한다.. .. 이거 element의 계층 구조 의미하는 거였나? xml이 데이터를 트리처럼 관리하니
  private int drillDownDepth;
  //특정 참조를 저장하기 위한 사적 인스턴스 변수
  private ArrayList _circularRef = new ArrayList();
  //현재의 depth of the drilldown으로 저장하기 위한 사적 인스턴스 변수
  private int _currentDepth;
  //getEJBLocalHome, getLocalHandle, getClass and getPrimaryKey 메소드들은 
  //처리하지 말아야 한다. why???
  private static String RESERVED = "EJBLocalHome^localHandle^class^primaryKey";
  //대박이다.. 예약어를 xor로 묶었어.. 헐.. 대박.. 천재다..

  public DOMGenerator(String docElementName, int drillDownDepth)
  {
     try
     {
        DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = fact.newDocumentBuilder(); //익숙해서 좋고~
        doc = builder.newDocument(); //이제 나도 팩토리 패턴에 익숙해진건가?
     }
     catch(ParserConfigurationException ex)
     {
        throw new RuntimeChainedException(ex); //오.. 체크드를 언체크드로 변환후 그래도 콜러에게 알리네? 워커가 착함;;
     }
     //drilldown depth를 저장
     this.drillDownDepth = drillDownDepth;
     //사용ㅈ가 정의한 이름을 사용하여 문서 요소를 만든다.
     doc.appendChild(doc.createElement(docElementName)); //아.. 어렴풋이 기억이 난다.
   }


   //이 메소드는 dom을 만들기 위해 로컬 참조를 넘긴다.
   public Document getDOM(EJBLocalObject local)
   {
      try
      {
         //cmp와 넘겨진 로컬 참조를 위한 관계 필드를 사용하여 요소를 만들기 위해 이메소드를 호출한다.
         populateElement(doc.getDocumentElement(), local); //먼가 심오한데?.. local 인스턴스를 통해 reflection으로 
         //클래스 정보에서 각종 메서드,관계들 파헤쳐서 doc에 넣어주는듯..
         //dom을 리턴
         return doc;
       }
      catch(IntrospectionException ex)
      {
         throw new RuntimeException(ex.getMessage()); //오 이런게 일반적 기법이구나~
      }
      catch(IllegalAccessException ex) //흠..리플렉션 패키지로 접근제한자 다 뚤을수 있는데?
      {
         throw new RuntimeException(ex.getMessage()); 
      } 
      catch(InvocationTargetException ex)
      {
         throw new RuntimeException(ex.getMessage()); 
      } 
   }


   //
   private void populateElement(Element parent, EJBLocalObject local) throws IntrospectionException,
   IllegalAccessException, InvocationTargetException
   {
      //현재 로컬 참조를 링크된 참조 목록에 추가한다.
      _circullarRef.add(local); //참조를 기억해둠
      //현재의 drilldown depth를 증가시킨다.
      _currentDepth++;
      //현재 로컬 참조에 대한 빈 정보를 얻는다.
      BeanInfo info = Introspector.getBeanInfo(local.getClass()); //오`~ 이해되고 있음..리플렉션 사용해 각종정보추출
      //속성 descrptors의 목록을 얻고 배열에서 반복시킨다.
      PropertyDescriptor[] properties = info.getPropertyDescriptors(); //굿굿!
      
      for(int i=0; i< properties.length; i++)
     {
         //속성 읽기 메소드를 얻는다. 프로퍼티 디스크립터라는 자료형이 편하긴 한듯.. 
         Method propReadMethod = properties[i].getReadMethod(); //메소드 순회하면서 어트리뷰트.. properties[i] 이름
         //과 일치하는 게터 메서드를 클래스에 선언된 메서드들을 탐색해서 찾고..실행(invoke)해서 값을 얻는듯.
         //속성 이름을 얻는다.
         String propName = properties[i].getName();
         //reflection을 사용하여 속성 값을 얻는다.
         Object prop = propReadMethod.invoke(local, null); 
         //예전되어 있던 속성을 건너뛴다.
         if(RESERVED.indexOf(propName) > = 0) continue; // 천재다..

         try
         {
            //ejb 로컬 참조로 속성을 캐스트 한다. 구현 방법이 아주 다양하기에 instanceof를 사용하지 말자!
            EJBLocalObject locProp = (EJBLocalObject)prop;
           //만일 링크 참조목록에서 로컬 참조를 이미 이용하고 있거나,
           //현재의 drilldown depth가 설정된 driildown depth보다 더 크다면.. 건너뛴다. = 트리 순회 로직
           if(isCircularRef(locProp) || _currentDepth >= drillDownDepth) continue;
           
           //속성으로 요소를 만든다.
           Element child = doc.createElement(propName);
           //자식 로컬 참조의 관계 필드와 연속 필드로 새로 만들어진 요소를 반복해서 만든다.(핵심= 재귀)
           populateElement(child, locProp); //내가 파일 시스템 트리 탐색할때 재귀 시도한거처럼..
         }
         catch(ClassCastException ex1)
         {
             //ClassCastException이 throw되었으면.. 핸들링! 내가 전에 깨달은 익셉션 핸들링
             //속성을 로컬 참조의 컬렉션으로 캐스팅하도록 한다.
             //이때 구현방법이 컨테ㅣ너마다 다른 instanceof는 사용하지 않도록 한다.
             try
             {
                 Collection colProp = (Collection)prop;
                 //현재의 drilldown depth가 설정된 driildown depth보다 크다면 처리과정을 건너띈다. =트리순회에서 제한조건
                 if( _currentDepth >= drillDownDepth) continue;

                 //컬렉션을 캡슐화할 자식 요소를 만든다.
                Element child = doc.createElement(propName);
                Iterator it = colProp.iterator(); 
                //당근 현재 catch된 블럭은 컨테이너 타입(트리에서 마지막 노드x)이니까.. 내부 요소를 접근해야지..
                while(it.hasNext())
                {
                    //컬렉션에서 각각의 로컬 참조를 얻는다.
                    EJBLocalObject locProp = (EJBLocalObject)it.next();
                    //만일 링크 참조 목록에서 로컬 참조를 이미 이용하고 있거나, 현재의 drilldown depth가
                    //설정된 drilldown depth보다 크다면 처리 과정을 건너뛴다. = 위에도 나왓지만 중복처리 방지이자 무한루프
                    //방지
                    if( isCircullarRef(locProp)) continue;
                     
                    //컬렉션에 현재 로컬 참조를 위한 지속 정보와 관계 정보를 포함할 요소를 만들고, 
                    //그것을 컬렉션을 나타내는 요소에 추가하ㅕ 컬렉션을 만든다.
                    Element grandChild = doc.createElement(propName + "-child");
                    child.appendChild(grandChild); //예전에 사용자 정의 익셉션을 스택및 재귀호출을 이용해 처리한 어떤
                    //분의 코드에선.. 트리의 깊이 * '\t' 함으로서 층을 표현햇지만.. dom구조의 xml은 계층구조가 알아서
                    //잘 표시되니.. 그런 구현까진 신경안써도 될듯
                    populateElement(grandChild, locProp); //손주 노드 탐색 ㄱㄱ (진짜 내가 예전에 파일 시스템에서 트리
                    //순회하려던 것과 유사하다...내 삽질도 의미가 있었다 ㅠㅠ)
                 }
                 //위의 while을 통과했다면.. 현재 노드의 하위 계층을 전부 추가했을테니..(재귀를 통해)
                 //자식들을 만든다.
                 parent.appendChild(child);
              }
              catch(ClassCastException ex2)
              {
                 //ClassCastException이 발생했다면.. 속성은 연속필드이고.. 
                 //그값이 애트리뷰트로 연재 노드에 추가된다. 헐.. 진짜 내가 구상했던 트리식 파일 시스템 처리와 거의 똑같네..
                 //isDirectory따라 재귀 순회하고.. isFile이라면.. 현재 노드의 데이터 필드에 추가하고;; 내가 대박친건가.. 아님
                 //사람들 생각이 다 비슷한건가;;
                 parent.setAttribute(propName, prop.toString() );
              }
          }
      }

      //순환 참조를 추적하기 위해 목록에서 현재의 로컬 참조를 삭제한다. <- 이해불가..내가 전에 이걸 몰라서 실패했나?
      _circularRef.remove(local); //하여간 심플한..순회 종료조건들이다.
      //현재의 drilldown depth를 감소시킨다. 
      _currentDrpth--;
   }

   //이것은 참조가 링크된 참조 목록에 있는지 여부를 검사하기 위한 유틸리티 메소드이다.
   private boolean isCircularRef(EJBLocalObject local)
   {
      Iterator it = _circularRef.iterator(); //전체 로직을 완벽히 이해는 못했지만.. 대박..
      while(it.hasNext())
      {
         if(local.isIdentical( (EJBLocalObject)it.next() ) ) return true;
         
         return false;
       }
   }
}

아래의 코드는 이 클래스를 사용하기 위한 방법을 보여준다.
User local = userHome.findByPrimaryKey("1");
return new DOMGenerator("user", 4).getDOM(local); //아름답다...

엔티티 모델에 의존하여 생성된 dom이 아래에 나와있다.


<?xml version="1.0" encoding="UTF-8" ?>
  <user firstName="Meeraj" id="1" lastName="Kunnu">
   <requests>
      <requests-child description="Outlook not working" id="2" status="p">
          <product description="Install Laptop" id="1" name="SVC01"/>
       </requests-child>
       <requests-child description="PC not booting" id="1" status="O".
           <histories>
              <histories-child description="Information requested" id="2" loggedAt="2000-12-12 12:!2:12.0" />
              <histories-child description="Request logged" id="1" loggedAt="2000-12-12 00:00:00.0" />
            </histories>
            <product description="Install Laptop" id="1" name="SVC01" />
         </requests-child>
     </requests>
     <phones>
         <phones-child id="2" number="0771 8210586" type="M" />
         <phones-child id="1" number="0231 2973536" type="W" />   
     </phones>
   </user>
                


우리는 j2ee app의 엔터프라이즈와 프리젠테이션 티어 사이에서 복잡한 데이터를 전송하기
위한 멋지고 유연한 모델을 보았다. 프리젠테이션 티어는 엔터프라이즈 티어에 의해 생성된
xml데이터를 xml을 인지하는 jsp 커스컴 태그와 xslt를 사용하여 클라이언트 디바이스(이를테면
file)상에 표현할 수 있다.

도메인 모델에 새로운 정의를 추가할때, 당신이 해야할 필요가 있는 유일한 일은 .. 작은 단위 로컬
엔티티 빈들을 사용하기 위한 그런 정의들을 정의하는 것과 cmr을 사용하기 위한 연관을 정의하는 것이다.

dom생성기(generator)는 동적인 xml문서들을 생성하기 위하여 그런 관계들을 검색하는 일반적인
방법을 제공한다.

하지만, 임의의 다른 설계 솔루션처럼... 이러한 접근은 또한 약점과 결정들을 가지고 있다. 

첫번째 명백한 측면은 xml기반의 data transfer object에 대해 개발자들이 자주 걱정하는 퍼포먼스
이다. app서버 (wls 6.1)와 데이터 서버(adaprive sql anywhere)가 동시에 돌아가는 1ghz,256mb의
windows mf 컴퓨터 상에서 복잡한 관계들을 가진 천개의 레코드 집합을 처리하는데 0.5초 이하 정도의
시간이 걸렸다.

두번째 명백한 측면은 타입 안정성이다. xml이 가장 높은 레벨의 데이터 추상화를 제공하기 때문에 
어트리뷰트나 텍스트노드들의 값은 항상 string 문자처럼 다루어진다. 

만약 당신이 엔터프라이즈 티어로부터 조회된 dto상에서 비지니스 연산을 수행하고자 한다면,
자바빈  컴포넌트(일반 자바클래스)를 사용하는 dto패턴을 채택하는 것이 더 좋다.

하지만, xml스키마는 xml문서상의 타입 안정성을 위한 강력한 메커니즘을 제공한다. 또한 이문서에서
설명된 접근 방법에서, 엔티티와 그것의 종속적인 엔티티에 연관된 대부분의 비지니스 로직은
엔티티 그 자체 내에 구현될 것이고, 독립적인 엔티티들과 연관된 비지니스 로직은
session facade에서 구현될 것이다. 두 경우 모두 모데인 객체로서 로컬 엔티티의 객체를 사용한다.

이러한 접근방법의 가장 큰 단점중 하나는 xml기반의 데이터 모델링을 위해 잘 정의된 기술이 없다
는 것이다. xml을 사용하여 도메인 객체의 관계를 모델링하기 위한 어떤 uml표기법이나 대중적인
스테레오 타입을 찾아내지 못했다.


'프로그래밍 > ejb' 카테고리의 다른 글

해쉬맵의 활용 전략(map dto, dto factory)  (0) 2014.01.02
ejb관련 - EJB.. 그만 공부하자..  (0) 2014.01.02
by givingsheart 2014. 1. 2. 09:37
정확치 않은 이해를 스케치 하는것임을 주의!

목적:

서버,클라간 요청/응답 횟수를 줄이고, do들과 dto들 사이의 의존성 줄임

전제:
클라의 ui에 표시되는 데이터들은 서버측 데이터를 이용해 초기화된다.

서버측에 여러 do들의 모임..(게임이라면.. 캐릭터정보do, 맵정보do, 아이템정보do, 몬스터정보do등등)
을 관리하는 객체가 있다면 (facade 세션빈.. 메디에이터)

요놈에 대해 정보를 요청할때.. 전체 정보를 요청할 것인가? 아니면 개별 do정보를 요청할 것인가?
개별 do중 각각의 어트리뷰트를 요청할 것인가에 대해..


컨셉:
1.클라측에서 해당 유스케이스A에 해당하는 dto를 요청(캐릭정보중 a,b 맵정보중 a,b 몬스터정보중 a,b)

2.서버에선 유스케이스별로 dto를 해쉬맵에 구성해둔후 맵을 통채로 클라에 전달

물론 이작업 역시.. 팩토리 클래스가 담당
글고 여기서 제네릭 엑세스 패턴이 활용.. 컨셉은 전체 집합에서 찾아낼 집할을 의미하는 키값의 집합을 매개
변수로 get메서드를 호출하면.. 내부에서 전체 조회를 통해 일치하는 키에 해당하는 집합을 새로이 해쉬
맵으로 구성해 리턴하는 전략.. 컨테이너의 생성자등 메서드의 매개변수로 다른 컨테이너를 받는 의미가
이러한 의미임!

아참.. 타입을 제너릭하게 사용시..Object 타입들이 왔다 갔다 하니..  형변환이란 노가다 작업이 필요해지긴하
다.. 큰 목적을 이루기 위해 이정도 수고쯤음 -_-a

제네릭 엑세스 인터페이스 형태

public interface AttributeAccess
{
  public Map getAttributes(Collection attributeKeys);
  public Map getAllArrtibutes();
  public void setAttributes(Map attributes); //셋과 비교해 맵의 장점 = 덮어쓰기 가능!(예전에 맵의 put을 잘못 이해했었지..)
}

글고.. dto에 맵적용 패턴활용시 타입점검의 기능이 약해짐.. 단순하게 구성하면.. key도 object형이기 
때문에.. 해당 맵엔 모든 타입(do)들이 들어갈수 있음.. 이걸 방지하려고.. 상위 타입을 만들고 key값에
<? extends BaseA>가 가능하긴 하지만.. 이렇게 되면.. 너무 복잡해질듯.. 직접 구현할 레벨이 안되기 
땜에.. 막연한 느낌이랄까..?

컨테이너들이 직렬화를 구현한 이유는 원격 송수신 이란.. 기본 전제가 있기 때문임.. 스윙의 컴포넌트
들.. 역시.. bean 형태로서 직렬화및, 각종 셋/겟지원.. + key/value로서 내부에 해쉬셋을 가지고 있다는
점.. (프로퍼티란 데이터 타입은 해쉬셋의 일종으로 키와 값을 문자열로 다룬다는 점만 특이점임.. 문자열
타입의 집합은 xml과 연동이 쉽고..)
추가로 키값을 개발자가 알지 못할 경우를 위해 해당 컨테이너(빈클래스,스윙컴포넌트) 클래스에선
static final String XXXX = "xxaasasa"; 처럼 키값을 지원함..  예전에 워드 + 포맷 객체 프로젝트 진행시
포맷 객체를 외부에서 생성후 전략 패턴을 사용했지만.. 내가 생각했었던.. 즉..외부에서 type을 지정해
주고.. 내부에서 switch case..  사용시 word객체.(Format.NORMAL, "안녕하세요") 처럼.. 요렇게 사용할
수 있게끔.. 타입(key)를 지원해주는것임.. 

물론 타입 안정성을 더욱 엄격히 해주려면.. 예전에 구상했던.. 채팅 프로그램에서 메세지를 계층
구조화 한것처럼.. enum을 사용해서.. 정확한 구현은 기억안나지만.. enum KeyType{A,B,C}로..
구현하고 위에서 생각한 것처럼.. 매개변수를 받을때 extends 상위 타입 또는 매개변수의 타입을 KeyType
으로 .. 요게 될런지는 모르겠음..


3.클라에선 해당 맵에서 알아서 꺼내씀.. 캐릭정보라면.. dto객체에 get("character")해서 캐릭터 해쉬맵
을 얻고, 캐릭터 정보중 상태정보를 원하면.. 캐릭터 해쉬맵에 대해 get("status")를 해서 상태정보(이걸
do로 구분할지, 어트리뷰트로 구분할진..모르겠음) 해쉬맵을 얻고.. 캐릭터의 hp가 필요하다면.. -_-;; 
int hp = statusMap.get("hp"); 요런식으로 ??  하여튼.. 모든 어트리뷰트에대해 set/get 추가가 불필요하
단.. 장점이 있음.. 

(주의할게.. bean managed  vs container managed 에서 전문가들은 cmp를 권하는 것의 의미를 상기해
야함.. ejb 패턴.. 너무너무 복잡하고.. 개념이 명확히 서질 않고 혼동되고 잇음 ㅠㅠ DTO Factory패턴과
DTO hashmap 패턴이 짬뽕이 된듯.. 이책은 3번쯤 읽어봐야 감좀 잡을듯;; 내수준에 너무 벅참;;)

2번에서 유스케이스별(몬스터와 싸우다 = 캐릭터 정보, 몬스터정보, 아이템정보, 지형정보등) 필요한 데이터를
이뮤터블로서(원본/사본) 묶어준후에.. 클라에 전송하면.. 클라는 필요한 정보를 뽑아내서 사용하면 될테고..
중요한 판정,유효성 검증등은 서버측에 맡기고.. (이것도 애매함.. 서버와 클라간 통신 횟수를 줄이는게 주요
목적인데.. 데이터를 받는게 아닌, 판정및 유효성을 맡기는 것이라.. 게임을 예로 들기엔 이상하단 느낌..OTL)

1.클라측의 ui가 계좌 거래 화면이면.. 일단 서버측에서 계좌정보란 do를 얻어와야 할것이고(로그인등 인증 생략)
.. 이것을 do통채로 전달하냐, dto로 필요정보만 추출하냐, 또는 계좌외 다른 do의 정보도 추가로 필요하냐에 따라 
dto용 데이터를 구성한후..(물론 dao를 통해 얻어온 데이터로) 클라에게 전달하고 클라는 잔고,이체가능액수
기타등등을 뿌려줄것이고

2.클라측에선 해당 계좌 정보를 사용자에게 비쳐주며.. 사용자의 유스케이스(이체,조회,출금...)를 선택받으면..
서버에 이체란 사용자의 커맨드를 전달하고. 서버는 세션빈 + 비지니스를 의미하는 엔티티빈 등을 이용해..
아.. 생각이 막혔다.. 나중에 다시 정리..


by givingsheart 2014. 1. 2. 09:35
레이어                                      책임                                                   구현 기술

프리젠테이션                 사용자 인터페이스                                 jsp,html,javascript,swing/awt중
                                                                                             일반 component 계열
애플리케이션                유스케이스,워크플로,입력검증,                 servlet,<usebean>타겟,swing/awt중
                                  서비스와 상호 작용                                 frame,panel등 component 계열

서비스                         트랜잭션 제어하기,비지니스/워크플로        ejb 세션빈
                                  로직호출,facade로 역할
                             
도메인                         도메인모델,도메인/비지니스로직/입력         ejb엔티티빈, 일반 자바 객체
                                  검증


퍼시스턴스                   도메인 객체 상태의 영속적인 저장소            o/r매퍼(object,relation,mapping),oodbms,ejb
                                                                                               엔터티빈 bmp(bean manage persistance)
                                                                                               엔터티빈 cmp(container m p)

**********************************************************
서비스 레이어: 유스케이스와 비지니스 로직을 호출하는 방법을 제공한다.
즉.. 유스케이스가 실행하는 트랜잭션(계좌이체:pk조회,계좌정보조회,잔금
확인...)을 제어하고, 유스케이스가 충족되는데 필요한 도메인 객체들 사이의
워크플로와 도메인 객체로의 위임을 다룸.(도메인객체가 유스케이스를 다룰
수 있게끔)

음.. 예전에 파일 시스템에서.. 내부의 복잡한 작업용 객체, 각종 비지니스
를 감추고 클라이언트(사용자)에 대해 copy,delete,rename등을 인터페이
스를 제공한 느낌이랄까? 한마디로 클라이언트측에 대해 서브시스템들을
캡슐화 + 단순 인터페이스로 제공함으로서.. 뭐랄까.. 의존성을 줄인다?
내 경운 클라에게 노출되는 개념은 최대한 직관적,현실적으로 제공하자는
생각였었음..(채팅프로그램이라면.. 클라이언트라면.. client 객체 생성후
start()만 제공..즉 서브시스템들을 클라이언트로부터 감춘다는 의미~)

즉.. 사용자가 이 파일들을 이 디렉토리에서 저 디렉토리로 옮겨라는 
비지니스에 대해.. copy(srcPath, destPath)만 받고.. 내부에서 작업할
copy용 워커를 팩토리에서 생성하고, 파일 작업을 워크 팩토리에서
생성하고.. 워커에게 실제 작업을 시키고.. 이런 과정은 클라에게서 
숨겨졌었음. 역할별로 분리하고, 캡슐화하고.. 소통의 창구를 단일화한다.. 
이 개념들이 디자인 패턴에서 복잡성,의존성을 줄여주는데 사용되는 여러 
패턴들의 기본 컨셉이라 생각함. 

ejb의 경우.. 도메인 레이어에 업무(비지니스)를 의미하는 객체(빈)들이
존재함.(일반적으론 풀을 사용) 빈을 이용해 각 도메인의 처리 결과를
얻고, 그것을 조합해 전체 서비스를 구성하는 것이.. 서비스 레이어의 역할인
듯..  

글고 도메인영역.. ejb등은 app로부터 독립적임 = 재사용
(계좌이체 빈이라면.. 이 빈은 .. 여러 다양한 비지니스에서 사용이 가능)

순수 자바라면 이부분이 지난번 배웠던 dao들의 영역인듯.. 

물론 하이버네이트,아이바틱스의 경우 아직 거의 모르지만, 선생님 말씀으론
도메인과, 퍼시스턴스(db) 사이에 끼어서.. db종류별, 도메인 종류별.. 의존성
및 .. 반복되는 작업을 처리해주는 미들웨어인듯..

******************************************************

동시 트랜잭션의 문제.. 버전 번호

상황:여러사람이 동시에 접근해 수정이 가능한 게시판이 있을때
a라는 사람이 작업하는 도중 b라는 사람도 작업을 하게 되었고
a가 작업완료후 b가 작업을 완료했으면?

1.서버에서 읽기를 통해 엔터티 빈에서 데이터를 가져오면서 버전번호를
같이 가져온다.

2.갱신한 데이터(편집한 게시판 내용을 의미하는 엔터티빈)와 버전 번호를 
서버로 돌려보낸다.

3.서버에서 갱신을 수행할때 1에서 발송한 버전 번호와 같은지 판단해서
같을 경우만 갱신한다.

4.버전 번호가 다를경우 갱신을 거부한다.(물론 뒤에 작업 하던 사람의
데이터를 완전히 날려버리지 않고.. 새로운 버전번호를 보내주어 재갱신
시도를돕는다)

=>이문제는..jsp에서 트랜잭션 처리에 대해.. http가 상태를 갖지 않는다는
특성때문에.. 브라우저 에서 하나의 요청후 f5등 새로고침, 뒤로가기 등을 하면 
요청이 2번 되는 문제를 해결하기 위한.. token 발행/검증 기법과 같은
개념일 것이다. (한번에 하나의 처리만 하게끔..) jsp 교재에선 클라이언트
의 request 아이디,현재 시간(timestamp)를 md5를 통해 토큰을 만들었다.
(서블릿or 스클립틀릿으로 지속성 있는 세션에 토큰을 심어놓고.. 리퀘스트/
리스폰스를 통해 토큰을주고 받아가며.. 세션에 있는 토큰과 비교하는 방식이었는듯?)

ejb에선 과연 어떤 방법을 쓸라나? 흥미 진진..

아 글고.. dto factory,session facade(결합성 분리)를 사용하는 의미를 잊지말것..
(ejb 패턴책 너무 어렵 ㅠㅠ)

발췌:
public void setMessagDTO(MessageDTO messageDTO) throws NoSuchMessageException
{
  if(messageDTO.getVersion() !=  this.getVersion() )
    throw new NoSuchMessageException();
   
  this.setSubject( messageDTO.getSubject() );
  this.setBody(messageDTO.getBody() );
}

하지만, DTOFactory 패턴에서도 설명했듯이, 엔티티 빈에 직접 접속하는 방법으로 DTO를 사용
하게 되면 EJB 2.0처럼 기능이 저하된다. 대신 DTOFactory/Session Facade는 엔티티 빈에서
데이터를 얻어 엔티티 빈의 로컬 인터페이스를 통해 get/set 메소드를 직접 호출하는 방법으로
엔티티 빈을 갱신하는 작업을 한다. (reflection 중 getDeclateMethode()로 얻고.. 반복문에서
get/set 문자열로 게터,세터 찾아내고 , invoke 활용하겠지? 아님 말고 -_-;)

이런 패러다임을 사용하면, 세션 빈이 set 메소드를 통해 직접 엔티티 빈을 갱신하게 되어
엔티티빈이 더이상 갱신하기 전에 데이터의 버전을 자동으로 검사할수 없게됨으로.. 개발자가 
갱신절차 전에 갱신할 데이터의 버전을 넘겨야한다.

public void updateMessage(MessageDTO messageDTO) //서비스 영역중 세션빈 메서드임? 헷갈려 죽겟네..
{
  Message message = null;
  try
  {
     mesage = this.messageHome.findByPrimaryKey( new MessagePK(messageID) );
     message.checkAndUpdateVersion( messageDTO.getVersion() ); //불일치시 익셉션 발생 가능
     //메세지 갱신
     message.setBody( messageDTO.getBody() );
     message.setSubject( messageDTO.getSubject() );
   }
   catch(IncorrectVersionException e)
   {
      //트랜젝션 롤백.. 저 위의 b님.. 죄송합니다;;
      this.ctx.setRollbackOnly();
      throw new StaleupdateException(); //상위 콜러측에 알림
    } 
    catch(...)
  ...
}

public void checkAndUpdateVersion(long version) throws IncorrectVersion...
{
  long currentVersion = this.getVersion();
  
  if(version != currentVersion)
    throw new IncorrectVersion...();
  else
    this.setVersion(++currentVersion);  //초단순.. +1
}

=>위의 처리가 전문용어로.. 낙관적(optimistic) 동시성(concurrency) 획득이라함 -_-;;
(타임스탬프 쓰는 방식도 거론하는데.. 서버 시계 멈추거나, 시간 오차등.. 태클걸고 있음..)



*****************************************************

아이바틱스 - 하이버네이트 개념 이해..(한번 봣던 문서같은데..그새 생소해짐..)


******************************************************

bmp vs cmp(추가로 cmp에서 자동으로 값을 read/write하기 위해 reflection 개념을 사용.. 메서드중 setXXX만
추출등.. 글고 전문가들은 bmp 사용하지 말것을 권고.. cmp가 트랜잭션 처리도 알아서 해주고.. 요즘은 어떤지
모르겠음.. 하도 옛날 자료라..)


*******************************************************
이번에 ejb 실습하면서 추가한 외부 라이브러리.. (선에서 자바ee 다운및 설치후)

C:\glassfish4\glassfish\modules\javax.ejb-api.jar 를 외부 라이브러리로 추가함..
그외에도 엄청 많은 jre 파일이 있는데.. 구분을 못할 정도임..

*********************************************************8

java ee 용어;;(스윙에,xml에,ejb에.. 머리가 흡수를 거부하고 있음 OTL)

****************************************************8
중국산? 자바 코드 모음...


http://www.pudn.com/downloads3/ebook/detail10484.html


*******************************************************8

상태/무상태 세션빈(초 간단 결론?static으로 처리만 하면 무상태, 세션에 대해 로그인 정보등 의미있는 정보를 유지하고 
있으면 상태)


by givingsheart 2014. 1. 2. 09:33
| 1 |