'분류 전체보기'에 해당되는 글 539건

  1. 2005.05.23 BAM, ‘BPM의 꽃’
  2. 2005.05.23 BPM is a superset of EAI and workflow ...
  3. 2005.05.23 [개념] Business Intelligence논의
  4. 2005.05.23 BPM 솔루션이란..?!
  5. 2005.05.17 Spring Web Flow 1
  6. 2005.04.23 [사설] 단위테스트에 대한 오해1 (단위테스트가 만병통치약은 아니다)
  7. 2005.04.15 [노트] Comparable 타입이란.. 1
  8. 2005.04.14 ebXML Reg/Rep RS 2.1 버전 한글판
  9. 2005.04.14 ebXML Reg/Rep RIM 2.1 버전 한글판
  10. 2005.04.14 UDDI 3.0 API 정의서
  11. 2005.04.14 UDDI 3.0 자료구조 정의서
  12. 2005.04.14 UDDI 3.0 레지스터리 관리 및 운영지침
  13. 2005.04.14 ebXML Registry의 WSDL
  14. 2005.04.14 ebXML Registry & Repository 스펙 3.0 (Committee Draft)
  15. 2005.04.14 전자문서개발 가이드라인 3.0 (공청회용)
  16. 2005.04.14 e비즈표준 기술 가이드라인1.0 (공청회용)
  17. 2005.04.14 TBG17 그룹의 코아 컴포넌트
  18. 2005.04.14 시맨틱 라이브러리 설계 및 활용지침(ECIF 규격)
  19. 2005.04.14 볼레로와 ebXML간의 메시지 교환지침(ECIF 규격)
  20. 2005.04.14 RosettaNet과 ebXML간의 전자문서 교환 지침(ECIF 규격)
  21. 2005.04.14 ATG2의 XML 스키마의 명명 및 설계와 관련된 지침
  22. 2005.04.14 UN/CEFACT ICG 제안한 Registry 0.5 버전
  23. 2005.04.14 웹 서비스를 ebXML 등록저장소에 등록 - 스펙(버전 1.0)
  24. 2005.04.14 Registering Web Services in an ebXML Registry, Version 10.01 Information Model v1.020
  25. 2005.04.13 HiveMind: What's it all about? 1
  26. 2005.04.13 Unit-Testing Hibernate With HSQLDB
  27. 2005.04.10 Annotations in Tiger, Part 2: Custom annotations
  28. 2005.04.10 Annotations in Tiger, Part 1: 메타데이터를 자바 코드에 추가하기
  29. 2005.04.10 이클립스 3.0 단축키
  30. 2005.04.10 [번역] J2SE 5.0 Annotations 1

BAM, ‘BPM의 꽃’

2005. 5. 23. 22:48
비즈니스 활동 모니터링(BAM, Business Activity Monitoring)이 새로운 IT 시장으로 부각되고 있다. BAM은 비즈니스 이벤트가 발생할 경우, 이와 관련된 데이터를 실시간으로 수집하고 분석해 적절한 대응을 취하자는 개념. 최근 ERP를 전사 규모로 확대하거나 비즈니스 프로세스 관리(BPM)를 도입한 기업들은 개선효과를 지속시키기 위해 KPI를 도출하고 이를 모니터링하려 하고 있다. 이러한 것들이 바로 BAM의 영역이다.
현재 BAM은 BPM과 결합되거나 BPM의 일부 모듈로 시장에 선 보이고 있으나, 독자적인 시장 형성 가능성 역시 매우 높은 것으로 평가받고 있다.
국내에서는 작년 하반기부터 팁코나 웹메소드 등 EAI 벤더들을 중심으로 접근이 시작됐고, 올해 들어 대부분의 BPM 벤더들도 BAM 시장을 주목하고 있다.
관련 전문가들은 올해 적어도 1~2개 사례가 출현할 것으로 예상하고 있으며, 시장 전개 양상에 따라 BPM보다도 더 빠른 확산도 가능할 것으로 전망하고 있다. 높은 기대 속에 초기 시장을 형성해가고 있는 BAM 시장을 살펴본다.

이강욱 기자 kwlee@it-solutions.co.kr

1. BAM의 정의와 확산
BAM이 강해야 BPM이 산다

2. BAM의 구현과 활용
수집•분석•조치 3개 요소가 관건

3. BAM 향후 전망
BPM, BI, BRE 시장판도 크게 바꿀 듯

4. 업체 동향






1. BAM의 정의와 확산

BAM이 강해야 BPM이 산다
보완 요소 부각으로 동반 성장 조짐

올해 국내 IT 시장을 주도할 핵심 트렌드를 꼽는다면 단연 BPM이다.
ERP 이후 가장 광범위하게 공감대를 이끌어내고 있으며, 제품 역시 빠르게 성숙 단계로 접어들고 있다. BPM은 이제 ‘포스트 ERP’ 시대를 이끌 핵심 애플리케이션(Killer Application)으로 시장 입지를 다져가고 있다.
이런 만큼 각 BPM 벤더들은 일제히 제품 차별화에 나서고 있고, 기능 강화에 박차를 가하고 있다. 그 와중에 BPM 경쟁력 강화의 핵심요소로 꼽히고 있는 부분이 바로 BAM이다.
BAM을 통해 BPM 기능을 한 단계 업그레이드할 수 있을 뿐만 아니라, 기존에 지원하지 못했던 부분까지 보완하는 것이 가능하기 때문이다.
BAM은 BPM의 핵심적인 기능인 프로세스의 가시성 제공에서 한걸음 더 나아가 비즈니스 이벤트의 감지와 분석, 그리고 이를 기반으로 한 빠른 대응을 가능케 해준다. 또한 BPM이 제공하지 못했던 프로세스 변경기준을 BAM은 생성할 수 있다.
이처럼 BAM은 BPM의 기능 업그레이드와 취약점 보완이라는 매력적인 요소를 두루 갖추고 있어 BPM 벤더들이 관심을 한 몸에 받고 있다.
티맥스소프트 고희숙 수석은 “BPM이 프로세스 분석을 중심으로 발전하고 있으나 변경기준의 부재라는 한계를 안고 있다”며 “BAM은 실제 업무를 중심으로 변경 기준 제시가 가능하고 특화 모니터링을 제공해 시장에서 동반 성장 조짐이 나타나고 있다”고 말했다.
팁코소프트웨어코리아, 웹메소드코리아, 한국오라클, 한국마이크로소프트, 한국CA 등은 올해 들어 BPM과 BAM이 통합된 BPM 제품을 발표해, BPM 및 BAM 시장 공략에 나서고 있다. 핸디소프트와 티맥스소프트 같은 국내 BPM 전문 업체들도 BAM 부분을 강화에 적극 나서고 있다.
이제 BAM은 BPM의 국제 표준격인 BPEL(Business Process Execution Language)의 준수 여부와 함께 향후 BPM의 핵심 경쟁력이 될 것으로 전망되고 있다.

BAM 모습 ‘천변만화’

BAM에 대한 관심고조와 함께 BAM에 대한 견해 역시 다양하게 제시되고 있다.
많은 사람들이 BPM과 BAM의 차이를 혼란스러워하고 있으며, 비즈니스 인텔리전스(BI), 또는 CPM(기업성과관리)과의 연관성 설명에도 어려움을 겪고 있다. BAM의 주요 특징을 통해 ‘특화된 BPM’으로 보기도 하며, 실시간 BI를 BAM으로 규정하기도 한다.
ERP는 표준 프로세스를 정립하는 것으로 각 프로세스간 관리 기능이 없다. 이 문제를 워크플로우를 기반으로 해결해 낸 것이 BPM이다. 이러한 관점에서 BAM을 설명한다면 정보계 데이터, 이력 데이터 등을 대상으로 하고 있는 BPM으로 볼 수 있다. BAM을 특화된 BPM으로 바라보는 시각이다.
BAM 기능 중 정보계 데이터나 이력 데이터를 불러와 실시간으로 새로운 이벤트를 분석하는 부분에 초점을 맞추면 이는 BI를 실시간으로 구현한 것이 된다. BAM을 실시간 BI로 규전하는 견해다.
이처럼 BAM은 구현되는 기능에 따라 다양한 모습으로 이해할 수 있다.
기본적으로 BAM 기능은 분석 및 평가를 위한 KPI를 어떻게 구성하느냐에 따라 크게 달라진다. 운영 데이터를 보여주는 단순 모니터링 툴부터 프로세스 활동을 평가하고 비즈니스 자체를 평가하는 고급 툴의 모습을 모두 가지고 있다.
이런 상황을 반영하듯 일부 BPM 벤더들은 BAM을 BPM에 특화된 리포팅 툴 정도의 인식하는가 하면, 일각에서는 BPM과 기능과 영역이 뚜렷하게 구분된 독립된 영역으로 규정하기도 한다.
전반적으로 웹메소드, 팁코 등과 같은 EAI 벤더들이 BAM을 독립된 영역으로 파악하고 향후 가능성을 높게 평가하고 있다. 반면 통합 BPM이나 BPM 플랫폼을 제시하는 벤더들은 BAM을 BPM에 붙어가야 의미가 있는 제품으로 평가한다.

모니터링+KPI가 BAM

다양한 개념이 제시되고 있는 BAM(Business Activity Monitoring)을 이해하기 위한 핵심 키워드는 당연히 ‘비즈니스 활동(Business Activity)’이다.
이미 존재해오던 콘솔 기반의 모니터링에 비즈니스 활동이라는 추가적인 영역을 시스템적으로 구현한 것이기 BAM이기 때문이다.
여기서 비즈니스 활동이란 실제 프로세스가 흘러가는 도중 발생하는 다양한 이벤트, 가령 주문 프로세스라 하면 주문을 비롯한 주문변경, 취소, 반송, 환불 등 관련 프로세스 등을 모두 포함하는 의미다.
비즈니스 활동 모니터링이란 이 시기에 발생한 모든 상황과 정황을 실시간으로 측정하는 것을 말한다. 이를 통해 실무자는 프로세스의 전이과정, 현 상황, 현 결과 등을 파악할 수 있다. 이러한 모니터링 결과가 KPI와 연계되어 평가가 이뤄질 때 이를 통상적으로 BAM이라고 지칭한다.
이벤트 발생 시점부터 과거 패턴, 자산현황, 신용정보 등과 결부되어 정상 거래 유무를 판단하고, 만약 허용치를 벗어나면 경고를 주는 구조가 갖춰지면 BAM이라고 하는 것이다.
예를 들어 신규주문, 취소, 환불/ 반품 프로세스가 동시에 진행되는 프로세스의 경우 BAM은 3개 프로세스를 동시에 파악할 수 있도록 한다. 그리고 이를 통해 실시간으로 몇 개의 주문이 들어왔고, 이중 실제 매출에 기여하는 주문이 어느 정도인지 파악할 수 있다.
이러한 모니터링 결과를 사전에 정의된 룰과 KPI와 연계해 결과값이 허용치를 초과하거나 밑돌 경우 자동으로 경고를 보내고 원인을 찾아낸다.

------------------------------------------------------------
<박스 / BAM과 BPM>
BAM이 BPM을 압도할 수도 있다

BAM과 BPM은 상호보완관계를 이루고 있어 공통점과 차이점을 모두 가지고 있다.
둘 간의 공통점은 우선 이벤트 드리븐 방식이며, 리얼타임 또는 라이트 타임을 지향하면서 지체시간 제로(Zero Latency)를 지향하고 있다는 점, 그리고 적극적인 푸시 방식으로 정보를 제공한다는 점을 들 수 있다.
반면 BPM은 프로세스간 연결고리를 관리하는 반면, BAM은 이벤트 발생부터 룰 엔진을 통한 분석과 해당 담당자에게 경고 발송 기능을 제공하는 차이점이 존재한다.
BAM을 리얼타임 BI로 이해하면 둘 간의 차이를 더 쉽게 이해할 수 있다.
BPM이 기간계를 중심으로 해 ERP에서 확장 ERP로, 그리고 이제 BPM으로 가고 있는 것이라면, BAM은 정보계를 중심으로 기존 BI가 RTE 개념과 접목되면서 BAM으로 나타나고 있는 것으로 설명된다.
한편 이러한 기능 차이에 주목해 BAM의 부각 가능성이 BPM을 압도한다는 견해도 제시되고 있다. ERP 구축 이후 활용과 개선 효과를 기대하는 고객에게는 BPM이 제시하는 비전보다는 BAM의 실제 기능이 훨씬 구미가 당긴다는 것이다.
아직까지 기업용 시장의 주류는 ERP가 차지하고 있다. BPR을 통해 ERP를 구축한 고객들은 어느 정도 프로세스를 구축하게 되고 비록 프로세스 간 최적화가 불가능하다 하더라도 이들에게 BPM은 추가 구매 요소가 그리 높지 않다는 것.
오히려 ERP 구축 이후 KPI 연결로 가는 것이 고객 요구에 부합하는 것이며, BAM은 이를 지원하고 있다는 설명이다. ERP 구축 이후 BPM 도입으로 단계별 프로세스 가시화와 기업최적화보다는, 모니터링하고 KPI를 점검할 수 있는 BAM이 더 유용할 수 있다는 설명이다.
더군다나 현 시점에서 BPM의 전사 구현은 위험도가 높을 뿐만 아니라, BPM이 전사 프레임웍을 제시하지도 못하고 있다. BAM은 지속적인 개선작업을 지원하고 제품기간 단축 등 기업의 목표 수행을 지원하는 합리적인 툴이 될 수 있다는 설명이다.
EAI 벤더들은 BAM 시장의 가능성을 높게 보고 있다. 그러나 그들 역시 BAM을 BPM과 결합된 개념으로 제시하기도 한다. BPM과 BAM이 결합되면 시너지 창출이 가능하고 활용도가 훨씬 다양해지기 때문이다.

------------------------------------------------------------<박스 끝>

2. BAM의 구현과 활용

수집․분석․조치 3개 요소가 관건
자동화와 실시간이 기술적 핵심

BAM에 대한 접근과 견해가 다양한데 비해 BAM 구현을 위한 요소는 생각보다 간단하다.
‘숱하게 발생하는 비즈니스 이벤트를 어떻게 수집하고, 분석해 조치를 수행할 것인가?’가 핵심 관건이다.
BAM 구현을 위해서는 실시간으로 이벤트의 수집, 분석, 대응이 이뤄지면 되는 것이다.
이벤트 수집을 위한 전제 조건은 결국 ‘실시간 인티그레이션’이다.
BAM에서 통합이 중요한 이유는 인프라 단을 비롯해 다양한 애플리케이션에서 흘러가는 프로세스를 감지하기 위해서는 전체 시스템 연동이 필수적이기 때문이다. 또한 KPI를 선정하고 이를 보여주기 위해서도 인티그레이션은 필수불가결한 요소다.
대부분의 BAM 솔루션은 BAM 엔진 밑단에 EAI 툴과 같은 데이터를 수집하는 레이어가 자리하고 있다. 오라클의 경우 BAM을 비롯해 BPM 솔루션들을 인티그레이션 제품군으로 분류하고 있는 것도 이러한 요소를 중히 여기고 있기 때문이다.
이러한 실시간 인티그레이션을 위해서는 기존 EAI와는 조금 달라야 한다.
KPI를 산정하고 평가하기 위해서는 기존 이력 데이터를 불러와야 하기 때문에 EAI 만으로는 한계가 존재한다. 따라서 실시간 인티그레이션을 위해서는 EAI 기능과 ETL이 결합되어야 한다. EAI를 통해 이벤트를 감지하고 ETL을 활용해 분석 업무를 담당하는 구조가 BAM이 말하는 실시간 인티그레이션이다. 이는 이론적으로는 우수하지만 아직까지 연동의 문제가 걸림돌로 작용하고 있다.
결국 실시간 인티그레이션은 EAI와 ETL이 점차 통합되어 가는 모습과 흐름을 같이하고 있다. 이미 몇 년 전부터 IBM과 어센셜소프트웨어는 IBM EAI 툴인 ‘MQ’와 어센셜의 ETL간 연동을 추진해왔다. 지난달 IBM이 어센셜을 인수함에 따라 EAI와 ETL 결합 움직임은 더욱 활발해질 것으로 예상된다.

비즈니스 룰을 통해 분석

BAM에서 분석은 비즈니스 룰 엔진이 담당하게 된다.
실시간으로 발생하는 무수한 비즈니스 이벤트를 사람이 개입해 OLAP이나 리포팅으로 분석하기란 사실상 불가능하다. 이를 사전에 비즈니스 룰을 설정해 두고 분석 과정을 자동화시켜야 실시간 분석이 가능해진다. 따라서 BAM에서는 비즈니스 룰 엔진이 핵심 요소를 이루고 있다.
비즈니스 룰 엔진은 사람의 개입 없이 룰에 따라 자동으로 감지하고 수행해 최종 결과치를 보여주는 자동화 개념을 바탕으로 하고 있다. 마치 BSC에서 KPI를 만들어 자동수집하고 최종 결과치를 보여주는 것과 유사한 구조이다. 이러한 점에 주목해 BAM을 ‘중간관리자/실무자를 위한 BSC’라 부르기도 한다.
BAM에서 비즈니스 룰은 OLAP 분석 결과나 도출된 KPI 등을 기반으로 만들어진다.
BAM이 제공하는 가장 핵심 기능이 실시간 분석이라는 점을 고려하면, BAM의 핵심 영역은 바로 비즈니스 룰 엔진이라고 할 수 있다. BAM에 룰이 없으면 사실상 이벤트 수집과 추출이 불가능하고, 설사 가능하더라도 데이터 링크에 불과하기 때문이다.
이러한 이유로 최근 발표되는 대다수의 BPM 솔루션들은 비즈니스 룰 엔진과 BAM이 함께 포함되고 있다.
조치는 문제 발생이 감지된 경우 담당자에게 경고를 보내고 여타 프로세스를 자동으로 시작하는 것 등을 말한다.
경고는 단문메시지, 이메일 등이 될 수 있을 것이고 사전 정의된 룰에 따라 시스템 차단 등이 자동 실행된다. 따라서 BAM의 사용자는 사람뿐만 아니라 시스템도 일부 사용자가 될 수 있다. 시스템이 다른 프로세스를 자동으로 유발시키는 경우도 있기 때문이다.
경고 발송은 결국 사용자가 처음 접하게 되는 화면에 푸시 형태로 전달하는 것이 가장 바람직해 BAM 역시 결국 포털 형태의 UI를 가져갈 것으로 전망된다.

자발적 수요 나타나고 있어

BAM은 모니터링 영역이 BPM의 부각으로 동반 상승하고 있는 것으로 파악하기도 하고, 실시간 분석환경의 필요로 새롭게 부각되고 영역으로 분류되기도 한다.
이러한 인식의 차이에도 불구하고 시장에서는 분명히 BAM적인 요구가 출현하고 있다는 점에 주목할 필요가 있다. 그리고 이러한 시장의 수요는 상당수가 ERP나 BPM을 도입한 기업들이 지속적인 개선효과 구현이나 활용도를 높이기 위한 자발적인 노력의 모습으로 나타나고 있다.
기업들의 고민이 구체화되면서 출현한 영역을 두고, IT 벤더들이 ‘그것이 바로 BAM’이라고 나서고 있는 형상이라고 하겠다.
ERP 확산에 적극적인 대기업들은 전사 엔터프라이즈 모니터링 시스템에 대해 고민하고 있고 비즈니스 룰 엔진(BRE) 역시 기존 보험권에서 통신, 제조, 제철 등의 분야로 확대될 움직임을 보이고 있다.
전사 엔터프라이즈 모니터링 시스템은 아직 개념적인 단계이지만 ERP․CRM 등 개별적으로 수행되던 모니터링 인프라를 통합하자는 것. 분석기법을 통일하고 대시보드를 통해 우선순위를 정해 모니터링을 의사결정에 최대한 반영하려는 시도이다.
BAM에서 말하는 인티그레이션과 통합 실시간 분석 및 모니터링이 구현되고 있어 BAM의 비전과 매우 유사한 접근임을 알 수 있다.
일부 조기경보 체계에도 BAM 요소가 적용되고 있다. 롯데제과는 조기경보 시스템 중 매출 추이 분석 부분에 BAM 요소를 일부 적용됐다. 지난 몇 년간 매출추이를 분석해 최근 매출 추이와 비교하고 이상징후가 있으면 사전 조치를 가능케 하는 방식이다.
롯데제과 사례는 시장 흐름을 보면서 조기대응을 가능케 하는 시도로 BAM은 이미 구현되고 있음을 보여준다.
이처럼 기업의 자발적인 움직임이 BAM이 제시하는 것과 유사한 방향을 띠고 있다는 것은 BAM의 시장 가능성이 그만큼 크다는 것을 위미한다.

품질․리스크 관리 등에도 적용 가능

BAM에 주력하는 벤더들은 점차 구체적인 BAM 적용 분야를 세분해 시장 공략에 나서고 있다. 이탈고객방지나 카드 사기방지 등이 BAM이 가장 먼저 적용될 수 있는 분야며, 이미 상당수 적용되고 있다. 룰을 어떻게 설정하느냐에 따라 품질관리, 리스크관리, 수익성 관리 등에서도 적용이 가능해 현재 접근이 시도되고 있다.
웹메소드 박정우 이사는 “BAM은 다양한 활용이 가능해 6시스마 기본 툴로도 사용이 가능하다”며 “6시그마에서 규정하고 있는 정의, 측정, 분석, 통제의 방법론이 BAM 철학과 유사해 KPI를 모니터링하는 것이 가능하다”고 말했다.
최근 금융권을 강타하고 있는 바젤Ⅱ가 규정하고 있는 내부통제법과 사베인즈-옥슬리 법안으로 대표되는 회계 컴플라이언스 부분에도 BAM의 적용이 가능하다.
내부통제법이나 회계 컴플라이언스에서는 ‘기업 프로세스 투명화’와 ‘부정 적발을 위한 시스템 구축’을 요구하고 있다. 공시관련 프로세스와 모니터링을 통합 관리하면 이들 버버안이 요구하는 사항을 충분히 총족 시킬 수 있다.
이외에도 금융권의 경우 한 계좌에서 일정 금액 이상의 자금이 여러 차례 입출금이 되풀이되는 경우 자금세탁 의혹을 가지고 모니터링을 강화하는 부분에 적용될 수 있다. 해외에서는 자금세탁 방지법 등의 관련 법안이 적용되고 있어 이러한 부분에 적용되고 있다. 그 외에도 감사/감리 시스템에도 적용하는 것이 가능하다.
관련업계는 BAM이 효과적인 내부 통제 방안으로 충분한 가치를 지니고 있어 투자비용 부담에도 불구하고 일부 대기업을 중심으로 기업 프로세스 투명하게 하려는 시도가 있을 것으로 기대하고 있다.


3. BAM 향후 전망

BPM, BI와 BRE 시장판도 크게 바꿀 듯
갈수록 BPEL, SOA 등 표준 준수가 관건

BAM은 모니터링을 중심으로 실시간 분석 환경이 결합된 형태로 제공되고 있다. 그러나 조만간 기업 IT 인프라와 애플리케이션을 총괄하는 구조로 진화될 것으로 보인다.
BAM은 KPI를 통해 비즈니스적 영향 분석뿐만 아니라 운영상의 문제까지를 모니터링 대상으로 하고 있다. 가령 주문이 늦게 들어오거나 허용치에 미치지 못하는 설정된 룰에 따라 네트웍, 애플리케이션 서버, 웹 서버, 주문 애플리케이션 서버, 아답타 등의 이상 유무를 자동 점검하는 것이다.
따라서 BAM은 인프라 단과 애플리케이션을 총괄할 수 있어야 하고 그러한 방향으로 나아갈 것이다. 그리고 인프라와 애플리케이션은 서로 영향을 주지 않는 상태에서 고유 역할을 수행하면서 BAM을 통해 서로 커뮤니케이션하는 구조로 될 것으로 보인다.
점차 BPM과 BAM에서 표준준수가 부각되는 이유가 BAM의 향후 발전 방향이 웹서비스 및 SOA를 기반으로 하고 있어야 효과 구현이 가능한 모습으로 진행되고 있기 때문이다.

BPM 시장 ‘제 2라운드 시작’

BAM의 근간이 된다고도 볼 수 있는 BPM은 올 하반기부터 판도가 크게 바뀔 것으로 전망된다. 관계 전문가들은 “올 하반기부터 본격적인 2라운드가 시작될 것”이라고 전망하고 있다. 그동안 국내 BPM 시장은 워크플로우 기반 BPM이냐, EAI 기반 BPM이냐는 논란을 거쳐 워크플로우 기반 BPM이 시장을 석권해왔다.
핸디소프트와 파일네트가 2강 체제를 형성하고 각각 공공분야와 금융이라는 뚜렷한 강세시장을 고수해왔다. 그러나 최근 들어 두 업체가 확실히 강세를 보였던 시장의 경계가 점차 무너지고 있어 경쟁이 가열되고 있다.
더군다나 한국오라클과 한국MS가 BPM 시장 공략을 강화하고 있어 이들이 시장에 미치는 파장이 어느 정도냐에 따라 시장 판도가 크게 바뀔 수 있다는 것이다.
이러한 시장 역학관계 변화와 함께 BPM에서도 점차 표준 논란이 강력하게 제기될 것으로 보인다.
지난달 방한했던 오라클 서버 테크놀로지 부문 라울 파텍 이사는 “EAI냐, 워크플로우냐는 논란은 로컬 벤더들이 부각시키는 부분이며 이를 기반으로 해 포장하는 수준에 불과하다”며 “기존 제품을 활용 측면에서 초기시장 공략에는 유효하지만 장기적으로는 확장성과 표준준수 부분에서 한계를 노출할 수밖에 없다”고 말했다.
올 하반기까지는 워크플로우 BPM이 그 이점을 유지할 수 있을 것이지만, 향후 오픈 환경 지원부분에서는 도태될 가능성 크다는 것이다.
대다수 BPM 전문가들 역시 글로벌 표준 지원이 BPM의 핫 이슈로 부각될 수밖에 없을 것으로 보고 있다. BPM에서 통합문제의 해결책은 결국 웹 서비스 뿐이라고 보기 때문이다.
이미 미국 IT 사용 기업들의 70%가 웹서비스를 지원하고 있고, 30%가 SOA를 구축하고 있는 환경에서 BPM에서 표준준수는 이제 대세이며 일반화될 것으로 보고 있다.
아직 국내 웹서비스 기업 비중 낮지만 조만간 도입이 시작될 것이고, 아직까지 C/S 환경인 기업은 웹 전환 고려 시 웹 서비스 지원으로 갈 것으로 예상하고 있다.

EAI와 BI, 향후 BAM 주도권 경쟁

BAM 시장에 참여하는 벤더들은 갈수록 증가할 것으로 보인다. 이미 가트너는 BAM은 한 개의 솔루션만으로는 구현이 불가능하고 여러 솔루션이 복합될 것이라고 전망하기도 했다. 이럴 경우 BAM 전문업체(Pure Player)들은 살아남지 못할 수도 있다고 예측했다.
BAM은 연관 시스템과의 연결성 문제 해결이 중요한데, 전문 업체들의 경우 이러한 부분에서 역량을 축적하기가 그리 쉽지 않기 때문이다.
이미 BAM 시장에 대형 벤더들의 진입이 시작되고 있다. 오라클이 BPM과 독립된 BAM 솔루션을 발표해 시장에 진입했고, SAP 역시 BPM을 출시했다.
SAP 4.0 이후부터 워크플로우를 지원하고 있음에도 불구하고, SAP는 전용 BPM 제품을 출시하고 BPM 시장에 진입했다. BPM이 ERP의 한계 극복에서 비롯된 만큼 BPM 시장에서 SAP의 가능성은 그 어느 벤더보다 크다고 평가된다. 그리고 BPM 강화는 필연적으로 BAM 부분의 강화로 이어질 것이다.
대형 벤더들의 BAM 시장 진입이 이뤄지고 있는 가운데 현재가지는 EAI 업체들이 주도권을 상당부분 가지고 있다.
BAM 시장에서 EAI 벤더들의 접근이 빠른 이유는 전사적인 이벤트 모니터링을 위해서는 EAI가 불가피하기 때문이다. 굳이 EAI가 아닌 어댑터 등을 통해서도 BAM이 가능은 하지만 EAI가 훨씬 용이하다. 그리고 EAI 벤더들은 데이터 수집이 자유롭고, 이를 기반으로 한 분석 및 경고 기법에 일찍부터 관심을 가져와 제품이 선진화된 상태다.
EAI 벤더들의 적극적인 움직임과는 비교해 BI 업체들은 아직 BAM에 대해 적극적인 움직임을 보이지 않고 있다. 배치 방식의 분석환경에 익수한 BI 벤더들이 실시간 분석이라는 트렌드에 빠르게 대응하기란 그리 용이하지 않을 것이다.
그러나 BI벤더들이 보유하고 있는 분석 영역이 BAM에서 핵심적인 영역을 차지하고 있고 KPI 도출 및 성과관리에 풍부한 노하우를 보유하고 있어 향후 독자 BAM으로 방향을 잡을 것으로 보인다. 이중 리포팅 툴만 보유한 업체들의 경우 BPM 벤더들과의 제휴 또는 BPM에 특화된 리포팅으로 나갈 것으로 보인다.


4. 업체 동향

BAM과 BPM 결합 ‘봇물’
독자시장 형성에는 이견

◇ 한국오라클 / 오라클 인티그레이션 BAM
4월 제품 출시, 시장 공략 본격화

한국오라클은 이달 초 BPM 솔루션을 공식 출시한다. 이미 지난달(3월)에 한국오라클은 ‘오라클 애플리케이션 플랫폼 스위트(APS, Oracle Application Platform Suite)’ 전략 발표를 통해 BPM 시장 공략 강화를 공식 선언한 바 있다.
오라클 BPM 솔루션은 BPM 제품인 ‘오라클 BPEL 프로세스 매니저’와 BAM 제품인 ‘오라클 인티그레이션 BAM’이 결하된 형태로 구성되어 있다.
오라클의 BAM 솔루션은 BPM 제품과 독립적으로 분류되어 있고 인티그레이션 제품군에 포함되어 있다. 오라클 인티그레이션 제품군은 BAM, BPM, EAI(데이터 허브), BI 인티그레이션 등으로 구성되어 있다. 오라클은 향후 BAM이 독립적인 요소로 성장해 갈 가능성이 클 것으로 판단해 별도의 제품군으로 가져가고 있다.
한국오라클 김행열 수석은 “BAM은 향후 독자 시장으로 성장해갈 가능성이 높다고 판단하고 있다”며 “이럴 경우 타사 제품을 지원하는 개방형 환경요구가 증대될 것이고 이를 위해 BPM과 BAM에서 표준 준수에 큰 의미를 부여하고 있다”고 말했다.
한국오라클은 자사 BPM 솔루션이 서비스 기반 아키텍처(SOA)를 기반으로 한 표준 솔루션이라는 점을 최대한 부각시킬 방침이다. 기존 솔루션들은 워크플로우나 EAI를 기반으로 하고 있어 확장성과 호환성, 재사용성이 부족하다는 것이다.
오라클의 BAM 솔루션은 각 프로세스 단계마다 설치된 센서를 통해 이벤트를 감지한다. 센서를 통한 데이터를 BAM에서 캡처하고 이를 BAM 엔진이 처리해 후속처리로 연결된다.
대시보드를 통해 실무자들은 KPI 동작 결과를 비주얼하게 파악할 수 있는 구조로 되어 있다. 대시보드를 통해 실시간으로 데이터 흐름을 파악하게 되므로 향후 퍼포먼스가 중요해 질 것으로 판단하고 있다.



◇ 팁코소프트웨어코리아 / 비즈니스 팩터 5.0
조기 공략으로 사례 확보, 신버전 출시 앞둬

팁코소프트웨어는 작년 하반기부터 BAM 시장 공략에 착수해 왔다.
경쟁사에 비해 조기 시장 공략에 나선 만큼 사례도 확보하는 성과도 거두고 있다. 팁코는 최근 S사의 마케팅 부서가 프로모션을 진행하는 데 있어 BAM 기법을 적용했다고 밝혔다. 신규 서비스 개발에 활용하기 위한 가입자 트렌드나 다운 횟수 등의 분석을 BAM 기법으로 수행하고 있다는 것이다. 이미 사례를 확보한 만큼 추가 확산도 조만간 가능할 것으로 기대하고 있다.
팁코소프트웨어코리아 성학수 이사는 “최근 들어 제조, 통신, 금융권 등에서 지속적으로 요구가 출현하고 있어 올 BAM 시장이 빠르게 활성화 될 것으로 기대하고 있다”고 말했다.
더군다나 다음 달(5월)에는 팁코의 BAM 솔루션인 ‘비즈니스 팩터 5.0’ 버전이 발표될 예정에 있어 시장 공략을 더욱 가속화할 계획이다.
비즈니스 팩터 5.0은 4.0 버전까지 존재하던 퍼포먼스 문제 해결에 중점을 두고 개발됐다. 4.0 버전까지는 데이터를 꺼내올 때 찾는데 시간이 걸려 성능에 얼마간의 문제가 있었으나 발표를 앞둔 신 버전은 이 부분이 크게 강화됐다.
이를 해결하기 위해서 팁코는 5.0 버전부터는 메모리 DB를 사용한다고 밝혔다. 대용량 지원과 속도 문제를 해결하기 위한 선택이라는 것이다. 비즈니스 팩터 5.0은 관련 서버와 디자인 툴, 프리젠테이션 툴인 이벤트 파인더로 구성되어 있다.
팁코 BAM은 비즈니스 활동 분석에 있어 Time(언제), Location(어디서), Topic(어떤 카테고리)를 가장 기본적인 요소로 삼고 있다. 나머지 요소들은 프로세스 디자인 과정에서 KPI에 따라 활동 모델링(Activity Modeling)으로 적용한다.
팁코는 본사 차원에서 BAM 전문업체인 프라자를 인수해 제품군을 갖추는 등 일찍부터 BAM 시장을 주목해 왔다.



◇ 웹메소드코리아 / 옵티마이즈
사베인즈-옥슬리 등 적용분야 세분 공략

웹메소드코리아 역시 여타 EAI 벤더들과 마찬가지로 작년부터 BAM에 대한 명확한 비전 제시에 나서고 있다. 작년 하반기부터 마케팅 강화 및 BAM 역량 강화에 착수하고 있다. 일본에서는 현재 몇 개의 파일럿 프로젝트가 진행되고 있어 관련 노하우 습득도 이뤄지고 있다고 밝히고 있다. 현재 적극적인 영업 활동을 전개하고 있으며 다음 분기부터 가능성이 높을 것으로 전망하고 있다.
웹메소드는 광의의 개념으로 BAM과 BPM이 결합된 BPO(Business Process Optimization)를 제시하고 있다. 웹메소드는 BPO가 BPM과 BAM이 결합된 형태지만, 기본적으로 BAM과 BPM은 그 영역이 달라 독립적으로 갈 수 있는 솔루션이라는 데 비중을 두고 있다.
해외에서는 모토톨라, 캐나다금융 등이 사베인즈-옥슬리 법안 준수를 BAM을 통해 구현하는 사례를 확보, 국내 시장도 이와 유사하게 공략할 방침이다.
사베인즈-옥슬리 법안 해당 기업들인 국내 100여개 기업들 역시 BAM 도입이 가능할 것으로 보고 회계법인 공략을 준비하고 있다.
웹메소드코리아 박정우 이사는 “BAM을 특화시켜 사베인즈-옥슬리 법안 시장 공략에 적극 나설 계획며 이를 특화시켜 웹메소드 사베인즈-옥슬리 솔루션으로 갈 수 있을 것”이라고 말했다. 또한 BAM 구성에서 EAI가 필수적인 만큼 높은 수준의 EAI 통합까지 가지 않고 수집 기능만 지원하는 기능을 구성해 패키지화도 고려할 수 있다는 입장이다.
웹메소드코리아는 국내시장이 BAM이 충분히 적용가능하며 여건이 성숙됐다고 판단하고 있으며, BPM보다도 더 빠른 부각도 가능할 것으로 예상하고 있다.



◇ 한국마이크로소프트 / 비즈톡 서버 BAM 서비스
비즈톡 서버 2004, BAM․BRE 포함돼

한국마이크로소프트는 비즈톡 서버를 통해 BPM 및 BAM 시장을 공략하고 있다.
몇 년 전부터 휴먼 워크플로우(HWS)를 강화하면서 BPM 시장을 준비해 왔다. 비즈톡 서버 2004에서 BAM과 BRE가 포함됐고, 엔진으로 HWS가 강화됐다.
한국MS는 BPM 및 BAM 시장 역시 과거 메시징 서버인 익스체인지를 파트너들과 함께 협업시스템으로 발전 시켜온 것처럼 파트너를 중심으로 공략할 계획이라고 밝히고 있다.
여전히 플랫폼 벤더를 지향한다는 것. 국내에서는 아직 공식 BPM 협력사를 두지 않고 있으나 글로벌하게는 얼티머스, K2.net, 에이즐 포이트 등과 협력 관계를 맺고 있다.
한국MS는 비즈톡 서버에서 BAM 서비스 모듈을 제공하고 있으며 BAM과 BRE가 독자시장으로 갈 것으로 전망하고 있다. 단지 BAM 보다는 BRE의 영역을 더 비중 있게 보고 있다.
비즈톡 서버는 그동안 28개 고객과 36개 사이트를 확보하는 성과를 거두고 있으나 대부분 BPM보다는 EAI 성격이 강한 사례들이었다.
17개사 정도가 ERP와의 통합목적으로 비즈톡 서버를 사용하고 있기 때문이다. 그러나 작년 하반기부터 BPM용 도입이 증가세를 보이고 있다. 삼성전자 ‘리빙프라자’ PDP 부분 적용이 대표적이다. PDP의 온라인 구매의 경우 재고물량, 생산 가능 여부, 물류사 차량, 서비스 요원 스케줄 등 12~16개 사항 체크가 필요하다. 여기에 주문을 변경하게 되면, 가령 60인치에서 40인치로 변경할 경우 30단계 이상의 체크요소가 증가하게 되는데 이를 비즈톡 서버를 통해 관리하고 있다.
한국MS는 BAM 자체보다는 BPM 사례 확보에 관심을 가지고 있으며, 현재 약 10여개 사이트를 물망에 올려놓고 BPM 비즈니스를 진행하고 있다.



◇ 한국CA / 에이온 R 10
통합 BPM에 주력, BAM은 한 요소로 접근

한국CA는 기존 비즈니스 룰 엔진이던 ‘에이온’을 BRE, BAM, BPM 개념이 접목된 통합 BPM 솔루션으로 크게 변모 시켯다. CA의 통합 BPM 솔루션인 ‘에이온 R10’은 작년 9월 베타 버전이 발표된데 이어 올 2월에 정식 출시됐다.
한국CA는 현재까지 독자시장을 형성하고 있는 BRE가 향후에는 통합으로 갈 것으로 예상, 비즈니스 룰 엔진을 중심으로 BPM과 BAM을 접목했다.
한국CA는 에이온 R 10이 현재 BPM에서 논의되고 있는 워크플로우, BRE, BAM, EAI 개념들 중 EAI를 제외한 다른 요소들을 모두 통합시킨 가장 앞선 통합 BPM 제품이라고 강조하고 있다. 룰과 BPM이 동시에 공급돼 실시간 환경을 실질적으로 구현할 수 있는 구조를 갖췄다는 것이다.
한국CA 이종인 대리는 “실시간 구현이 비즈니스 룰만으로는 힘들어 워크플로우와 결합시켰으며 워크플로우, BRE, BAM에 집중하고 있다”며 “통합 BPM 기조 속에서 BAM은 한 요소로 가져갈 것”이라고 말했다.
한국CA는 BAM을 리포팅 요소로 받아들이고 있다. 다만 단순 모니터링이 아닌 KPI로 사용하기 위한 메시지를 전달하는 도구라는 것. 따라서 향후 BAM은 균형성과지표(BSC)나 활동기준 원가관리(ABC) 등의 영역까지 포함할 것으로 전망하고 있다. 그러나 이 모든 것은 BPM을 기반으로 할 것이라는 것이 한국CA의 예측이다.
한국CA는 통합 BPM을 앞세워 BRE를 중심으로 시장을 공략해 갈 계획이다.
BRE 시장의 경우 작년 1월부터 관련 비즈니스를 시작해, 국내 제품 발표가 다소 늦었다. 그러나 올해 들어 전략제품인 에이온 R 10이 출시되어 시장 공략이 활발할 것으로 기대하고 있다. 한국CA는 BPM 제품을 라이프사이클 관리(LCM) 제품군에 포함시키고 있다. LCM 제품군은 에이온, 포털, 모델링 툴, 형상관리 제품 등이 포함되어 있다.



◇ 티맥스소프트웨어 / 비즈마스터
BPM 플랫폼 개념 제시, 사례 확보에 주력

티맥스소프트는 최근 기존 EAI 툴 성격이 강했던 ‘비즈마스터’를 워크플로우와 EAI, BAM 기능을 구현해 BPM 솔루션으로 발표했다.
티맥스 역시 BPM 시장 공략에 있어 한국MS와 오라클과 같은 플랫폼 개념을 제시하고 있다. 그리고 BPEL을 기반으로 설계된 표준준수 제품이라는 점을 강조한다는 점에서 오라클 BPM과 비슷한 모습을 보여주고 있다.
티맥스가 말하는 플랫폼의 기본 취지는 개발 공수를 줄이자는 것. BPEL에 기반으로 BPM을 개발했고 여기에 현업 사용자들에게 보여주기 위한 도구로 워크플로우를 결합하고 추가로 EAI와 BRE, BAM이 추가됐다.
티맥스소프트 고희숙 팀장은 “티맥스는 표준에 일찍부터 주목하고 있다가 재작년 11월 BPEL 표준 발표 시점과 거의 동시에 EAI를 BPEL로 가자는 결정을 내렸다”며 “작년 6월 BPEL 중심으로 제품을 설계했고 현업들이 보기 힘들다는 문제가 있어 워크플로우를 추가해 제품을 발표했다”고 말했다.
티맥스의 경우 BAM은 BPM의 한 부분으로 가야한다고 보고 있다. BPM은 BAM이 없으면 지속적인 개선효과를 기대할 수 없다는 것이 주된 요인이다.
BAM이 확대되는 와중에 표준단위, 인터페이스를 만들어 가면 독자 시장 가능성도 충분하다고 인정하고 있다. 그러나 아직까지 BAM 제품이 각사 BPM에 최적화된 상태에서 크게 벗어나지 못하고 있어 시간이 걸릴 것으로 판단하고 있다.
티맥스 BPM은 룰이 적용된 사례까지는 확보하고 있으나 룰과 워크플로우가 구현된 사례는 아직 확보하지 못하고 있다. 내부적으로는 워크플로우까지 적용된 BPM을 제품 개발 버그 발견 업무에 적용하고 있다. 워크플로우는 화려한 UI를 선호해 현재 UI 강화 작업을 진행 하고 있다.
티맥스는 현 BPM 벤더 가운데 워크플로우 엔진과 EAI 엔진을 모두 가지고 있는 벤더 드물어 향후 핵심 경쟁력으로 부각될 수 있을 것으로 기대하고 있다

Posted by 아름프로


한눈에 딱 들어오네요. ^^
Posted by 아름프로
Business Intelligence의 목적은 똑똑하고(Intelligent) 빠르고 강하고 효율적인 조직으로 만드는 종합적인 업무정보분석체계를 갖추는 데 있다.


Business Intelligence :


하나의 흐름을 정의하는 key word는 시기적절, 유효적절하여 감탄스러울 정도로 그 시기의 흐름을 정확하게 투영하곤 한다. Business Intelligence(이하 BI)의 어의는 그 단어(흐름)가 생겨날 때의 특질을 반영하고 있다. “업무의 각 분야의 데이터로부터 현재까지의 데이터를 분석하고 미래의 계획을 세울 수 있는 통찰력을 얻게 하는 일련의 기능집합” (가트너). “정보분석체계” 정도의 정의가 가장 시의적절 하다고 보이며 단어의 탄생시기의 뜻과도 크게 달라지지는 않은 것 같다.


Posted by 아름프로
BPM(Business Process Management) 툴은 이름 그대로 비즈니스 프로세스의 현 상태 또는 향후의 모습을 모델로 나타내고 정보 시스템에 적용하기 위한 툴이다. 그러나 제품의 화면을 보면 워크플로우 툴, 일부 기능설명 그림을 보면 EAI 툴과 아주 똑같다.


비즈니스 프로세스를 관리한다는 것은...


비즈니스 프로세스 관리의 기본은 어떤 업무가 시작해서 완료까지 어떠한 흐름으로 진행되는지, 흐름의 단위(프로세스)의 연결을 그리며 거기에 어떤 문제가 포함되어 있는지를 확인하면서 새로운 프로세스가 필요한 경우에 가능한 한 다른 프로세스에 영향을 주지 않도록 흐름에 추가하는 등 변경, 재이용을 하면서 항상 현 상태를 파악하고

비즈니스 효율을 올리는 방향으로 흐름을 최적화 해 나가는 것을 말한다.  


단순한 업무를 소규모로 수행하는 정도라면 업무지침서만 만들어도 무난할지도 모른다. 조금 더 복잡한 경우에는 흐름을 그래픽하게 그리면서 컴퓨터에서 관리가 가능하게만 해도 좋을 것이다.

그러나 프로세스의 수가 많아지고 복잡함의 정도가 증가하면 업무 진척도의 감시가 어렵게 되어 워크플로우 툴의 도움을 빌리게 된다. 대부분의 경우에는 그룹웨어의 기능을 사용하게 될 것이다.  


비즈니스 프로세스가 더욱 복잡하게 되어 결국 정보 시스템의 힘을 빌린 업무도 일의 흐름에 포함시키면 워크플로우 툴의 가치는 더욱 높아지게 된다. 하지만 업무가 하나의 시스템으로 완결이 되지않고 복수의 시스템의 연계로 구성 되어지는 경우, 연계를 자동적으로 수행하는 구조가 아니면 효율을 올리는 것은 어려울 것이다.

거기서 시스템 연계의 구조가 필요하게 되고 연계하는 시스템 수가 늘어난다면 EAI가 필요하게 될 것이다.

그 구조를 일의 흐름에 포함시켜서 관리하기위해 BPM 툴이 선보이게 되었다.


실제로는 BPM은 EAI의 발전이라 할 수 있지만 그 역할 면에서  위에서 말한 것을 생각해 본다면 워크플로우 와 EAI의 다른 점을 쉽게 알 것이다.


비즈니스 환경의 변화로의 재빠른 대응, 업무 처리의 향상, 경영의사의 신속한 반영.....

기업 간의 경쟁이 치열한 지금 정보 시스템에 요구하고 있는 것은 변화에 민감하게 따라가는 스피드 이다.


업무부문의 관리자 이용하는 것이 BPM 툴이다.


BPM 툴에 대한 필요성은 2가지이다. 한 가지는 업무 프로세스를 계속적으로 최적화 해 나가고 싶다는 것과 다른 한 가지는 복수의 서로 다른 시스템의 연계를 합리적으로 이끌고 싶다는 것이다. 이 두 가지는 많은 경우 업무 프로세스를 최적화 하는데 시스템 간의 연계가 전제가 되며 시스템 간의 연계의 합리화를 진행하면 비즈니스 프로세스의 재구성이라는 상황으로 전개된다.


계층의 윗부분 일수록 상위 관리자(최고 상부는 경영층)가 사용하는 툴로 되어 있다.

BPM 툴은 EAI 그리고 파트너 기업의 정보 시스템과 연계하는 B2BI의 윗 부분에 위치한다.

BPM은 업무부문의 관리자가 사용하는 툴이다.  EAI는 정보 시스템 부문이 이용하는 툴이라 말 할 수 있다.

BPM의 위에는 BI(Business Intelligence),  BAM(Business Activity Monitoring)이라는 분석 툴이 위치하고 있다.




BPM 툴의 도입에 따른 장점


그러면 이러한 BPM 툴의 도입에 따른 장점을 정리해 보자.

우선 첫 번째로는 현 상태의 업무의 흐름구조가 시각적으로 명확화 할 수 있는 것이다.

경영효율을 올리기 위한 문제점을 여기서부터 발견하고 개선으로 연결시킬 수 있다.

두 번째는 비즈니스 프로세스의 변경, 신규추가가 간단히 이루어진다는 것이다. 이것에 의해서 비즈니스 환경의 변화에 대응한 비즈니스의 변경과 새로운 비즈니스의 구축이 단기간에 이루어진다.


세 번째 장점은 모니터링 기능과 분석 기능에 의해서 현 상태의 파악과 개선 포인트의 도출을 꾀할 수 있다.

실시간으로 업무진행의 감시가 가능하고 비즈니스 프로세스의 문제점을 재빠르게 발견하는 것이 가능하다.

네 번째 장점은 대부분의 시스템을 연계해서 업무를 자동화하는 경우, 연계 프로그램을 개별적으로 작성하는 것과 비교해서 BPM 툴 (내장된 EAI 기능)을 이용하는 것이 저비용으로 마무리 될 것이다.

현재의 이 점을 주안점으로 해서 BPM 툴을 도입하는 경우가 제일 많다.


발전 형태에 의한 다른 3가지의 종류의 BPM 툴

BPM기능을 강조하는 툴에는 발전된 형태에 따라서 3 종류로 나눌 수 있다.


(1) 워크플로우 타입

서류의 승인 플로우, 작업자의 작업 플로우 관리에 주안점을 두고 워크플로우 툴에서 파생된 BPM 툴. Savvion technology의 Savvion Business Manager가 전형적인 예이다.


(2) EAI 타입

시스템 간의 연계를 수행하는 미들웨어인 EAI툴의 기능으로 정보 시스템 부문이외에 상위 관리자도 프로세스 치환 등의 설계가 수행되는 기능이 추가 되어진 BPM 툴.

예를 들면 리가시 시스템 등의 연계에 있어서 오래된 아이비엠의 WBI Server와 웹 서비스에 의한 통합을 제공하는

웹 메소드의 web Methods Integration Platform 등이 있다.
    

(3) 웹 어플리케이션 서버 타입

J2EE의 시스템 연계기술 JCA 등을 이용해서 어플리케이션 서버 상에서 EAI를 실현 할 수 있다.

여기에 BPM 기능을 추가한 툴이 BEA의 Web Logic Integration이 그 예이다.


이 종류들의 차이점은 첫 번째로써 비자동화 프로세스를 포함하고 있는지 없는지의 차이점과 또 하나는 기존 시스템의 연계를 얼마만큼 중요시하는가의 차이라고 말할 수 있다.  

여기서 비자동화란 사람이 작업하는 것을 나타내며 기계화, 자동화가 불가능한 프로세스를 가리킨다.


결국, 시스템 연계를 그다지 고려하지 않고 비자동화 프로세스를 관리하고 싶은 경우에는 (1)번 타입이고 이미 일부에서 복수시스템 연계를 꾀하고 있는 경우라면 (2)번 타입,  어플리케이션 구축을 하여 기존 시스템을 대체하면서 다른 시스템의 연계를  꾀하는 경우에는 (3)번 타입이 적당하다고 말할 수 있다,

그렇지만 (2), (3) 타입에서도 비자동화 프로세스의 관리를 할 수 있는 툴을 준비, 또는 표준으로 하고 있는 경우가 있어 이 점은 툴을 선택할 때 조심해야 한다.


Plan→Do→Check→Action의 매니지먼트 사이클


BPM 툴의 대부분은 비즈니스 프로세스를 모델화 하는 워크플로우 설계, 관리기능과 시스템 간의 연계를 수행하는 EAI 기능의 모두를 갖추고 있다. 이 기능에서 수행하는 것은 비즈니스 프로세스의 매니지먼트 사이클을 만들어 내는 것이다. 매니지먼트 사이클은 PDCA 사이클 (Plan, DO, Check, Action)이 기본이지만 BPM의 경우는

프로세스의 [모델링]-> [실행]-> [모니터링]->[분석]의 흐름으로 되어 있다.



예를 들어 요구서 발행과 출하의 프로세스에 변경이 있는 경우에도 이 메인 프로세스 자체에는 영향이 없다.

이처럼 모델링 기능에 있어서 프로세스를 GUI 화면을 사용해서 설계하고 여러 가지 처리와 서브 프로세스의 호출 수행하는 것이 가능하다. 각종 비즈니스 오퍼레이션과 서브 프로세스를 준비해 둔다면 새로운 비즈니스 프로세스 설계와 변경, 치환이 간단해진다.

이 같은 모델링 기능은 당연히 모든 BPM 툴이 갖추고 있다. 비자동화 프로세스도 관리할 수 있는 Savvion Business Manager는 EAI기능을 가지고 있지 않은 모델링과 모니터링, 분석에 특화시킨 툴이지만 다른 시스템과의 어댑터를 사용한 연계가 가능하다.


모니터링 분석

실행후의 모니터링과 분석기능을 툴 안에 가지고 있는 제품은 한정되어 있지만 조금씩 확대되어 오고 있다.

예를 들어 아이비엠의 경우는 WBI에 최근 매입한 Holosofx사의 BAM 툴을 WBI Modeler and Monitor를 제품에 내장하고 있다. 이것은 모델링 툴이지만 비즈니스 프로세스의 액티비티 로그를 입력데이터로 취급하여 프로세스의 감시, 관리를 수행하는 모니터링 툴이기도 하다.


또 웹 메소드에서는 web Methods Integration Platform와 연계해서 실시간으로 데이터를 취득해서 여러 가지 분석을 수행하는 web Methods Optimize를 판매하고 있다.

비즈니스 프로세스의 모델링과 분석에 멈추지 않고 KPI(Key Performance Indicator)에 의한 비즈니스 퍼포먼스 평가 등을 가진 툴을 포함시키면 BPM의 가치를 더욱 올릴 수 있다고 말한다.


시스템연계의 장점과 그 방법


BPM의 또 장점중 하나인 시스템간의 연계기능은 EAI 툴의 경우와 아주 똑같다.

시스템과 시스템을 연결하는 연계 프로그램의 수를 1대1로 나름대로 접속하는 경우와 비교해 큰 폭으로 줄이는 것을 할 수 있다는 점이다.

복수의 시스템 (N)이 있고 나름대로 상호간 연계되어진 경우,  계산 해보면 n * (n -1) /2 개의 연계 프로그램이 필요하게 된다. 이것으로는 연계하는 시스템이 많을수록 개발비용이 늘어나 버린다.

여기서 복수 시스템 부분을 “Hub”라고 부르는 통합용 툴에 접속해 Hub 안에서 연계처리를 수행하면 개발하는 연계프로그램의 수를 N개로 끝낼 수 있다. 연계 프로그램은 주요한 어플리케이션에 대해서는 “어댑터” 로 판매되고 있는 것으로 구입해서 연결만 시키면 간단하게 저비용으로 운영이 가능하다.

현재의 오픈 시스템에서는 J2EE의 표준연계 사양인 JCA를 이용한 연계와 웹 서비스를 이용한 연계가 주목 받고 있다. 자바 기반의 어플리케이션인 웹 로직 서버를 플랫폼으로 한 WebLogic Integretion, 웹 메소드의 webMethods Integration Platform은 이런 타입의 EAI를 실현하는데 대표적인 제품이다.

표준사양을 기반으로 하는 연계방법은 저비용으로 EAI의 구축이 가능하다.

더욱이 이런 타입의 연계는 트랜잭션의 보증이 어렵다는 결점도 지적되고 있지만 BEA에서는 트랜잭션 처리용의 미들웨어 사용에 의해 문제가 없다고 말하고 있다. 모든 시스템이 Hub에 접속하는 형태로 정리하는 것으로 접속이 실뭉치 같은 상태가 되는 것을 방지할 수 있다.


BPM 툴의 선택방법

1. 비자동화 프로세스를 포함하고 있는가?


기본적으로는 BPM은 자동적인 처리에 의한 비즈니스 프로세스를 대상으로 하고 있다.

그러나 워크플로우 툴에서 발전해 온 제품 중에는 시스템 연계 프로세스도 비자동화 프로세스도 함께 모델링이 가능하고 모니터링과 분석이 수행되는 것도 있다. 또한, 종래에 자동처리만을 대상으로 해온 EAI 제품에서도 최근 비자동화를 포함시켜서 관리 할 수 있는 기능을 추가하고 있는 것도 있다. 우선 이점을 확인하자.


2. 기존 시스템을 이용할 것인가? 대체 할 것인가?


기존 시스템을 대체하는 경우라면 어플리케이션 서버 제품으로 어플리케이션 개발과 BPM 도입을 병행하는 것이 비용 면에서 유리하다.

3. 자사의 프로세스만인가? 아니면 외부 시스템 등도 함께 관리가 가능한가?


기업 간의 B2Bi가 확대되는 가운데 자사내의 시스템 밖에 관리 할 수 없는 툴에서는 막막한 경우가 있을 수 있다.

특히 다른 이유가 없다면 향후에 대해서 생각 한다면 외부기업 시스템도 관리 할 수 있는 툴이 좋을 것이다.

4. 프로세스의 변경이 유동적으로 수행되는가?

설계한 비즈니스 프로세스의 운용 중에 변경이 필요하게 된 경우에 신속하게 모델을 수정할 수 있는지를 보고 수정결과가 업무에 즉시 반영 할 수 있는지를 확인한다. 유동적인 변경으로 대응가능이 가능한지 아닌지를 확인 할 필요가 있다.

5. 모니터링과 분석을 위한 기능, 추가해서 사용할 수 있는 툴은 있는가?

  비즈니스 프로세스의 PDCA 사이클의 형태로 만들고 계속적으로 최적화를 꾀하는 경우에는 모니터링과 분석을 위한 기능이 필요하다. 반드시 툴 자체에 갖추고 있지 않아도 되지만 주변에 이런 목적의 툴이 준비되어 있는지 확인 해 둔다.

또한 호환성이 좋은 BAM, BI 툴 등도 찾아보는 것이 좋다.

6. 모니터링 툴의 GUI 등의 조작성, 시각적 표현성이 어떤가?


BPM은 전문기술자가 이용하는 툴이 아니고 업무 관리책임자가 이용하는 것이므로 충분히 조작이 알기 쉽고 숙련되기까지의 시간을 최소화 할 수 있는 툴을 선택해야 한다.

7. 프로세스 템플릿이 준비되어 있는가?


BPM은 자신이 비즈니스 프로세스를 정의 할 수 있는 것이 매력이지만 경우에 따라서는 일반적인 프로세스를 본보기(표준)로 사용하고 싶은 경우가 있을 것이다. BPM에서는 비즈니스 프로세스가 재이용이 가능한 것이 특징이다. 이것을 템플릿이라 하는데 연습이나 이해의 목적으로도 활용이 가능하다.

가능한 한 여러 가지의 템플릿이 있으면 좋다.

8. 연계 어플리케이션에 맞는 어댑터가 준비되어 있는가?


연계에는 웹 서비스 등을 이용하는 경우와는 다르게 연계용 어댑터가 필요하다.

ERP용 등 주요한 제품에는 어댑터가 준비되어 있지만 그 가용성에는 상당히 커더란 차이가 있다.

아이비엠의 경우 40게 이상의 어댑터가 준비되어 있고 분기별에 한번 씩 버전 업을 하면서 여러 개를 추가하고 있다.

9. JCA와 웹 서비스에서의 연계가 가능한가?


표준기술에 의한 연계는 향후 보급이 원할 할 것으로 생각된다. 특히, 웹 서비스의 경우는 부가가치가 높아질 가능성이 크다. 이것에 대해서 지원되고 있는가, 혹은 이후에 예정으로 되어 있는지도 확인 해두는 것이 좋다.

10. 트랜잭션 처리의 안정성과 성능은 어떤가?


웹 서비스의 경우는 특히 트랜잭션의 보증이 현재의 시점에서는 어렵다고 얘기한다.

또한 JCA를 이용하는 경우도 마찬가지로 성능 면에서도 불안하다는 점이 지적되고 있다. 이것을 보조할 수 있는 툴을 이용할 수 있는가를 포함해서 확인해야할 점이다.
Posted by 아름프로

Spring Web Flow

2005. 5. 17. 13:01


alt="Spring Web Flow">





May 2005



Discuss this Article






Introduction


Have you found as your web application gets more complex, understanding and managing the page flow – the orchestration that drives your application use cases – gets harder and harder? Are you tired of being forced into very particular ways of doing things that dont give you much reuse? Do you feel youre spending too much time developing your own approaches to generic problems like session state management?


Enter Spring Web Flow.


What is Spring Web Flow?


Spring Web Flow (SWF) is an emerging module of The Spring Framework. The module is part of Springs web application development stack, which includes Spring MVC.


Spring Web Flow aims to be the best solution for the management of web application page flow. It is a powerful controller for use when your applications demand complex controlled navigations, such as wizards, to guide the user through a series of steps within a larger application transaction.


An example of such a controlled navigation is illustrated as a UML State Diagram below:



Figure 1 - An Example Flight Booking Flow


Astute readers will recognize this as a typical flight booking flow – the kind you participate every time you book an airline reservation on-line.


Why Does Spring Web Flow Exist?


In traditional web applications, page flows like the one above are not explicit—they are not first class citizens. Take a webapp built on Struts, for example. To implement a page flow in Struts, most developers build on what the framework provides them: actions and views. In this case, a single action is associated with a specific request URL. When a request comes in at that URL, the action is executed. During execution, the action performs some processing and then selects an appropriate result view for display. Its that simple.


So to implement a multi-step page flow in Struts, individual actions are chained together through the various views. Action URLs to process different events like back or submit are hard-coded into each view. Some form of ad-hoc session storage is used to manage flow state. Redirect after post is used to prevent duplicate submissions, etc.


Although this is a simple and functional approach, it has a major disadvantage: the overall page flow of the web application is not clear from looking at the action definitions in the struts-config.xml file. You cant see the forest – the flow – from the trees – the many action and view definitions. Flexibility also suffers since actions and views cannot be easily reused. Finally, you simply have to do too much work—it should be easier!


Spring MVC offers a slightly higher level of functionality: form controllers that implement a predefined page flow. Two such controllers are provided out of the box: SimpleFormController and AbstractWizardFormController. However, these are still specific examples of a more general page flow concept.


Tapestry and JSF use an event-driven approach at the page level, rather than the request level, where each page and its backing controller logic are kept together. However, neither provides first-class support for a logical page flow with a well-defined lifecycle that spans several pages and potentially different paths. As youll see, the lifecycle of such a page flow is longer than a single request, but shorter than a session.


This is where Spring Web Flow comes in, allowing you to represent the page flow of a web application in a clear and simple way, and reuse it anywhere, including environments like Struts, Spring MVC, Tapestry, JSF, and even Portlets.


Advantages


As you will see, Spring Web Flow offers several advantages:



  • The page flow in a web application is clearly visible by looking at the corresponding web flow definition (in an XML file or Java class).

  • Web flows are designed to be self contained. This allows you to see a part of your application as a module you can reuse in multiple situations.

  • Web flows capture any reasonable page flow in a web application always using the same consistent technique. You're not forced into using specialized controllers for very particular situations.

  • Finally, a web flow is a first-class citizen with a well-defined contract for use. It has a clear, observable lifecycle that is managed for you automatically. Simply put, the system manages the complexity for you and as a result is very easy to use.


How does Spring Web Flow Work?


For now it suffices to say that a web flow is composed of a set of states. A state is a point in the flow where something happens; for instance, displaying a view or executing an action. Each state has one or more transitions that are used to move to another state.


A transition is triggered by an event .


The Book Flight Sample Web Flow


To demonstrate what a web flow definition looks like, the following piece of XML captures the flight booking process illustrated in the UML state diagram above:




"http://www.springframework.org/dtd/spring-webflow.dtd">


























then="enterPassengerInformation" else="displayReservationVerification"/>




































Figure 2 – A XML-based Flight Booking Flow definition


As you can see, just from scanning the XML definition, the logical flow driving the booking process is clearly discernable, even if you dont yet know about Spring Web Flow implementation details.


And if you look a bit closer, youll see two subflows that spawn child processes of the booking flow. The first subflow guides the user through entering his passenger information. The second has the user make his seat assignments. The ability to nest flows that act as mini application modules is one of the most powerful capabilities of Spring Web Flow.


You could show the definition above to a business analyst and shed probably get it. Better yet, you could engineer a visual diagram from this definition and present that to a business analyst for review. Tools to do exactly this are already appearing.


The Book Flight Flow Explained


The next part of this article breaks down the key parts of the above Book flight definition, and provides supporting dialog that illustrates how Spring Web Flow works.


The Flow Definition

Starting with line 1 of the XML-based flow definition:




...


The webflow element defines the flow, specifying its id and start-state. The id is simply a unique identifier. The start state is the first state to transition to when a new flow session is activated at runtime.


So for this business case, when a new bookflight session is activated, it transitions to the obtainTripInfo state.


The Obtain Trip Info Action State

Moving on to the obtainTripInfo state definition.









Recall that when states are entered, behavior happens. As youll see, there are different state types that execute different behaviors. An action state, like obtainTripInfoabove, executes an action when entered. That action returns the logical result of its execution, and that result is mapped to a state transition. Its that simple.


So for this business case, obtainTripInfo, when entered, executes the bindAndValidate method on the Action implementation with the bookingActions identifier. This method binds form input from the browser to a Trip domain object and validates it. If that process is successful, the suggestItineraries state is entered. If an error occurs, the tryAgain state is entered.


The Booking Action

When using Spring Web Flow with Spring IoC, the bean attribute of the action element refers to the name of an Action implementation exported in the Spring Application Context. Here, the bookingActions bean definition looks like this:



web-context.xml

class="org.springframework.samples.bookflight.BookingActions">



This allows our action implementation to be managed by Spring and configured via dependency injection.


The Suggest Itineraries Action State

Now take a look at the next action state that, given a bound and validated Trip object as input, returns a collection of suggested itineraries:








The actual implementation code required to make this happen is straightforward:



public class BookingActions extends FormAction {
...
public Event suggestItineraries(RequestContext context) {
Trip trip = (Trip)context.getRequestScope().getAttribute("trip");
Collection itineraries = bookingAgent.suggestItineraries(trip);
context.getRequestScope().setAttribute("itineraries", itineraries);
return success();
}
}

When the suggestItineraries state is entered, the suggestItineraries method is invoked. The other action states work in exactly the same way: entering the state invokes a method on the target action bean.


The Display Suggested Itineraries View State

Once a collection of suggested itineraries is returned, the next step has the user review them so she may select the best one. This is accomplished by the following state definition:








As you can see, displaySuggestedItineraries is a view state—a state type we have not yet discussed. A view state, when entered, causes the executing flow to pause, and returns control back to the client with instruction to render the configured view. Later, after some user think-time, the client signals an event describing what action the user took. That resumes the flow, and the event that occurred is mapped to a state transition, which takes the user to the next step in the flow. Again, its that simple.


So for this business case, when the displaySuggestedItineraries state is entered the suggestedIteneraries view is rendered and control returns to the browser. The user then decides which itinerary she wants and clicks the select button. That signals the select event, passing in the id of the selected itinerary as an event parameter.


The user may also choose to startOver, at which time the flow transitions to the cancel state.


Note it is the responsibility of the client environment the flow is hosted in to map the requested view name, like suggestedItineraries, to a renderable view template, like /WEB-INF/jsp/suggestedIternaries.jsp. For example, in Spring MVC, the FlowController does this using the familiar ModelAndView and ViewResolver constructs. In Struts, the FlowAction does this using the familiar ActionForward.


Client Side State

At this point you might ask:


since the executing flow is paused when a ViewState is entered, and control is returned to the browser, how is the same flow picked up and resumed on subsequent events?


The answer is the client tracks the unique idof the executing flow, and provides it as input when the next event is signaled. This is typically done using a hidden form field.


For example, in a jsp:



">

The Is Passenger Info Required? Decision State

After the user selects the Itinerary she wants, the flow has to make a contextual decision about where to go next.


Specifically, if the user has not logged in, or she has logged in but wishes to confirm her passenger information – like the credit card she will use – the flow should allow her to enter that information. On the other hand, if she has already logged in and wishes to go straight to the booking page, the flow should skip this optional step.


Basically, a dynamic decision has to be made that takes into account the users information and preferences.


The decision state is perfect for this. See the definition below:





then="enterPassengerInformation" else="displayReservationVerification"/>


The Enter Passenger Information SubFlow State

The process of managing passenger information is logically independent of the booking process. It is one part within that process, yes, but it certainly makes sense a user would want to edit her information outside of the booking context.


Subflow states facilitate this. When a subflow state is entered, a child flow is spawned. The parent flow is suspended until the child flow ends. This lets you view your application as a set of self-contained modules – flows – that you can easily embed in multiple situations in a consistent manner.


Take a look at the enterPassengerInformation subflow state:










The flow attribute is the id of the flow to spawn when this state is entered. The attribute-mapper element maps attributes to and from the subflow. Input mappings map attributes down to the subflow. Output mappings map attributes back up to the parent flow when the subflow ends. As you can see, expressions (in this case OGNL) are also supported.


So for this business case, when the enterPassengerInformation state is entered, the passenger flow is spawned. The passengerId attribute is passed down to the flow as input. From there, the subflow does whatever it wants. Its a black box as far the parent flow is concerned. When the subflow ends, the parent flow resumes, responding to the ending result to determine where to go next—in this case, to reservation verification.


The Display Confirmation End State

There is one last core state type that has yet to be discussed: the end state. When an end state is entered, the active flow session terminates. Upon termination, all resources associated with the flow are cleaned up for you automatically.


Below is the displayConfirmation end state that displays confirmation after an itinerary is successfully booked:




When this state is entered, the bookflight flow ends and the reservationConfirmation view displays.  Because the bookflight flow was acting as the root flow, and not a subflow, it and any allocated resources are automatically cleaned up.


Note: had the ending flow been acting as a subflow, the entered end state is treated as a subflow result the resuming parent flow can respond to.  More specifically, the entered end state ID is used as grounds for a state transition in the resuming parent flow's subflow state.  You can see this in action by taking a look at the "enterPassengerInformation" subflow state definition.  Note how it responds to the "finish" result of the subflow, which corresponds to a "finish" end state within the passenger flow.


Flow Deployment


So far youve learned what Spring Web Flow is all about, and youve seen an example of a realistic flow definition. What you havent seen yet is how to deploy that flow definition for execution in a particular environment, like Spring MVC in a servlet environment.


Doing this is a cinch. Heres all you have to do with Spring MVC:













This automatically exports the bookingFlow at the /booking.htm URL for use in a servlet environment.


Advanced Topics


The following section introduces some of the more advanced features of Spring Web Flow.


Flow Execution Listeners


The FlowExecutionListener construct is an observer that allows you to listen and respond to the lifecycle of an executing flow. You can use this feature to do anything from state precondition and post condition checks, to auditing and security.


Flow Execution Storage Strategies


The mechanism by which the state of an executing flow is saved and restored is fully pluggable. HttpSession-based storage is the default, and SWF provides two other storage strategies out of the box: one using server-side continuation-based session storage, another using full client-side serialization. Defining your own custom storage, for example to store flow state in a Database, is trivial.


When Is Spring Web Flow Right For You?


It should be noted that Spring Web Flow is not a one-size-fits-all solution. As youve seen, its a stateful system that automates the management of page flows that drive business processes. It should not be used when simpler, stateless solutions are more appropriate. For example, it should not be used where sites require free navigations, where the user is free to click around anywhere they please. Spring Web Flow is designed to power controlled navigations, where the user is guided through a process with a clear business goal and lifecycle.


To further make the use case more concrete, here are some examples of good flows, where the SWF system would be appropriate:



  • Book a flight

  • Pay your taxes

  • Apply for a loan


Here are some examples where Spring Web Flow would not be appropriate:



  • Index pages

  • Welcome pages

  • Menus

  • Simple form flows (one page)


Spring Web Flow is meant to be used as a compliment to traditional controllers within any web environment, such as Spring MVC, Struts, Tapestry, Web Work, JSF, or Portlets. A single site should combine use of simple controllers with web flows where appropriate.


Road Map


Spring Web Flow 1.0 final will be released with Spring 1.3, scheduled right before JavaOne in June. Between now and then, expect regular, stable-for-development-use preview releases. The offering is already quite mature in terms of feature set and sample applications.


As the development team pushes closer to a final release, here are some of the most important features we will be working on:


Integration


As a standalone library, Spring Web Flow is a strong fit for integration with other frameworks. Out of the box Spring MVC, Struts, and Portlet MVC integration is already provided. JSF and Tapestry integration are expected by the final release.


Flow Management


With Spring 1.2, exporting beans in an MBeanServer for management and monitoring is easy. A strongly typed FlowExecutionMBean management interface already exists, and we plan to extend that so global statistics on all flows executing on the server can be centrally monitored through a JMX console.


Pluggability


Every construct in the system will be made pluggable for easy extension and customization, even from the xml definition. This includes States and Transitions, among other concepts.


Compensating Transactions


Supporting features and sample applications demonstrating use of compensating transactions to rollback previously committed work during execution of a flow is of high interest to us.


Conclusion


Spring Web Flow is a powerful solution for managing controlled navigations that drive business processes. And its fun to work with. If you havent tried it already, what are you waiting for?


References


Spring Web Flow is covered in the Core Spring training course offered by Interface21 - http://www.springframework.com/training


The Spring Framework, http://www.springframework.org


The Spring Web Flow Wiki, http://opensource.atlassian.com/confluence/spring/display/WEBFLOW/Home


The kdonald blog, http://www.jroller.com/page/kdonald


Struts, http://struts.apache.org


Java Server Faces, http://java.sun.com/j2ee/javaserverfaces/


Tapestry, http://jakarta.apache.org/tapestry


WebWork, http://www.opensymphony.com/webwork/


JMX, http://java.sun.com/jmx


JavaOne, http://java.sun.com/javaone/



Biographies


Keith Donald is an Interface21 principal and a core Spring Framework project member. An experienced developer and mentor, Keith has built applications for customers spanning a diverse set of industries including banking, network management, information assurance, education, and retail. He specializes in translating business requirements into technical solutions. Keith is the founder of the Spring Rich Client Project and co-lead of Spring Web Flow with Erwin Vervaet. Lately you can find him leading Spring Training courses across the US and abroad, and as a guest speaker on Spring with the NoFluffJustStuff (NFJS) tour.


Erwin Vervaet is a software engineer with a keen interest in applying modern IT concepts and tools. He has been using the Java language since 1996, and has a master's degree in computer science from the Katholieke Universiteit Leuven in Belgium. He has been involved in IT research, e-commerce projects, open source initiatives, and industrial software systems. Erwin currently works as an independent consultant.





PRINTER FRIENDLY VERSION



Posted by 아름프로
- 단위테스트가 만병통치약은 아니다 -

TDD나 Unit 테스트와 관련한 책들을 보면, 이를 하면 모든 것이 해결되는 것처럼 이야기한다.
특히나, 이러한 테스트를 통해서 모든 문제가 해결되다고 말한다.
물론, 이를 통해서 추후에 발생될 문제에 대해서 사전에 점검하는 차원에서는 분명히
필요한 것이 옮은 것임에는 분명하다.

한책에는 자신이 한 테스트에 대해서는 우선 믿어야한다라는 것으로
책의 시작부분을 다루고 있다. 이 책에서 말하듯 이러한 믿음 없이는 어떠한 테스트를
하더라도 시간낭비밖에 안될 수도 있다.

하지만, 지나친 믿음은 자칫 잘 못된 결과에 따른 추후에 큰 문제로 발생될 수 있다는
것도 이야기는 해야할 듯 싶다.

문제가 발생되더라도 단위테스트 소스들을 통해서 문제의 위치를 쉽게 찾아 고칠 수
있다고는 말하지만, 여기엔 크나큰 함정이 하나 있슴도 알아야 될 것이다.

이 단위테스트라는 것 또한 그냥 단순히 테스트를 만들 수 있는 것이 아니라는 점이다.
어떤 것을 테스트 해야하는지 어떤 결과가 나오는지에 대한 여러 환경적이거나 예측
할 수 있는 부분까지의 고려등이 반영이 되어야 된다는 점이다.

쉽게 말해서 "어설픈 단위테스트는(어설픈 테스트에 대한 설계) 안하니만 못하다"란 것이다.
단위테스트는 단순히 작은 단위로만 짤라서 그 기능만을 테스트 하는 것이라고 착각을
하기 쉽지만, 그 작은 조각이 전체에서는 핵심 부분이 될 수도 있는 것이기에 그러한
것까지도 많은 고민과 신경을 써야 한다는 것이다.

TDD나 Agile쪽에 이야기하듯 단위테스트는 마지막이 아닌, 테스트하면서 코드를
만들어나가는 것이라고는 하지만, 무작정 시작을 통한 코드와 내용을 추가는
조심해야할 부분이며 이것은 자칫 스스로의 무덤을 파는 길임을 잊지 말아야 한다는 것이다.

고객의 요구사항에 대한 분명한 청사진을 이해하고 기본적인 시나리오쯤은 인지하고
그리고 이에 대한 큰 흐름과 내용은 이해를 하고나서 그래도 기본적인 작업들이 이루어
져야 될 것이다. 물론 현업에서는 테스트코드부터 바로 뛰어드는 어리석은 작업을
하시는 분들이 없으리라 믿지만, 최근에 쏳아져 나오는 책들에는 이러한 것들에 대해서는
언급을 하고 있지 않기에 새롭게 이쪽에 대해서 시작을 하는 분들에게는 자칫 만병통치
약으로 믿었던 것에서 병을 얻게 되지 않을까 하는 생각에서 글을 써본다.

일단 일을 시작하는 것은 중요하지만, 그래도 한번쯤은 더 생각하고 실행하는 지혜 또한
잊지 말아야할 대목일 것이다.

혹시 또 오해가 있을지 몰라서 적자면,
단위테스트가 나쁘다라는 말은 아님을 분명히 밝힌다.
너무나도 훌륭한 방법중에 한가지이지만 자칫 잘못 생각할 수 있는 부분을
집고 넘어가고픈것 뿐이다.
Posted by 아름프로
직접써야되는데... 게으른 스머프이다보니.. ㅡㅡ;;
네이버에 좋은 글이 있기에 퍼봅니다.

===========================================

우선 인터페이스라고 하면 해당하는 메소드에 대한 선언을 가지고 있죠.

해당 인터페이스를 구현하면 비교의 역할이 있음을 알려주고, 해당 타입으로 캐스팅 정의할 수 있도록 처리를 해줍니다.

즉.. 다음과 같은 형태가 되는거죠.

public class A implements Comparable {
// Return 타입 : 음수(작은경우), 0(같으면), 양수(크면)
public int compareTo(Object o) {
.......;
return int값;
}
}

인터페이스를 상속받았으므로 해당 클래스가 compareTo()메소드를 정의하도록 되어있죠. 따라서 비교는 프로그래머가 정의를 하게 됩니다.

그럼 사용은 어떻게 할까요..
public int insertNode(Comparable key) {
A a = new A();
....; // 처리로직
return a.compareTo(key);
}

위에서 볼 부분은 물론 a.compareTo(key);부분이죠..
a는 Comparable를 구현했으므로 비교가 가능하겠죠.
key 파라미터로는 A클래스가 오면 됩니다. Comparable 인터페이스를 구현했으므로 ClassCaseException이 발생하지는 않겠죠.

만약 B라는 클래스도 위의 A클래스처럼 Comparable 인터페이스를 구현한다면..
public int insertNode(Comparable key) {
B b = new B();
....; // 처리로직
return b.compareTo(key);
}
와 같이 사용해도 아무런 문제는 없겠죠. A클래스와 마찬가지로 B클래스도 Comparable 인터페이스를 상속받았으니까요..

따라서 insertNode()라는 메소드를 서로 다른 클래스에서 Comparable를 구현한 어떤 클래스던지 동일한 메소드명으로 사용이 가능하게 되는거죠.

아래와 같이 A나 B클래스 내부에 정의를 할수도 있습니다.
public class A implements Comparable {
......
public int insertNode(Comparable key) {
....; // 처리로직
return this.compareTo(key);
}
}

public class B implements Comparable {
......
public int insertNode(Comparable key) {
....; // 처리로직
return this.compareTo(key);
}
}

자바 API에는 Serializable이나 Cloneable과 같이 단순히 역할을 정의함으로써 JVM에서 처리하도록 표시만 해주는 Marker Interface가 있는가 하면, Comparable 인터페이스처럼 공통적인 역할을 제시하고 메소드를 필요에 따라 구현하도록 하는 Interface도 있습니다.

위의 인터페이스 용도는 대부분의 자바API가 그런 것처럼 클래스나 인터페이스명에 그대로 나타납니다. 즉 Comparable은 '비교할수 있는..'기능을 정의한 인터페이스입니다.
Posted by 아름프로
ECIF(전자상거래 표준화 통합 포럼)에서 국제 표준을 국내 실정에 맞게 개발한 ECIF 규격(ebXML 레지스트리 V2.1 서비스 기능 정의서)이다.

Posted by 아름프로
ECIF(전자상거래 표준화 통합 포럼)에서 국제 표준을 국내 실정에 맞게 개발한 ECIF 규격(ebXML 레지스트리 V2.1 정보 모델 기능 정의서)이다.
Posted by 아름프로
ECIF(전자상거래 표준화 통합 포럼)에서 국제 표준을 국내 실정에 맞게 개발한 ECIF 규격이다.
    UDDI 3.0 레지스트리 시스템의 구현에서 지원해야 할 프로그래밍 인터페이스와 이 인터페이스를 통해 교환되어지는 SOAP 메시지의 규격과 기능들 중에 기존의 UDDI 2.0에 추가된 API들을 정의한다.

Posted by 아름프로
ECIF(전자상거래 표준화 통합 포럼)에서 국제 표준을 국내 실정에 맞게 개발한 ECIF 규격이다.
    UDDI 3.0 API를 통해 UDDI 3.0 레지스트리에서 저장하고 관리되며, 교환되는 자료 구조 중에서 기존의 UDDI 2.0 레지스트리에 추가된 구조들을 정의한다.

Posted by 아름프로
ECIF(전자상거래 표준화 통합 포럼)에서 국제 표준을 국내 실정에 맞게 개발한 ECIF 규격이다.
    웹 서비스 이용에 필수적인 웹 서비스 레지스트리를 안정적으로 운영하기 위해 OASIS UDDI 3.0 레지스트리 표준에 근거하여 웹 서비스 레지스트리에 대한 구축 및 운영 지침을 수립하고 이에 대한 세부사항을 규정함으로서, 향후 웹 서비스를 기반으로 한 전자 거래 기술을 활성화시킬 수 있도록 한다.

Posted by 아름프로
ebXML 의 Registry의 서비스를 웹 서비스의 입장에서 추상적으로 기술한 WSDL(Web Services Description Language) 입니다. 웹서비스에 관심있으신 분들은 참고 하시길 바랍니다
Posted by 아름프로
오아시스에서 3월 13일자로 ebXML Reg/Rep spec 3.0 Committee 버전이 나왔습니다. 참고 하시기 바랍니다.
PS: 아마 정식 버전과는 별 차이가 없을 것으로 예상됩니다.

출처 : remko

Posted by 아름프로
본 지침은 한국전자거래진흥원에서 2003년도 2월에 개발하여 발표한 전자문 서 개발 가이드라인의 개정판에 해당된다. UN/CEFACT에서 개발한 ebXML 코어 컴포넌트 기술 규격 2.01버전에서 제시하고 있는 방법론을 완전히 준용하였으며, UN/CEFACT ATG그룹에서 개발한 XML Naming & Design 문서는 몇몇 규칙과 관련하여 국내에 맞게 수정이 이루어졌다.  

국내 각 업종/부문에서 개발되는 전자문서를 보다 효과적으로 개발하기 위한 방안을 개발자들에게 제공한다.  

*공청회 및 한국전자문서교환위원회(KEC)에서 승인된 이후에 정신버전의 책자를 배포할 예정입니다.

출처 : remko

Posted by 아름프로
본 가이드라인은 사용자가 B2B 시스템을 구현하고자 할 때 계획, 수행, 평가 각 단계에서 필수적으로 알아야 할 사항들에 대해 기술별로 적절한 가이드를 제시하고 평가할 수 있는 지침을 제공한다.  

*공청회 및 한국전자문서교환위원회(KEC)에서 승인된 이후에 정신버전의 책자를 배포할 예정입니다.

출처 : remko

Posted by 아름프로
UN/CEFACT TBG17그룹에서 작업한 규격으로 현재 계속 작업중인 산출물입니다. 이 엑셀 자료는 TBG17에서 작업중인 코어 컴포넌트 라이브러리를 위한 기본 자료로 현재 전세계에서 제출한 코어 컴포넌트 목록이 수록되어 있습니다. 현재 19개의 코어 컴포넌트가 릴리즈되어 있으며, 수백개의 후보 목록이 있습니다.  엑셀 자료를 열어보면 상단에 버튼이 있는데, 그걸 클릭해서 원하는 검색 범위를 선택하면 결과가 엑셀에 펼쳐지게 됩니다.  

출처 : remko

Posted by 아름프로
정보 시스템(Information System)을 설계하고 구현하면서 개발자들은 파일 시스템을 만들거나 데이터베이스를 설계하고 구축하며, 기업/조직의 시스템간 메시지를 교환한다.
  정보화나 e비즈니스가 발달하고 규모가 커지면서 이제는 시스템내부에서 뿐만 아니라 시스템간 상호운용성까지 생각해야 할 단계에 이르러 기업내부에서 사용하는 메타데이터의 상호연동을 고려하게 되었다.
  이러한 메타데이터의 상호연동을 위해서는 기업 내부와 외부에서 사용하는 메타데이터에 대한 시맨틱을 명확히 하고 시맨틱 레벨에서 매핑을 할 필요성이 제기된다.
  시맨틱 라이브러리는 개별 시스템 개발자들이나 설계자들이 기업 내부 시스템의 메타데이터를 개발하기 위한 공통 기준을 제시한다.
  본 규격은 시맨틱 라이브러리를 개발하는데 필요한 개발 및 설계 지침을 제공하여 개별 실무자들이 통일적이고 일관되게 메타데이터를 개발하는데 필요한 기준 규격으로 활용하기 위해서 개발되었다.

  시맨틱 라이브러리 설계 및 활용을 다루고 있는 본 기술 규격서는 언어 전반에 걸친 시맨틱 라이브러리를 개발하는 것은 아니다. 단지 국내 전자상거래 및 e-비즈니스 분야에서 한정되어 사용되는 메타데이터의 시맨틱에 대해서 다루며, 한정된 범위의 시맨틱 라이브러리의 구성요소들을 개발하고 갱신하며, 관리하기 위한 규칙과 지침을 제시할 것이다.

Posted by 아름프로
급속하게 발전하는 정보기술의 발달과 함께 전자 무역의 표준화의 필요성이 대두되고 있다. 이에 전자무역은 최신 IT 기술을 활용하여 무역 프로세스와 구조 자체를 근본적으로 혁신하기 위한 노력이 있어왔다. 본 지침은 전 세계 금융결제망인 스위프트와 글로벌 물류업체 연합인 TT Club이 조직한 볼레로 닷 넷의 볼레로 서비스와 국제 표준인 동시에 국내 표준으로 채택된 ebXML 서비스를 상호 연동할 수 있도록 마련되었다.
  이 규격은 ebXML과 볼레로에서 적용하고 있는 전자문서를 기본으로 하여, 두 표준 간의 상호 연동 가능한 규격에 대해 규정한다.
  본 지침은 6개의 장과 부속서로 구성된다. 본 지침의 근간을 이루는 것은 6장으로 볼레로에서 서비스 되고 있는 XML 전자문서와 ebXML 전자문서의 교환 세부 규격을 제시한다.
  본 지침의 4장은 볼레로 서비스의 이해를 돕기 위하여 볼레로 시스템의 아키텍처와 주요특징, Core Messaging Platform 등 세부 내역을 소개한다.
  본 지침의 5장은 국내표준인 ebXML의 비즈니스 프로세스, 명명규칙 및 사전정의, Core Component, Registry/Repository, Core Messaging Platform, CPP/CPA 등을 소개하고 있다.
  이외에 1장에서는 본 지침에 대한 개략적인 소개를 하고, 부속서에서는 본 지침과 관련된 제반 참고 자료가 제공된다.

  본 지침은 전자무역에 사용되는 ebXML 전자문서의 개발 및 표준화에 활용되며, ebXML 전자문서를 바탕으로 한 전자무역 네트워크와 볼레로 서비스를 연계 적용하기 위해 활용된다. 이는 크게 두 개의 주체로 나눌 수 있는데. 하나는 실제 무역에 종사하는 무역 업체이며, 다른 하나는 무역서비스 제공 업체(Service Provider)이다.
  무역 업계의 최종사용자인 무역 업체는 자체적으로 전자무역 네트워크를 구축하고, 이를 볼레로 서비스를 이용하고 있는 거래파트너, 금융기관, 물류업체 등과 연계하여 전자무역을 수행하고자 할 경우 본 지침을 활용하며, 무역서비스 제공 업체(KTNET 등)는 본 지침에서 다루는 볼레로와 ebXML 전자문서의 연동 세부 규격을 참조하여 ebXML 표준 전자문서를 개발, 전자무역 네트워크를 구축하고 이를 볼레로 서비스와 연계 서비스하기 위하여 본 지침을 활용하게 된다. 무역 업체나 무역서비스 제공 업체는 전자문서의 개발에 있어 본 지침의 4장에서 언급되는 연계 방안을 참조하여 반영한다.


Posted by 아름프로
본 규격은 e-비즈니스 활성화로 인해, 인터넷상에서의 표준인 RosettaNet, BizTalk, cXML, ebXML 등이 대두되고 있다. 이들은 인터넷 및 XML을 기반으로 한 기업간의 협업을 위한 프레임워크인 것이다. 국제 표준이며, 국내 표준으로 채택된 ebXML은 산업 표준(RosettaNet, BizTalk, cXML등) 서비스와 ebXML 서비스를 상호 연동할 수 있는 방안이 요구 된다.
이미 다년간 실증된 RosettaNet 서비스와 ebXML 서비스가 네트워크 간 혹은 인터넷상에서의 상호 연동 할 수 있는 시스템을 요구하고 있으며 RosettaNet과 ebXML이 서로 상호 연계에 염두에 두고 작성되었다.

1. 적용 범위
  이 규격은 ebXML과 RosettaNet의 표준을 기본으로 하여, 두 표준 간의 메시지 상호 연동 가능한 규격에 대하여 규정한다.

  이 규격의 주요 내용에 대한 적용범위는 다음과 같다.

a) 기본적인 매핑 규칙 규정
  ebXML과 RosettaNet 프레임워크간의 연동을 위한 매핑 규칙에 대하여 규정한다.

b) 데이터 연동 규격  규정
  각각에 프로토콜 헤더 데이터 연동 규격에 대한 기본 규칙에 대하여 규정한다.

c) 기타 연동 규격 규정
  보안, 중복, Out-of-Bound등의 두 표준간의 연동 상 발생할 수 있는 사항들에 대해 가능한 방법으로 연동하여 처리할 수 있는 규정한다.  
Posted by 아름프로
UN/CEFACT ATG2에서 작업한 규격으로 현재 공개 검토까지 마치고 ATG그룹의 최종 승인과 UN/CEFACT 최종 승인을 기다리고 있는 규격입니다. XML 스키마의 명명 및 설계와 관련된 지침  

출처 : remko
Posted by 아름프로
이 스펙에서는 UN/CEFACT가 UN/CEFACT artefacts를 위하여 ebXML Registry Repository를 어떻게 해석하고 구현할 것인가에 대한 가이드를 제공하고 있습니다.

0.5 Draft 버전으로써 2005년 2월에 발표한 스펙입니다.

출처 : remko
Posted by 아름프로
웹 서비스를 ebXML Registry Repository에 등록하는 방법에 대하여 기술해 놓은 스펙 입니다.

현재 ebXML RS, RIM 스펙 3.0 을 기반으로 검토가 이루어지지 않아서 아직 확정되지 않았지만, 오아시스 등록저장소 TC 에서 이미 승인되었습니다.

버전은 1.0 이며, 2003년 3월에 제안된 내용입니다.

출처 : remko
Posted by 아름프로
좀 지난 자료긴 하지만..
안올렸기에.. ^^

첨부자료 있습니다.
Posted by 아름프로



alt="HiveMind: What's it all about?">







April 2005



Discussion








HiveMind, one of the newer Jakarta subprojects at The Apache Software Foundation,
is described as a framework for creating applications, not an application,
or even an application server, itself. Howard Lewis Ship created HiveMind
while working on WebCTs enterprise e-learning product, Vista. Howard
also created Tapestry, a very popular web development framework. Tapestry paved
the way for component-based web application frameworks and HiveMind is also
beginning to make some waves of its own. In fact, the soon-to-be-released version
of Tapestry actually uses HiveMind extensively. In a recent email, Howard recently
explained to me his thoughts about HiveMind as:



My vision for HiveMind is drawn from the workings of a bee hive or ant colony
(or, for Star Trek fans, the Borg collective). Each individual member has
a very limited job to do, and does its work without concern with what any
other member is doing. And yet, a bee hive or ant colony will expand physically,
collect food, produce new generations of workers, fight against intruders
... do all the things necessary to survive, as if it were a single living
entity (Douglas R. Hofstadter's book "Gödel Escher Bach: An Eternal Golden
Braid" entertainingly discusses this concept at length). This directed
behavior on the part of the bee hive is emergent behavior: the individual
bees of the hive don't have or need an understanding of the greater goals
in order to pursue their part; they just react to their environment, and
the constant stream of chemical signals that flow about the hive.



Likewise, in HiveMind, we can set to task a good number of simple services,
and by letting them collaborate and share information, they can produce the
desired application behavior. But at its heart, HiveMind is about the simplicity
that comes from breaking complex problems into small pieces -- the heart of
Object Oriented development.


As far as an overview, that pretty much sums it up. HiveMind is all about
designing systems as small, testable services which interact with one another
to make up an application. In this article, we will explore some of the key
features of HiveMind by developing a user registration service to be used by
an online application.


The Objective


The requirements for the registration service are:



The user registration service will allow the creation of user accounts based
upon an email address. The email address used to create an account must
be unique within the system. As part of the registration process, an email
should be sent to the users email address containing a system-generated
password for account verification purposes. The user accounts should be stored
in a database.



To follow good programming practices, we define an interface for our service.



public interface RegistrationService
{
public void registerUser( String emailAddress )
throws UserAlreadyExistsException;
}

Since our requirements are relatively simple, our service interface also turns
out to be quite simple. Here, we allow the creation of a user account using
only an email address. If a user account already exists in the system with
the supplied email address, we will throw a UserAlreadyExistsException. Now
that weve
defined what our service looks like, we have to let HiveMind know about our
service using a module descriptor file (discussed in more detail later). As
of now, we only have one service in our HiveMind module, so our descriptor
file will look like:




id="registrationService"
interface="hivemind.example.article.service.RegistrationService"/>


Here, weve created a module with id hivemind.example.article containing
one service with id registrationService. Our implementation class
will likely need to collaborate with some other classes in order to fulfill
all of these requirements. First, since we will be dealing with persistent
user account information, we should create a User class to contain the data.
The User class should contain properties for the email address and password
(should be somewhat easy to imagine, so we wont list the code). Next,
we will need some way of asking if a user account with the requested email
address is already in the database. We will also need to be able to add a user
account to the database. These actions logically belong together, as they are
both database-related and pertain to the User class.



public interface UserRepository
{
public User getUserByEmailAddress( String emailAddress );
public void addUser( User user );
}

We should also provide a mechanism for creating new User objects.



public interface UserFactory
{
public User createUser( String emailAddress );
}

Finally, we will need a way to send account verification emails to our users
once their account is created.



public interface EmailService
{
public void sendEmail( String to, String subject, String body );
}

We now have three more services to tell HiveMind about. Our module descriptor
now looks like:




id="registrationService"
interface="hivemind.example.article.service.RegistrationService"/>
id="emailService"
interface="hivemind.example.article.service.EmailService"/>
id="userFactory"
interface="hivemind.example.article.domain.factory.UserFactory"/>
id="userRepository"
interface="hivemind.example.article.domain.repository.UserRepository"/>



Now that weve created abstractions for most the auxiliary actions we
need to perform, we can get down to writing the core of our service implementation.
With these abstractions in place, the logic is quite simple.



public class RegistrationServiceImpl implements RegistrationService
{
private UserRepository userRepository;
private UserFactory userFactory;
private EmailService emailService;

public void registerUser(String emailAddress)
throws UserAlreadyExistsException
{
if(userRepository.getUserByEmailAddress(emailAddress) == null)
{
User user = userFactory.createUser(emailAddress);
userRepository.addUser(user);
emailService.sendEmail(emailAddress,
"Account Registration",
"Your new account password is \"" +
user.getPassword() +
"\".");
}
else
{
throw new UserAlreadyExistsException();
}
}

public void setUserFactory(UserFactory userFactory)
{
this.userFactory = userFactory;
}

public void setUserRepository(UserRepository userRepository)
{
this.userRepository = userRepository;
}

public void setEmailService(EmailService emailService)
{
this.emailService = emailService;
}
}

Notice how we are relying upon the userRepository, userFactory, and emailService
member variables to be non-null. Many of you will find this to be quite disturbing,
because your years of experience have taught you that this will likely cause
a NullPointerException at some point. Just relax. Were going to let
HiveMind provide our dependencies for us.


Dependency Injection


When it comes to collaborating with other objects, we have a few choices of
how we obtain the references to those objects. We can create the objects ourselves.
We can lookup the objects in some sort of repository or registry. Or, we can
just have them handed to us by some external entity. HiveMind uses the latter
approach and the concept is known as dependency injection (a.k.a.
Inversion of Control). Dependency injection can be described using The
Hollywood Principle, or the notion of dont call us; well
call you. In our example, were letting HiveMind provide us with
our dependencies by exposing setter methods for them or by using setter-based
injection. Dependencies can also be injected via constructor parameters
and that is known as constructor-based injection. With HiveMind
setter-based injection and constructor-based injection are not mutually exclusive.
You are free to mix and match them as you see fit. Most people stick with just
one type for consistency; which type you choose is up to you.


Using dependency injection provides many benefits. One of which is the ability
to unit test your implementation very easily. Since our objects arent
creating the dependencies they need, we have control over what dependent objects
they use. We can supply them with mock objects which behave precisely
as we need in order to test certain conditions. The accompanying code contains
JUnit test cases which use JMock to do just that. For now, though, lets
see how to tell HiveMind about our implementation class.




id="registrationService"
interface="hivemind.example.article.service.RegistrationService"/>
id="emailService"
interface="hivemind.example.article.service.EmailService"/>
id="userFactory"
interface="hivemind.example.article.domain.factory.UserFactory"/>
id="userRepository"
interface="hivemind.example.article.domain.repository.UserRepository"/>


class="hivemind.example.article.service.impl.RegistrationServiceImpl"/>




Here, weve instructed HiveMind that our implementation class is to
be used for the registrationService service points implementation.
Since there are service points which implement the interfaces for all of our
dependencies, they will be automatically injected. Note, however, that the
dependencies can only be autowired if there is no ambiguity about
which service point to use (outside the scope of this article). So far, we
havent implemented the other three services in our module. The email
service would be fairly easy to write using JavaMail, so we wont include
it. The user factory implementation would be responsible for instantiating
a User object and setting its email address and password (randomly generated
of course). That, as you can imagine, would be quite trivial also. The user
repository, however, will require a bit more effort. Remember that the user
repository is an abstraction for the database that contains the user data.
We could develop the code using JDBC, but writing object/relational mapping
code by hand can be quite tedious. So, well use Hibernate instead. We
could have just as easily used JDO or some other O/R mapping tool, but Im
more familiar with Hibernate. Our Hibernate implementation of the UserRepository
interface might look like:



public class HibernateUserRepository implements UserRepository
{
private Session session;

public User getUserByEmailAddress( String emailAddress )
{
String hql = "select u from User u where u.emailAddress = ?";
Query query = session.createQuery( hql );
query.setString( 0, emailAddress );
return ( User )query.uniqueResult();
}

public void addUser( User user )
{
session.save( user );
}

public void setSession( Session session )
{
this.session = session;
}
}

Again, we must inform HiveMind about our implementation class:




id="registrationService"
interface="hivemind.example.article.service.RegistrationService"/>
id="emailService"
interface="hivemind.example.article.service.EmailService"/>
id="userFactory"
interface="hivemind.example.article.domain.factory.UserFactory"/>
id="userRepository"
interface="hivemind.example.article.domain.repository.UserRepository"/>
id="hibernateSession"
interface="org.hibernate.Session"/>



class="hivemind.example.article.service.impl.RegistrationServiceImpl"/>









Notice, however, that we have a service point hibernateSession of
type org.hibernate.Session (were using Hibernate3 so that we dont
have to catch all of the checked exceptions) which has no implementation defined.
We cant just tell HiveMind to construct an object which implements the
Session interface directly. Hibernate requires that you use a Hibernate SessionFactory
to create Session objects. So, how do we tell HiveMind that it needs to construct
a Configuration object, which can construct a SessionFactory object, which
can construct a Session object? We must define a service implementation
factory.


Service Implementation Factories


A service implementation factory is responsible for constructing the implementation
object for a service. You may not have known it, but we were using a service
implementation factory already when we defined our services implementations.
When we used the element in our module descriptor, HiveMind
used its built-in BuilderFactory service implementation factory, which is responsible
for performing the dependency injection and various other tasks, to construct
our implementation object. If you wish to use a different service implementation
factory, you must provide the service id of a service which implements the
ServiceImplementationFactory interface. Heres what our Hibernate Session
factory looks like (were using the HiveMind 1.1 API here):



public class HibernateSessionFactory
implements ServiceImplementationFactory, RegistryShutdownListener
{
private SessionFactory sessionFactory;
private ThreadEventNotifier threadEventNotifier;
private boolean updateSchema = true;
private Log log;

public void init()
{
log.debug( "Initializing Hibernate SessionFactory..." );
Configuration config = new Configuration();
config.configure();
if( updateSchema )
{
log.debug( "Updating database schema..." );
new SchemaUpdate( config ).execute( true, true );
}
sessionFactory = config.buildSessionFactory();
}

public Object createCoreServiceImplementation
( ServiceImplementationFactoryParameters params )
{
log.debug( "Creating Hibernate Session..." );
Session session = sessionFactory.openSession();
threadEventNotifier.addThreadCleanupListener(new SessionCloser(session));
return session;
}

public void registryDidShutdown()
{
log.debug( "Closing Hibernate SessionFactory..." );
sessionFactory.close();
}

public void setThreadEventNotifier(ThreadEventNotifier notifier)
{
this.threadEventNotifier = notifier;
}

public void setLog( Log log )
{
this.log = log;
}

public void setUpdateSchema( boolean updateSchema )
{
this.updateSchema = updateSchema;
}

private class SessionCloser implements ThreadCleanupListener
{
private final Session session;

public SessionCloser( Session session )
{
this.session = session;
}

public void threadDidCleanup()
{
log.debug( "Closing Hibernate Session..." );
session.close();
threadEventNotifier.removeThreadCleanupListener( this );
}
}
}

Theres a lot here, so well just go through the methods one-by-one.
First, the init() method is used to initialize the Hibernate SessionFactory,
using only the default hibernate.cfg.xml file (and optionally
updating the schema). Then, theres the createCoreServiceImplementation()
method. That method (from the ServiceImplementationFactory interface) is responsible
for creating the actual Hibernate Session object. Notice that it registers
a listener object with the ThreadEventNotifier which closes the Hibernate Session
upon thread cleanup (well talk more about this a bit later).
Then, we have the registryDidShutdown() method, which is from the RegistryShutdownListener
interface. That method will close out the SessionFactory when the HiveMind
registry is shutdown (more on this later also). Now that we have implemented
a service implementation factory for Hibernate Sessions, we have to let HiveMind
know about it:




id="registrationService"
interface="hivemind.example.article.service.RegistrationService"/>
id="emailService"
interface="hivemind.example.article.service.EmailService"/>
id="userFactory"
interface="hivemind.example.article.domain.factory.UserFactory"/>
id="userRepository"
interface="hivemind.example.article.domain.repository.UserRepository"/>
id="hibernateSession"
interface="org.hibernate.Session"/>
id="hibernateSessionFactory"
interface="org.apache.hivemind.ServiceImplementationFactory"/>



class="hivemind.example.article.service.impl.RegistrationServiceImpl"/>









class="hivemind.example.article.hibernate.HibernateSessionFactory"
initialize-method="init"/>




One restriction placed upon us by Hibernate is that the Session objects are
not thread-safe. Therefore, we should only be using one Session per thread.
How do we tell HiveMind that it is supposed to instantiate a new Session for
each thread? We use a different service lifecycle model.


Service Lifecycle Models


HiveMind introduces a somewhat unique concept called service lifecycle models.
A service lifecycle model controls when a services implementation (the
interceptor stack, core implementation object, and all its dependencies) is
created. Furthermore, a service lifecycle model can also control which implementation
object is used for a specific invocation. The registry delegates to a service
points service lifecycle model when it needs to return the service object
requested by a client. Many service lifecycle models (all except primitive)
actually return lightweight proxy objects which implement the service interface
rather than the actual implementation. At runtime, when a method is called
on the lightweight proxy, it then constructs the implementation and delegates
all invocations to it. Lets take a look at each of the service lifecycle
models:



  • Primitive – the simplest service model. The service implementation
    is constructed upon first reference (when the registry is asked for it) and
    destroyed upon registry shutdown.

  • Singleton – the default service model. The service implementation
    is constructed upon first invocation and destroyed upon registry shutdown.

  • Threaded – the service is constructed upon first invocation and to
    be used only within the calling thread and is destroyed upon thread cleanup.
    A service implementation class may optionally implement the Discardable interface
    to receive notifications of when it is discarded by the threaded service
    model.

  • Pooled – the service is obtained from a pool upon first invocation
    and returned to the pool up on thread cleanup. Optionally, the service implementation
    class may implement the PoolManageable interface to be receive notifications
    of when it is activated (bound to a thread) or deactivated (unbound from
    a thread and returned to the pool).


Youre probably wondering what was meant by thread cleanup from
the description of the threaded and pooled service models. HiveMind is specifically
targeted for web applications and other multi-threaded environments. HiveMind
can allow specific services to hold thread-specific state (for the duration
of a single web request, typically) and needs to be informed when to free that
state data (that is, and the end of the web request). To inform these services
that the thread-specific state needs to be freed, HiveMind provides the ThreadEventNotifier
service, which notifies listeners of thread cleanup events. A
thread cleanup event means that the current thread is effectively terminating
its execution and any thread-specific information should be cleaned up. The
threaded and pooled service models register themselves with the ThreadEventNotifier
as ThreadCleanupListeners, so that they may discard or return to the pool the
service implementations, respectively. How does the ThreadEventNotifier know
when to fire the thread cleanup events? The registry contains a convenience
method called cleanupThread(), which tells the ThreadEventNotifier to fire
the events. In web applications, the logical time to call cleanupThread() is
right before the response is returned to the client. HiveMind comes with a
servlet filter which does exactly that. For stand-alone , multi-threaded applications,
its a little more difficult to figure out how and when to call cleanupThread().
Ideally, you would have a class responsible for executing logic (Runnable objects)
in other threads (JDK 5 calls these Executors). That class would be responsible
for calling cleanupThread() after each execution. Another lifecycle event,
which weve already seen, is fired when the HiveMind registry is shutdown.
All RegistryShutdownListeners registered with the ShutdownCoordinator will
recive notifications. Now that you know how service models work, youre
probably wondering how to use them. That turns out to be the easy part. You
specify which service model you wish to use in the element:




id="registrationService"
interface="hivemind.example.article.service.RegistrationService"/>
id="emailService"
interface="hivemind.example.article.service.EmailService"/>
id="userFactory"
interface="hivemind.example.article.domain.factory.UserFactory"/>
id="userRepository"
interface="hivemind.example.article.domain.repository.UserRepository"/>
id="hibernateSession"
interface="org.hibernate.Session"/>
id="hibernateSessionFactory"
interface="org.apache.hivemind.ServiceImplementationFactory"/>


class="hivemind.example.article.service.impl.RegistrationServiceImpl"/>









class="hivemind.example.article.hibernate.HibernateSessionFactory"
initialize-method="init"/>



service-id="hibernateSessionFactory"
model="threaded"/>



Notice that we also specified the service id of our previously-defined Hibernate
Session factory. Also, Since Hibernate Session objects are lightweight and
not designed to be re-used we chose to use the threaded service
lifecycle model as opposed to the pooled service lifecycle model.
We have omitted a key component from our implementation, transaction control
- but we dont want to insert transaction control logic into our code.
We would rather treat transactions as a cross-cutting concern to
borrow a term from the aspect-oriented programming (AOP). We can do so using
service interceptors.


Service Interceptors


One of the most fundamental forms of AOP is around advice where
logic is inserted before and after a method call. HiveMind supports this concept
using service interceptors. Implementing your own service interceptors can
be quite involved, as it requires you to dynamically generate entirely new
classes at runtime which implement the service interfaces you wish to intercept
(currently done using Javassist or JDK proxies). However, with HiveMind 1.1,
support has been added for the MethodInterceptor interface from the AOP Alliance
project which simplifies the process tremendously (it also opens the door for
reusing outside codesay, the large code base that already exists inside
the Spring framework). We could write our transaction interceptor as follows:



public class TransactionInterceptor implements MethodInterceptor
{
private TransactionService transactionService;

public Object invoke( MethodInvocation methodInvocation ) throws Throwable
{
if( transactionService.isActive() )
{
return proceedWithInvocation( methodInvocation );
}
else
{
try
{
transactionService.begin();
return proceedWithInvocation( methodInvocation );
}
finally
{
if( transactionService.isRollbackOnly() )
{
transactionService.rollback();
}
else
{
transactionService.commit();
}
}
}
}

private Object proceedWithInvocation( MethodInvocation methodInvocation )
throws Throwable
{
try
{
return methodInvocation.proceed();
}
catch( RuntimeException e )
{
transactionService.setRollbackOnly();
throw e;
}
}

public void setTransactionService( TransactionService transactionService )
{
this.transactionService = transactionService;
}
}

This interceptor depends upon a TransactionService object to provide the actual
transaction support. Implementing a TransactionService using Hibernate is quite
easy, so I will not include the code here. Abstracting the transactional logic
this way allows us to easily switch to another technology in the future. Our
transaction interceptor logic would not have to change at all. Also note that
it automatically marks the transaction for rollback upon any RuntimeException
(a la EJB). With this final piece to the puzzle in place, our module descriptor
now looks like:




id="registrationService"
interface="hivemind.example.article.service.RegistrationService"/>
id="emailService"
interface="hivemind.example.article.service.EmailService"/>
id="userFactory"
interface="hivemind.example.article.domain.factory.UserFactory"/>
id="userRepository"
interface="hivemind.example.article.domain.repository.UserRepository"/>
id="hibernateSession"
interface="org.hibernate.Session"/>
id="hibernateSessionFactory"
interface="org.apache.hivemind.ServiceImplementationFactory"/>
id="transactionService"
interface="hivemind.example.article.service.TransactionService"/>
id="transactionInterceptor"
interface="org.aopalliance.intercept.MethodInterceptor"/>





service-id="hivemind.lib.MethodInterceptorFactory"
name="transaction">










class="hivemind.example.article.hibernate.HibernateSessionFactory"
initialize-method="init"/>



service-id="hibernateSessionFactory"
model="threaded"/>


model="threaded">










Notice the insertion of the element inside our element
for the registrationService. This instructs HiveMind to add a
service interceptor to the service using the MethodInterceptorFactory which
is included with HiveMind. Also note the use of the service:transactionInterceptor syntax.
Here, were using the built-in service object provider (object
providers are outside the scope of this article) to tell HiveMind that it is
to use the transactionInterceptor service object for the implementation
of our service interceptor. Now that we have our module completely fleshed
out, we can write a simple application which uses our registration service.


Running the Example


Heres the complete code for our sample application:



public class Main
{
public static void main( String[] args ) throws Exception
{
Registry registry = RegistryBuilder.constructDefaultRegistry();
RegistrationService registrationService =
(RegistrationService)registry.getService(
RegistrationService.class );
try
{
registrationService.registerUser( "user@localhost" );
}
finally
{
registry.cleanupThread();
registry.shutdown();
}
}
}

The first thing we do in our application is create a HiveMind registry object.
A HiveMind registry contains zero or more modules. In this case, all of the
modules in the registry are described by classpath resources named /META-INF/hivemodule.xml (the
default location for a HiveMind module descriptor). This is a very important
and powerful feature! With this one line of code, HiveMind has automatically
discovered and parsed every module descriptor on the classpath and loaded the
corresponding modules into the registry. So, if this were a web application
having one hundred jar files in the /WEB-INF/lib directory, containing
module descriptors, there would be one hundred modules in the resulting registry.
Again, this was done using only one line of code. Because this mechanism leverages
the Java class loader, it is very flexible. If you repackage your web application
with additional libraries containing HiveMind module descriptors, they will
simply be integrated into the Registry the next time the application is started,
without changing any existing code. As you can imagine, this makes assembling
HiveMind-based applications very easy. If need be, a RegistryBuilder instance
can be used to create custom (non-default) registries. In HiveMind 1.1, theres
even a way to use Groovy scripts to define your modules! However, for the most
part, only the default registry will be needed. Next, we used the registry
to lookup our service object for the registration service. HiveMind requires
that you provide the interface you are expecting so that it can ensure youre
going to get what you ask for. From that point on, we can invoke any of the
service objects methods as usual. Thats all there is to it! With
those few lines of code, all of the dependencies were tied together for us
and our services were ready to use.


Conclusion


We have perused many of the key features of HiveMind in some detail. In some
respects, though, we have barely scratched the surface of what HiveMind can
do. For instance, as you experiment with HiveMind, youre bound to make
some mistakes in your module descriptor documents (I made plenty while writing
this article). HiveMind, fortunately, contains a feature known as line-precise
error reporting which can help you quickly identify your mistake. HiveMind
also contains build-in support for localization. Another notable feature not
covered here involves even listener registrations. HiveMind can automatically inject implementation
objects (not services) as event listeners into other services. Perhaps the
biggest omission is a discussion about configuration points, which allow you
to dynamically define XML syntax for passing configuration information into
your services.


HiveMind boasts a thriving community of interested users and developers alike.
At this moment, the development team is diligently working on the 1.1-alpha-3
release, with a full 1.1 release anticipated soon. With so much involvement,
hopefully many more projects like HiveTranse, a SourceForge project aimed at
providing a standardized transaction framework for HiveMind, will start to
emerge. What is needed is for many projects to adopt HiveMind and create reusable
modules and frameworks that others can plug in to their applications. That
is the vision of HiveMind, assembling large applications from small, testable,
reusable components.


Download Hivemind
Sources


About the Author


James Carman an independent software consultant from Cincinnati, OH. He is
one of the directors of our local Cincinnati Java Users Group (www.cinjug.org).
As of late, he has been working in Bioinformatics, but in the past has done
more business-oriented programming. He is also a committer on the Jakarta Commons
and Jakarta HiveMind projects at The Apache Software Foundation.



Posted by 아름프로



alt="Unit-Testing Hibernate With HSQLDB">





April 2005


Discussion






The Motivation


I've used lots of methods to transform data between databases and object code.
From hand-coded SQL to JDO to EJB. I've never found a method I liked particularly
well. This distaste has become especially acute since adopting test-driven
development (TDD) as a guiding philosophy.


Unit-testing should have as few barriers as possible. For relational databases
those barriers range from external dependencies (is the database running?)
to speed to keeping the relational schema synchronized with your object model.
For these reasons it is vital to keep database access code away from the core
object model and to test as much as possible without touching a real database.


This has often led me to one of two patterns. The first is externalizing all
data access to domain objects and their relationships to separate classes or
interfaces. These are typically data store objects that can retrieve, edit,
delete and add domain entities. This is the easiest to mock-out for unit-testing,
but tends to leave your domain model objects as data-only objects with little
or no related behavior. Ideally access to child records would be directly from
the parent object rather than handing the parent object to some third-party
class to determine the children.


The other method has been to have the domain objects have access to an interface
into the data-mapping layer a la Martin Fowlers Data Mapper pattern.
This has the advantage of pushing object relationships inside the domain model
where the object-relational interface can be expressed once. Classes that use
the domain model are unaware of the persistence mechanism because it is internalized
into the domain model itself. This keeps your code focused on the business
problem you are trying to solve and less about the object-relational mapping
mechanism.


My current project involves crunching a number of baseball statistics and
running simulations with the data. Since the data was already in a relational
database it was a chance for me to explore the Hibernate object-relational
mapping system. I have been very impressed with Hibernate, but I ran into the
problem was trying to insert a layer of indirection while using Hibernate as
my data mapper for unit-testing. The extra layer was so flimsy that it felt
embarrassing to write it. The real deployed version was simply a pass-through
to a Hibernate-specific implementation. Even worse, the mock versions had more
complexity in them than the real "production" version simply because
they didn't have some of the basic object storage and mapping that came with
Hibernate.


I also had enough complex Hibernate query usage that I wanted to unit-test
this significat portion of the application. However, testing against a live database
is a bad idea, because it almost invariably introduces a maintenance nightmare.
In addition, since tests are best when they are independent from each other,
using the same obvious primary keys in test fixture data means you have to
create code to clean the database before each test case, which is a real problem
when lots of relationships are involved


By using HSQLDB and Hibernate's powerful schema-generation tool I was able
to unit-test the mapping layer of the application and find numerous bugs in
my object queries I would not have found as easily by manual testing. With
the techniques outlines below I was able unit-test my entire application during
development with no compromises in test coverage.


Setting up HSQLDB


I used version 1.7.3.0 of HSQLDB. To use an in-memory version of the database
you need to invoke the static loader for the org.hsqldb.jdbcDriver. Then when
you get a JDBC connection you use JDBC url such as jdbc:hsqldb:mem:yourdb where
'yourdb' is the name of the in-memory database you want to use.


Since I'm using Hibernate (3.0 beta 4), I hardly ever need to touch real-live
JDBC objects. Instead I can let Hibernate do the heavy lifting for me--including
automatically creating the database schema from my Hibernate mapping files.
Since Hibernate creates its own connection pool it will automatically load
the HSQLDB JDBC driver based on the configuration code lives in a class called
TestSchema. Below is the static initializer for the class.



public class TestSchema {

static {
Configuration config = new Configuration().
setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect").
setProperty("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver").
setProperty("hibernate.connection.url", "jdbc:hsqldb:mem:baseball").
setProperty("hibernate.connection.username", "sa").
setProperty("hibernate.connection.password", "").
setProperty("hibernate.connection.pool_size", "1").
setProperty("hibernate.connection.autocommit", "true").
setProperty("hibernate.cache.provider_class", "org.hibernate.cache.HashtableCacheProvider").
setProperty("hibernate.hbm2ddl.auto", "create-drop").
setProperty("hibernate.show_sql", "true").
addClass(Player.class).
addClass(BattingStint.class).
addClass(FieldingStint.class).
addClass(PitchingStint.class);

HibernateUtil.setSessionFactory(config.buildSessionFactory());
}

Hibernate provides a number of different ways to configure the framework,
including programmatic configuration. The code above sets up the connection
pool. Note that the user name 'sa' is required to use HSQLDB's in-memory
database. Also be sure to specify a blank as the password. To enable Hibernate's
automatic schema generation set the hibernate.hbm2ddl.auto property to 'create-drop'.


Testing In Practice


My project is crunching a bunch of baseball statistics so I add the four classes
that I'm mapping ( Player, PitchingStint, BattingStint and FieldingStint).
Finally I create a Hibernate SessionFactory and insert it into the HibernateUtil
class which simply provides a single access method for my entire application
for Hibernate sessions. The code for the HibernateUtil is below:



import org.hibernate.*;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {

private static SessionFactory factory;

public static synchronized Session getSession() {
if (factory == null) {
factory = new Configuration().configure().buildSessionFactory();
}
return factory.openSession();
}

public static void setSessionFactory(SessionFactory factory) {
HibernateUtil.factory = factory;
}
}

Since all of my code (production code as well as unit-tests) get their Hibernate
sessions from the HibernateUtil I can configure it in one place. For unit-tests
the first bit of code to access the TestSchema class will invoke the static
initializer which will setup Hibernate and inject the test SessionFactory into
the HibernateUtil. For production code the SessionFactory will be initialized
lazily using the standard hibernate.cfg.xml configuration mechanism.


So what does this look like in the unit-tests? Below is a snippet of a test
that checks the the logic for determining what positions a player is eligible
to play at for a fantasy baseball league:



public void testGetEligiblePositions() throws Exception {
Player player = new Player("playerId");
TestSchema.addPlayer(player);

FieldingStint stint1 = new FieldingStint("playerId", 2004, "SEA", Position.CATCHER);
stint1.setGames(20);
TestSchema.addFieldingStint(stint1);

Set positions = player.getEligiblePositions(2004);
assertEquals(1, positions.size());
assertTrue(positions.contains(Position.CATCHER));
}

I first create a new Player instance and add it to the TestSchema via the
addPlayer() method. This step must occur first because the FieldingStint
class has a foreign-key relationship to the Player class. If I didn't add this
instance first I would get a foreign-key constraint violation when I try to
add the FieldingStint. Once the test-fixture is in place I can test the getEligiblePositions()
method to see that it retrieves the correct data. Below is the code for the
addPlayer() method in the TestSchema. You will notice that Hibernate is used
instead of bare-metal JDBC code:


}



public static void addPlayer(Player player) {
if (player.getPlayerId() == null) {
throw new IllegalArgumentException("No primary key specified");
}

Session session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
try {
session.save(player, player.getPlayerId());
transaction.commit();
}
finally {
session.close();
}
}

One of the most important things in unit-testing is to keep your test-cases
isolated. Since this method still involves a database, you need a way to clean
your database prior to each test case. I have four tables in my schema so I
wrote a reset() method on the TestSchema that removes all rows from the tables
using JDBC. Note because HSQLDB knows about foreign keys, the order in which
the tables are deleted is important. Here is the code:



public static void reset() throws SchemaException {
Session session = HibernateUtil.getSession();
try {
Connection connection = session.connection();
try {
Statement statement = connection.createStatement();
try {
statement.executeUpdate("delete from Batting");
statement.executeUpdate("delete from Fielding");
statement.executeUpdate("delete from Pitching");
statement.executeUpdate("delete from Player");
connection.commit();
}
finally {
statement.close();
}
}
catch (HibernateException e) {
connection.rollback();
throw new SchemaException(e);
}
catch (SQLException e) {
connection.rollback();
throw new SchemaException(e);
}
}
catch (SQLException e) {
throw new SchemaException(e);
}
finally {
session.close();
}
}

When bulk deletes become finalized in Hibernate 3.0 we should able to remove
this last bit of direct JDBC from our application. Until then we have to get
a Connection and issue direct SQL to the database.


Be sure not to close your Connection, closing the Session is sufficient for
resource cleanup. Out of habits developed from writing lots of hand-crafted
JDBC code, the first version closed the JDBC Connection. Since I configured
Hibernate to create a connection pool with only one Connection I completely
torpedoed any tests after the first one.Be sure to watch out for this!


Since you can never be sure what state the database may be in when your test
class is running (imagine running all of your test cases), you should include
database cleanup in your setUp() methods like so:



public void setUp() throws Exception {
TestSchema.reset();
}

Conclusion


Being able to test against a real-live RDBMS without all of the hassles of
trying to run tests against your deployed database is essential, even when
working with sophisticated O/R mappers like Hibernate. The example I showed
here is not exclusive to Hibernate and could probably be made to work with
JDO or TopLink, though Hibernate makes this kind of testing particularly easy
since it has a built-in schema generation tool. With a setup like the one described
above you don't ever have to leave the comfort of your IDE and still have extensive
test coverage over your code.


Posted by 아름프로



developerWorks  > Java technology >
              
developerWorks
Annotations in Tiger, Part 2: Custom annotations
82 KBe-mail it!
Contents:
Defining your own annotation type
Annotating an annotation
Conclusion
Resources
About the author
Rate this article
Related content:
Annotations in Tiger, Part 1: Add metadata to Java code
Taming Tiger
IBM developer kits for the Java platform (downloads)
Subscriptions:
dW newsletters
dW Subscription
(CDs and downloads)
Write your own annotations in Java 5

Level: Introductory

Brett McLaughlin (brett@newInstance.com)
Author/Editor, O'Reilly Media, Inc.
02 Sep  2004

Part 1 of this series introduced annotations, the new metadata facility in J2SE 5.0, and focused on Tiger's basic built-in annotations. A more powerful related feature is support for writing your own annotations. In this article Brett McLauglin shows how to create custom annotations and then how to annotate your annotations to document and customize your code further.


In the first article in this series, I explained what metadata is, why it's valuable, and how to use the basic built-in annotations introduced in J2SE 5.0 (aka Tiger). If you're comfortable with these concepts now, you might already be thinking that the three standard annotations Java 5 offers aren't especially robust. You can do only so much with Deprecated, SuppressWarnings, and Override. Fortunately, Tiger also lets you define your own annotation types. In this article, I'll take you through this relatively simple process with some examples. You'll also find out how to annotate your own annotations and what you gain by doing so. My thanks to O'Reilly Media, Inc., which has graciously allowed me to use the code sample from the annotations chapter of my book on Tiger for this article (see Resources).





Defining your own annotation type
With the addition of a little syntax (and Tiger has added plenty of syntactical constructs), the Java language supports a new type -- the annotation type. An annotation type looks a lot like an ordinary class, but it has some unique properties. Most notably, you can use it with the at sign (@) in your classes to annotate your other Java code. I'll walk you through the process piece by piece.




    

The @interface declaration
Defining a new annotation type is a lot like creating an interface, except that you precede the interface keyword with the @ sign. Listing 1 shows an example of the simplest possible annotation type:




Listing 1. A very simple annotation type



package com.oreilly.tiger.ch06;

/**
* Marker annotation to indicate that a method or class
*   is still in progress.
*/
public @interface InProgress { }


Listing 1 is pretty self-explanatory. If you compile this annotation type and ensure that it's in your classpath, you can then use it on your own source code methods to indicate that a method or class is still in progress, as in Listing 2:



Listing 2. Using your custom annotation type


@com.oreilly.tiger.ch06.InProgress
public void calculateInterest(float amount, float rate) {
  // Need to finish this method later
}


You use the annotation type in Listing 1 exactly the same way you use the built-in annotation types, except that you indicate the custom annotation by both its name and package. Of course, normal Java rules apply, so you can import the annotation type and refer to it as simply @InProgress.




  

Don't miss the rest of this series
Be sure to read, "Part 1" of this series, which introduces annotations in Java 5.0.
  


  
  


Adding a member
The basic usage I've just shown you is far from robust. As you'll remember from Part 1, annotation types can have member variables (see Resources). This is useful, especially when you begin to use annotations as more-sophisticated metadata, not just raw documentation. Code-analysis tools like to have lots of information to crunch, and custom annotations can supply that information.




Data members in annotation types are set up to work using limited information. You don't define a member variable and then provide accessor and mutator methods. Instead, you define a single method, named after the member, that you want to allow for. The data type should be the return value of the method. The concrete example in Listing 3 should make this somewhat confusing requirement more clear:



Listing 3. Adding a member to an annotation type


package com.oreilly.tiger.ch06;

/**
* Annotation type to indicate a task still needs to be
*   completed.
*/
public @interface TODO {
  String value();
}


As odd as Listing 3 might look, it's what you need in annotation types. Listing 3 defines a string named value that the annotation type can accept. You then use the annotation type as in Listing 4:



Listing 4. Using an annotation type with a member value


@com.oreilly.tiger.ch06.InProgress
@TODO("Figure out the amount of interest per month")
public void calculateInterest(float amount, float rate) {
  // Need to finish this method later
}



Again, not much is tricky here. Listing 4 assumes that com.oreilly.tiger.ch06.TODO has been imported, so in the source, you don't prefix the annotation with its package name. Also note that Listing 4 uses the shorthand approach: You feed the value ("Figure out the amount of interest per month") into the annotation without specifying the member-variable name. Listing 4 is equivalent to Listing 5, which doesn't use the shorthand:



Listing 5. "Longhand" version of Listing 4



@com.oreilly.tiger.ch06.InProgress
@TODO(value="Figure out the amount of interest per month")
public void calculateInterest(float amount, float rate) {
  // Need to finish this method later
}


Of course, we're all coders, so who wants to mess with the longhand version? Take note, though -- the shorthand version is available only if the annotation type has a single-member variable named value. If you don't meet this condition, you lose the shorthand feature.



Setting default values
What you've seen so far is a good start, but you have plenty of ways to spruce it up. Probably the next addition you'll think of is to set some default values for the annotation. This is nice when you want users to specify some values, but they need to specify other values only if they differ from the default. Listing 6 illustrates both this concept and its implementation with another custom annotation -- a fuller-featured version of the TODO annotation type from Listing 4:




Listing 6. Annotation type with default values


package com.oreilly.tiger.ch06;

public @interface GroupTODO {

  public enum Severity { CRITICAL, IMPORTANT, TRIVIAL, DOCUMENTATION };

  Severity severity() default Severity.IMPORTANT;
  String item();
  String assignedTo();
  String dateAssigned();
}


The GroupTODO annotation type in Listing 6 adds several new variables. Note that this annotation type doesn't have a single-member variable, so you gain nothing by naming one of the variables value. Any time you have more than one member variable, you should name them as precisely as possible. You don't get the benefit of the shorthand syntax shown in Listing 5, so you might as well be a little more verbose and create better self-documentation for your annotation type.



Another new feature that Listing 6 demonstrates is that the annotation type defines its own enumeration. (Enumerations -- usually just called enums -- are another new feature of Java 5. This isn't anything remarkable, or even specific to annotation types.) Then, Listing 6 uses the new enumeration as the type for the member variable.



Finally, back to the subject at hand -- default values. Establishing them is pretty trivial. You add the keyword default at the end of the member declaration, and then supply the default value. As you might expect, this must be the same type that you declared for the member variable. Again, this isn't rocket science -- just a little bit of a lexical twist. Listing 7 shows the GroupTODO annotation in action, in a case in which severity is not indicated:



Listing 7. Taking advantage of default values


  @com.oreilly.tiger.ch06.InProgress
  @GroupTODO(
    item="Figure out the amount of interest per month",
    assignedTo="Brett McLaughlin",
    dateAssigned="08/04/2004"
  )
  public  void calculateInterest(float amount, float rate) {
    // Need to finish this method later
  }


Listing 8 shows the same annotation in use, this time with a value supplied for severity:



Listing 8. Overriding default values


  @com.oreilly.tiger.ch06.InProgress
  @GroupTODO(
    severity=GroupTODO.Severity.DOCUMENTATION,
    item="Need to explain how this rather unusual method works",
    assignedTo="Jon Stevens",
    dateAssigned="07/30/2004"
  )
  public  void reallyConfusingMethod(int codePoint) {
    // Really weird code implementation
  }




Annotating an annotation
Before closing the book on annotations (at least in this series), I'll deal briefly with annotating annotations. The set of predefined annotation types you learned about in Part 1 have a predetermined purpose. However, as you move into writing your own annotation types, the purpose of your annotation types isn't always self-evident. In addition to basic documentation, you'll probably write types that are specific to a certain member type, or perhaps a certain set of member types. This requires you to supply some sort of metadata on your annotation type, so that the compiler can enforce the annotation's intended functionality.




Of course, annotations -- the Java language's choice for metadata -- should immediately come to mind as the solution.  You can use four predefined annotation types -- referred to as meta-annotations -- to annotate your annotations. I'll cover each one in turn.



Specifying the target
The most obvious meta-annotation is one that allows you to indicate which program elements can have annotations of the defined type. Unsurprisingly, this meta-annotation is called Target. Before you see how to use Target, though, you need to know about another new class -- actually an enum -- called ElementType. This enum defines the various program elements that an annotation type can target. Listing 9 show the ElementType enum in its entirety:




Listing 9. The ElementType enum


package java.lang.annotation;

public enum ElementType {
  TYPE,     // Class, interface, or enum (but not annotation)
  FIELD,    // Field (including enumerated values)
  METHOD,   // Method (does not include constructors)
  PARAMETER,    // Method parameter
  CONSTRUCTOR,    // Constructor
  LOCAL_VARIABLE, // Local variable or catch clause
  ANNOTATION_TYPE,  // Annotation Types (meta-annotations)
  PACKAGE   // Java package
}


The enumerated values in Listing 9 are pretty obvious, and you can figure out on your own (with help from the comments) how each one applies. When you use the Target meta-annotation, you supply it at least one of these enumerated values and indicate which program elements the annotated annotation can target. Listing 10 shows Target in action:



Listing 10. Using the Target meta-annotation


package com.oreilly.tiger.ch06;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

/**
* Annotation type to indicate a task still needs to be completed
*/
@Target({ElementType.TYPE,
         ElementType.METHOD,
         ElementType.CONSTRUCTOR,
         ElementType.ANNOTATION_TYPE})
public @interface TODO {
  String value();
}


Now the Java compiler will apply TODO only to types, methods, constructors, and other annotation types. This helps you ensure that nobody else takes your annotation type and misapplies it (or, better yet, that you don't misapply it in a fit of fatigue).



Setting retention
The next meta-annotation you want to get under your fingers is Retention. This meta-annotation is related to how the Java compiler treats the annotated annotation type. The compiler has several options:


  • Retain the annotation in the compiled class file of the annotated class, and read it when the class first loads

  • Retain the annotation in the compiled class file, but ignore it at runtime

  • Use the annotation as indicated, but then discard it in the compiled class file





These three options are represented in the java.lang.annotation.RetentionPolicy enum, shown in Listing 11:



Listing 11. The RetentionPolicy enum


package java.lang.annotation;

public enum RetentionPolicy {
  SOURCE,   // Annotation is discarded by the compiler
  CLASS,    // Annotation is stored in the class file, but ignored by the VM
  RUNTIME   // Annotation is stored in the class file and read by the VM
}


As you should expect by now, the Retention meta-annotation type takes as its single argument one of the enumerated values you see in Listing 11. You target this meta-annotation to your annotations, as shown in Listing 12:



Listing 12. Using the Retention meta-annotation


@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
  // annotation type body
}


As you can tell from Listing 12, you can use the shorthand form here, because Retention has a single-member variable. And if you want the retention to be RetentionPolicy.CLASS, you don't have to do a thing, because that's the default behavior.



Adding public documentation
The next meta-annotation is Documented. This is another one that's pretty easy to understand, partly because Documented is a marker annotation. As you should remember from Part 1, marker annotations have no member variables.  Documented indicates that an annotation should appear in the Javadoc for a class. By default, annotations are not included in Javadoc -- a fact worth remembering when you spend a lot of time annotating a class, detailing what's left to do, what it does correctly, and otherwise documenting its behavior.




Listing 13 shows what the Documented meta-annotation looks like in use:



Listing 13. Using the Documented meta-annotation


package com.oreilly.tiger.ch06;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
* Marker annotation to indicate that a method or class
*   is still in progress.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface InProgress { }


The one "gotcha" with Documented is in the retention policy. Notice that Listing 13 specifies the annotation's retention as RUNTIME.  This is a required aspect of using the Documented annotation type. Javadoc loads its information from class files (not source files), using a virtual machine. The only way to ensure that this VM gets the information for producing Javadoc from these class files is to specify the retention of RetentionPolicy.RUNTIME. As a result, the annotation is kept in the compiled class file and is loaded by the VM; Javadoc then picks it up and adds it to the class's HTML documentation.



Setting up inheritance
The final meta-annotation, Inherited, is probably the most complicated to demonstrate, the least-often used, and the one that creates the most confusion. All that said, let's cheerily run through it.




First, take a use case: Suppose that you mark a class as being in progress, through your own custom InProgress annotation. No problem, right? This will even show up in the Javadoc if you've correctly applied the Documented meta-annotation. Now, suppose you write a new class and extend the in-progress class. Easy enough, right? But remember that the superclass is in progress. If you use the subclass, and even look at its documentation, you get no indication that anything is incomplete. You would expect to see that the InProgress annotation is carried through to subclasses -- that it's inherited -- but it isn't. You must use the Inherited meta-annotation to specify the behavior you want, as shown in Listing 14:



Listing 14. Using the Inherited meta-annotation


package com.oreilly.tiger.ch06;

import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
* Marker annotation to indicate that a method or class
*   is still in progress.
*/
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface InProgress { }


With the addition of @Inherited, you'll see the InProgress annotation show up on subclasses of annotated classes. Of course, you don't really want this behavior on all your annotation types (that's why the default is not to inherit); for example, the TODO annotation wouldn't (and shouldn't) be propagated. Still, for the case I've shown here, Inherited can be quite helpful.




Conclusion
At this point, you're ready to go back into the Java world and document and annotate everything. Then again, this reminds me a bit of what happened when everyone figured out Javadoc. We all went into the mode of over-documenting everything, before someone realized that Javadoc is best used for clarification of confusing classes or methods. Nobody looks at those easy-to-understand getXXX() and setXXX() methods you worked so hard to Javadoc.




The same trend will probably occur with annotations, albeit to a lesser degree. It's a great idea to use the standard annotation types often, and even heavily. Every Java 5 compiler will support them, and their behavior is well-understood. However, as you get into custom annotations and meta-annotations, it becomes harder to ensure that the types you work so hard to create have any meaning outside of your own development context. So be measured. Use annotations when it makes sense to, but don't get ridiculous. However you use it, an annotation facility is nice to have and can really help out in your development process.



      

Resources

  • Don't miss Part 1 of this series, which introduces annotations in Java 5.0.

  • The open source XDoclet code-generation engine enables attribute-oriented programming for the Java language.

  • JSR 175, the specification for incorporating a metadata facility into the Java language, is in proposed final draft status under the Java Community Process.

  • Visit Sun's home base for all things J2SE 5.0..

  • You can download Tiger and try it out for yourself.

  • John Zukowski's series Taming Tiger covers the new features of Java 5.0 in practical tip-based format.

  • Java 1.5 Tiger: A Developer's Notebook (O'Reilly & Associates; 2004), by Brett McLaughlin and David Flanagan, covers almost all of Tiger's newest features -- including annotations -- in a code-centric, developer-friendly format.

  • Find hundreds more Java technology resources on the developerWorks Java technology zone.

  • Visit the Developer Bookstore for a comprehensive listing of technical books, including hundreds of Java-related titles.

  • Interested in test driving IBM products without the typical high-cost entry point or short-term evaluation license? The developerWorks Subscription provides a low-cost, 12-month, single-user license for WebSphere®, DB2®, Lotus®, Rational®, and Tivoli® products -- including the Eclipse-based WebSphere Studio IDE -- to develop, test, evaluate, and demonstrate your applications.


About the author
Author photoBrett McLaughlin has worked in computers since the Logo days (remember the little triangle?). In recent years, he's become one of the most well-known authors and programmers in the Java and XML communities. He's implemented complex enterprise systems at Nextel Communications, written application servers at Lutris Technologies, and now writes and edits books for O'Reilly Media, Inc.



Posted by 아름프로



한국 developerWorks > 자바 >
developerWorks
Annotations in Tiger, Part 1: 메타데이터를 자바 코드에 추가하기
e-mail it!
목차:
메타데이터의 가치
어노테이션의 기초
Override 어노테이션
Deprecated 어노테이션
SuppressWarnings 어노테이션
결론
참고자료
필자소개
관련자료:
Annotations in Tiger, Part 2: Custom annotations
Taming Tiger
IBM developer kits for the Java platform (downloads)
Subscriptions:
dW newsletters
Java 5의 빌트인 어노테이션을 사용하는 방법

난이도 : 초급

Brett McLaughlin (brett@newInstance.com)
Author/Editor, O'Reilly Media, Inc.
2004년9월 02일

J2SE 5.0 (Tiger)의 새로운 기능인 Annotation은 필요가 많은 메타데이터 기능을 핵심 자바 언어로 가져왔다. 메타테이터가 유용하게 쓰이는 이유를 설명하고 자바의 Annotation 소개한다.


프로그래밍, 특히 자바 프로그래밍의 최신 경향 중 하나는 metadata를 사용한다는 것이다. 메타데이터는 간단히 말해서 데이터에 대한 데이터이다. 메타데이터는 문서화에 사용될 수 있고 코드 의존성을 트래킹하는데 사용되며 심지어 초기 컴파일 시간 체크를 수행 할 때도 사용될 수 있다. XDoclet 같은 (참고자료)메타데이터용 툴들은 이러한 기능을 핵심 자바 언어로 가져왔고 얼마 동안 자바 프로그래밍 관습의 일부가 되었다.



J2SE 5.0 (일명 Tiger)이 나오기 전 까지, 핵심 자바 언어는 javadoc 방법론과 함께 메타데이터 장치에 근접했다. 특별한 태그 세트를 사용하여 코드를 마크업(mark-up)하고 그런 다음 javadoc 명령어를 실행하여 태그를 포맷된 HTML로 변환하여 태그들이 어태치 될 클래스들을 문서화한다. 하지만 Javadoc은 부적당한 메타데이터 툴이다. 문서들을 모으는 것 이상의 다른 목적의 데이터들을 얻을 수 있는 견고하고 표준화된 방법이 없기 때문이다. HTML 코드가 종종 Javadoc 아웃풋과 섞인다는 사실이 이를 더욱 증명하고 있다.



Tiger는 어노테이션이라는 새로운 기능을 통해 보다 다양한 메타데이터 장치를 핵심 자바 언어에 추가했다. 어노테이션은 코드에 추가할 수 있고, 패키지 선언, 유형 선언, 생성자, 메소드, 필드, 매개변수, 변수에 적용할 수 있는 변경자(modifier)이다. Tiger에는 빌트인 어노테이션이 추가되었고 직접 작성할 수 있는 커스텀 어노테이션도 지원한다. 이 글에서는 메타테이터의 효용을 설명하고 Tiger의 빌트인 어노테이션을 소개하겠다. Part 2에서는 커스텀 어노테이션에 대해 자세히 알아 볼 것이다. O'Reilly Media, Inc.에 특별히 감사한다. 이들의 도움으로 내 저서의 어노테이션 챕터에서 코드 샘플을 인용할 수 있었다.(참고자료)



메타데이터의 가치
일반적으로 메타데이터의 효용은 세 가지로 나눌 수 있다. 문서화, 컴파일러 체크, 코드 분석. 코드 레벨의 문서화는 가장 자주 인용되는 사용법이다. 메타데이터는 메소드가 다른 메소드에 의존하고 있다는 것을 가르키는 유용한 방법을 제공한다. 또한 그들이 불완전한지, 특정 클래스가 또 다른 클래스를 레퍼런싱 하는지 등을 가르킨다. 이는 정말로 유용하지만 문서화는 메타데이터를 자바에 추가하는 것과 가장 관련이 적은 항목이다. 코드의 문서화에 있어서는 Javadoc이 사용이 쉽고 강력한 방식을 제공하고 있기 때문이다. 이미 사용하고 있는 것이 있고 작동도 잘 되고 있는데 문서를 굳이 만들 필요는 없지 않는가?






Part 2를 놓치지 마세요!
커스텀 어노테이션을 설명하는 "Part 2"도 잊지 말고 읽어주시기 바랍니다.






컴파일러 체크
보다 중요한 메타데이터의 장점은 컴파일러가 메타데이터를 사용하여 몇 가지 기본적인 컴파일 시간 체크를 수행할 수 있는 기능이라고 할 수 있다. 예를 들어, 이 글의 The Override 어노테이션섹션에서 Tiger 는 메소드가 또 다른 메소드를 수퍼클래스에서 겹쳐 쓰게끔 지정하는 어노테이션을 도입한다. 자바 컴파일러는 메타데이터에서 가르키는 작동이 실제로 코드 레벨에서 발생한다는 것을 확인할 수 있다. 이러한 유형의 버그를 추적해 본 적이 없다면 어리석은 일 같지만 대부분의 자바 프로그래밍 베테랑들은 코드가 왜 작동하지 않는지를 밝혀내기 위해서 밤을 지새우기도 하는 법이다. 메소드가 잘못된 매개변수를 갖고 있고 사실 수퍼클래스에서 메소드를 겹쳐 쓰지 않는다는 것을 발견했을 때의 씁쓸함이란... 메타데이터를 소비하는 툴을 사용하면 이러한 유형의 에러를 쉽게 발견할 수 있다. 많은 밤을 뜬눈으로 지새우지 않아도 된다.






JSR 175
JSR 175(자바 프로그래밍 언어를 위한 메타테이터 장치) 메타데이터를 핵심 자바 언어로 결합하는 공식 스팩을 제공한다.(참고자료) JSR에 따르면 어노테이션은 "프로그램의 문법에 직접적인 영향을 주지 않는다. 하지만 개발과 전개 툴은 이러한 어노테이션을 읽고 특정 방식으로 처리하면서 부가적인 자바 프로그래밍 언어 소스 파일, XML 문서 등을 만들어내서 어노테이션을 포함하고 있는 프로그램과 결합하여 사용될 수 있게 한다."




코드 분석
아마도 좋은 어노테이션 또는 메타데이터 툴의 최고의 기능은 여분의 데이터를 사용하여 코드를 분석하는 것이다. 간단한 경우, 코드 목록을 구현하고 필요한 인풋 유형을 제공하고 리턴 유형을 지시한다. 하지만 자바 리플렉션도 같은 기능을 제공한다고 생각할 수도 있다; 결국 이 모든 정보에 대한 코드를 검사할 수 있다. 표면적으로 볼 때 그럴 듯 하지만 실제로 그렇지 않다. 많은 경우 메소드는 인풋으로서 받아들이거나 아웃풋으로 리턴한다. 이는 메소드가 원하는 것이 아니다. 예를 들어, 매개변수 유형이 Object이지만 메소드는 Integer를 사용해서만 작동한다. 이는 메소드가 겹쳐쓰기된 곳에서 쉽게 발생할 수 있다. 그리고 수퍼클래스가 메소드를 일반 매개변수로 선언하던가 많은 직렬화가 진행되는 시스템에서도 쉽게 발생한다. 두 경우 모두 메타데이터는 코드 분석 툴을 지정할 수 있다. 매개변수 유형이 Object이더라도 정말로 원하는 것은 Integer라는 것을 나타낼 수 있다. 이러한 종류의 분석은 상당히 유용하며 그 가치는 상당하다.




보다 복잡한 경우 코드 분석 툴은 모든 종류의 추가 태스크들을 수행할 수 있다. 그 예 중 하나가 Enterprise JavaBean (EJB) 컴포넌트이다. 심지어 간단한 EJB 시스템으로의 의존성과 복잡함은 상당하다. 로컬 인터페이스와 로컬 홈 인터페이스의 가능성과 함께 홈 인터페이스와 원격 인터페이스를 얻는다. 이 모든 클래스들을 연동시키는 것은 진정한 고통이다. 하지만 메타데이터는 이 문제에 대한 솔루션을 제공한다. 좋은 툴은(예를 들어, XDoclet)은 이 모든 의존성을 관리하면서 "코드-레벨" 연결이 없지만 "로컬-레벨" 관계를 가진 클래스들이 연동될 수 있도록 한다. 이것이 바로 메타테이터의 진정한 가치이다.



어노테이션의 기초
메타데이터가 어디에 좋은 지를 이해했으니 Tiger 의 어노테이션을 소개하겠다. Tiger는 "at" 표시(@)를 취한다. 그 뒤에는 어노테이션 이름이 붙는다. 그런 다음 데이터가 필요할 때 어노테이션에 데이터를 제공한다. (name=value)종류의 표기법을 사용할 때 마다 어노테이션을 만든다. 코드 한 조각은 10, 50 또는 그 이상의 어노테이션을 가진다. 하지만 많은 어노테이션은 같은 어노테이션 유형을 사용한다. 이 유형은 실제 구조체이고 어노테이션 자체는 이 유형의 특정 사용법이다. (사이드 바 참조 어노테이션 또는 어노테이션 유형?)






어노테이션 또는 어노테이션 유형?
어노테이션과 어노테이션 유형이 무엇인지 혼돈스러운가? 가장 쉽게 이해하려면 이미 익숙한 자바 언어 개념의 관점에서 생각해야 한다. 단일 클래스 (예를 들어, Person)를 정의할 수 있고 단 한 버전의 클래스를 JVM에 가질 수 있다. (단, 중첩 클래스 경로를 수행하지 않는 한) 하지만 주어진 시간동안 사용할 때, 이 클래스의 10개 또는 20개의 인스턴스를 갖게 된다. 여전히 단 하나의 Person 클래스만 존재하지만 다양한 방식으로 여러 번 사용된다. 어노테이션 유형과 어노테이션의 경우도 이와 같다. 어노테이션 유형은 클래스와 유사하고 어노테이션은 이 클래스의 인스턴스와 비슷하다.





어노테이션은 세 가지 기본 범주로 나뉜다:




  • Marker 어노테이션은 변수가 없다. 이 어노테이션은 이름으로 구분되며 추가 데이터 없이 나타난다. 예를 들어, @MarkerAnnotation은 marker 어노테이션이다. 데이터가 없으며 단지 어노테이션 이름만 있을 뿐이다.




  • Single-value 어노테이션은 marker와 비슷하지만 데이터를 제공한다. 싱글 비트 데이트를 제공하기 때문에 간단한 신택스를 사용할 수 있다. (단, 어노테이션 유형이 이 문법을 수용해야 함): @SingleValueAnnotation("my data")이는 @표시만 제외하고는 일반적인 자바 메소드 호출과 비슷하다.




  • Full 어노테이션은 다중 데이터 멤버를 갖고 있다. 결과적으로 전체 신택스를 사용해야 한다. (그리고 어노테이션은 일반 자바 메소드와 더 이상 비슷하지 않다): @FullAnnotation(var1="data value 1", var2="data value 2", var3="data value 3")



디폴트 신택스를 통해 어노테이션에 값을 제공하는 것 외에도 한 개 이상의 값을 전달해야 할 때 name-value쌍을 사용할 수 있다. 또한 어노테이션 변수에 값 어레이를 제공할 수 있다. 이때 중괄호({})를 사용한다. Listing 1은 어노테이션에서의 값의 어레이 예제이다.



Listing 1. 어노테이션에서 어레이 값 사용하기



@TODOItems({ // Curly braces indicate an array of values is being supplied
@TODO(
severity=TODO.CRITICAL,
item="Add functionality to calculate the mean of the student's grades",
assignedTo="Brett McLaughlin"
),
@TODO(
severity=TODO.IMPOTANT,
item="Print usage message to screen if no command-line flags specified",
assignedTo="Brett McLaughlin"
),
@TODO(
severity=TODO.LOW,
item="Roll a new website page with this class's new features",
assignedTo="Jason Hunter"
)
})


Listing 1의 예제는 보기보다 간단하다. TODOItems 어노테이션 유형은 값을 취하는 하나의 변수를 갖고 있다. 여기에서 제공되는 값은 매우 복잡하다. 하지만 TODOItems를 사용하면 single-value 어노테이션 스타일과 실제로 맞다. Single value가 어레이라는 것을 제외하면 말이다. 이 어레이는 세 개의 TODO 어노테이션을 포함하고 있는데 각각 값이 증폭된다. 콤마는 각 어노테이션에서 값을 분리하고 하나의 어레이에서의 값도 콤마로 분리된다.



TODOItemsTODO는 커스텀 어노테이션이다. 커스텀 어노테이션은 Part 2의 주제이다. 여러분에게 복잡한 어노테이션을 보여주고 싶었다. Listing 1은 어떤 어노테이션 보다 복잡하지만 그렇게 심하지는 않다. 자바의 표준 어노테이션 유형을 살펴본다면 그렇게 복잡한 것도 드물다. 다음 섹션에서는 Tiger의 기본 어노테이션 유형이 사용하기 쉽다는 것을 알게될 것이다.



Override 어노테이션
Tiger의 첫 번째 빌트인 어노테이션 유형은 Override이다. Override는 메소드에 대해서만 사용되어야 한다. (클래스, 패키지 선언, 기타 구조체는 안된다.) 주석이 첨가된 메소드는 수퍼클래스에서 메소드를 오버라이드한다는 것을 나타낸다. Listing 2는 예제이다.





Listing 2. The Override 어노테이션


package com.oreilly.tiger.ch06;

public class OverrideTester {

public OverrideTester() { }

@Override
public String toString() {
return super.toString() + " [Override Tester Implementation]";
}

@Override
public int hashCode() {
return toString().hashCode();
}
}


Listing 2는 따라가기 쉽다. @Override어노테이션은 두 개의 메소드, toString()hashCode()OverrideTester 클래스의 수퍼클래스 (java.lang.Object)에서 메소드의 버전을 오버라이드 한다는 것을 나타내고 있다. 언뜻 보기에는 사소한 것 같지만 매우 좋은 기능이다. 이들 메소드를 오버라이딩 하지 않고는 클래스를 컴파일 할 수 없다. 어노테이션은 toString()과 썩일 때 적어도 hashCode()와 맞는다는 것을 확인해야 하는 것을 나타낸다.



이 어노테이션 유형은 코딩하기엔 너무 늦었거나 무언가를 잘못 타이핑했을 때 빛을 발한다. (Listing 3)



Listing 3. Override 어노테이션의 오타 찾아내기


package com.oreilly.tiger.ch06;

public class OverrideTester {

public OverrideTester() { }

@Override
public String toString() {
return super.toString() + " [Override Tester Implementation]";
}

@Override
public int hasCode() {
return toString().hashCode();
}
}


Listing 3에서, hashCode()hasCode()로 잘못 표기되었다. 어노테이션은 hasCode()가 메소드를 오버라이드해야 한다는 것을 지시한다. 하지만 컴파일 시, javac는 수퍼클래스(java.lang.Object)가 오버라이드 할 hasCode()라는 메소드가 없다는 것을 알게 된다. 결과적으로 컴파일러는 에러를 표시한다. (그림 1)





그림 1. Override 어노테이션에서의 컴파일러 경고





빠진 기능
Deprecated로 에러 유형 메시지를 single-value 어노테이션 유형으로 포함시킬 수 있도록 한다면 좋을 것이다. 컴파일러는 사용자가 deprecated 메소드를 사용할 때 메시지를 프린트할 수 있다. 메시지는 이 메소드를 사용할 때의 결과가 얼마나 심각한지를 나타낼 수 있다. 이 메소드가 정지할 때 대안을 권할 수도 있다. 아마 다음 J2SE 버전에 포함될 것 같다. (Mustang이 임시 이름이다.)





이 간편한 기능으로 오타를 매우 빠르게 잡을 수 있다.



Deprecated 어노테이션
이제 Deprecated표준 어노테이션 유형을 살펴보자. Override와 마찬가지로 Deprecated는 marker 어노테이션이다. Deprecated를 사용하여 더 이상 사용되지 말아야 하는 메소드에 주석을 단다. Override와 다른 점은, Deprecated는 더 이상 사용되지 말아야 하는(depreciated) 메소드와 같은 라인상에 놓여져야 한다. (이유는 나도 모르겠다.)





Listing 4. Deprecated 어노테이션 사용하기



package com.oreilly.tiger.ch06;

public class DeprecatedClass {

@Deprecated public void doSomething() {
// some code
}

public void doSomethingElse() {
// This method presumably does what doSomething() does, but better
}
}



이 클래스를 컴파일 할 때 비정상적인 그 어떤 것도 기대해서는 안된다. 오버라이드 또는 호출이든 Depreciated 메소드를 사용하면 컴파일러는 어노테이션을 처리하고 메소드가 사용되어서는 안된다는 것을 알게 되고 에러 메시지를 만든다. (그림 2)




그림 2. Deprecated 어노테이션의 컴파일러 경고





컴파일러 경고를 켜고 정상적인 depreciation 경고를 원한다는 것을 자바 컴파일러에게 명령한다. 두 플래그 -deprecated또는 -Xlint:deprecated중 하나와 javac명령어를 사용할 수 있다.



SuppressWarnings 어노테이션
마지막 어노테이션 유형은 SuppressWarnings이다. 이것이 어떤 일을 수행하는지 알아내는 것은 쉽다. 하지만 왜 이 어노테이션이 중요한지는 분명하지 않다. 이는 실제로 Tiger의 새로운 기능의 부작용이다. 예를 들어, generics를 생각해보자. generics는 모든 유형의 새로운 type-safe 작동을 만든다. 특히 자바 컬렉션의 경우 더욱 그렇다. 하지만 generics 때문에 컴파일러는 컬렉션이 type-safety 없이 사용될 때 경고를 던진다. Tiger를 겨냥한 코드에는 유용하지만 Java 1.4.x의 경우엔 코드 작성이 고통 그 자체이다. 전혀 신경 쓰지 않은 것에 대해 경고를 받아야 한다. 컴파일러를 어떻게 하면 없앨 수 있을까?





SupressWarnings는 구원자다. OverrideDeprecated와는 다르게 SupressWarnings는 변수를 갖고 있다. 따라서 이를 작동하게 하려면 싱글-어노테이션 유형을 사용한다. 값 어레이로서 변수를 제공할 수 있다. 각각 삭제할(Suppress) 특정 유형의 경고를 나타낸다. Listing 5의 예제를 보자. Tiger에서 에러를 만드는 코드이다.



Listing 5. type-safe가 아닌 Tiger 코드


public void nonGenericsMethod() {
List wordList = new ArrayList(); // no typing information on the List

wordList.add("foo"); // causes error on list addition
}



그림 3은 Listing 5에서 코드 컴파일을 한 결과이다.




그림 3. non-typed 코드에서 컴파일러 경고





Listing 6은 SuppressWarnings 어노테이션을 사용하여 번거로운 경고를 제거한다.



Listing 6. 경고 제거하기


@SuppressWarnings(value={"unchecked"})
public void nonGenericsMethod() {
List wordList = new ArrayList(); // no typing information on the List

wordList.add("foo"); // causes error on list addition
}


간단하지 않은가? 경고 유형을 배치하고(그림 3의 "unchecked") SuppressWarnings에 전달하면 된다.



SuppressWarnings의 변수 값이 어레이를 취한다는 사실은 같은 어노테이션으로 다중의 경고를 삭제할 수 있음을 의미한다. 예를 들어, @SuppressWarnings(value={"unchecked", "fallthrough"})는 두 개의 값 어레이를 취한다. 이 장치는 매우 유연한 방식을 제공하여 장황하지 않게 에러를 핸들 할 수 있다.




결론
이 글에서 본 문법이 다소 생소하더라도 어노테이션은 이해하기도 쉽고 사용도 쉽다는 것을 알아야 한다. Tiger 에서 제공하는 표준 어노테이션 유형이 어설프고 개선의 여지가 많다. 메타데이터는 점점 유용해지고 있고 자신의 애플리케이션에 맞는 어노테이션 유형을 사용할 수 있을 것이다. Part 2에서는 커스텀 어노테이션 유형을 작성하는 방법을 자세히 다루겠다. 자바 클래스를 만들고 이를 어노테이션 유형으로서 정의하는 방법, 컴파일러가 어노테이션 유형을 인식하게 하는 방법, 코드에 주석을 달 때 이를 사용하는 방법 등을 설명하겠다.





참고자료



필자소개
Author photoBrett McLaughlin은 현재 자바 및 관련 기술을 이용하여 애플리케이션 기반구조 구현을 전문적으로 수행하고 있다. Brett은 Java Apache 프로젝트인 Turbine의 공동 창립자이다.





 

한국 developerWorks > 자바 >
  
 



Posted by 아름프로

이클립스 3.0 단축키

2005. 4. 10. 02:12
제가 정리해놓은거 보다 깔끔해서 링크합니다. ^^
더 자세한 내용은 링크 참조..
========================================

필수 단축키

한줄 삭제 CTRL + D,
메소드나 필드 이동하기 CTRL + O
페이지 이동 CTRL + E

ULTRAEDIT나 EDITPLUS 의 CTRL+TAB 과 같은 기능. : CTRL+F6

VIEW 들의 이동. (Package Explorer, source, Outlines...) : CTRL+F7

Perspective 같은 이동(?)  : CTRL+F8  

파일 닫기 : CTRL+W

들여쓰기 자동 수정. (3.0 NEW) : CTRL+I

블록 주석(/*..*/) 추가.(3.0 NEW): CTRL+SHIFT+/
위(아래)줄과 바꾸기 : ALT+UP(DOWN)

블록 선택하기.  : ALT+SHIFT+방향키

메소드의 파라메터 목록 보기. : CTRL+SHIFT+SPACE
자동으로 import 하기 : CTRL+SHIFT+O

열린 파일 모두 닫기 : CTRL + SHIFT + F4

블록 주석 제거 : CTRL+SHIFT+\

전체화면 토글 : CTRL+M
한줄(블럭) 복사 : Ctrl + Alt + 위(아래)

다음 annotation(에러, 워닝, 북마크 가능)으로 점프 : Ctrl + , or .

퀵 픽스 : Ctrl + 1  
메소드 정의부로 이동 : F3
하이어라키 팦업 창 띄우기(인터페이스 구현 클래스간 이동시 편리) : Ctrl + T  


(이외에.. 3.0에선 형광펜기능[선택한 변수 형광펜으로 표시]도 있어서 편해요.. ^^)

이것 이외의 단축키 리스트 :  HELP->Help Contents->Java Development User Guide->Reference->JDT Basics

새로운 기능:  HELP->Help Contents->Java Development User Guide->What's new

유용한 기능 :  Tips and tricks

Posted by 아름프로
번역상에 이상이 있는 부분 알려주세요..
원본은 아래에 링크 했습니다.
===========================================

많은 API들은 많은 boilerplate code(원본에서 변경없이 재사용되어지는 코드)이 필요로 합니다.
예로 JAX-RPC로 웹서비스를 작성하기 위해서는 당신은 인터페이스와 구현체 한쌍을 제공해야만 합니다.
만약 프로그램이 원격에서 접근가능한  메소드를 나타내는 주석(Annotation : 추후 주석으로 해석)들로
장식되어져("decorated")  있다면 툴에 의해서 자동적으로 처리될 수 있습니다.

다른 API들은 프로그램과 동시에 유지되기 위한 "side files"을 필요로 합니다.
예로 JavaBeans는 bean과 동시에 유지되기 위한 BeanInfo 클래스가 필요로 합니다, 그리고
Enterpise JavaBeans(EJB)는 deployment descriptor를 필요로 합니다.
이러한 side files내에 정보가 프로그램 자체의 주석으로써 유지되어지면
더욱 쓰기 편해지고 실수로인한 에러(error-prone)가 줄어들 것입니다.

자바 플랫폼은 항상 다양한 ad hoc annotation mechanisms(임시 변통의 주석 처리방법)을 가지고 있습니다.
예로 transient 제어자(modifier)는 필드가 serialization subsystem에 의해 무시되어지는 것을
나타내는 ad hoc annotation 입니다. 그리고
@deprecated 태그는 메소드가 더이상 사용해서는 안됨을 나타내는 ad hoc annotation 입니다.
현재 릴리즈5.0은 metadata로 알려진 독자적으로 주석타입을 사용하고 정의 할 수 있는
범용적 주석(general purpose annotation) 기능을 가지고 있습니다.
이 기능은 주석타입을 선언하기 위한 구문, 주석처리 선언(annotating declarations)을 위한 구문,
주석을 읽기 위한 API들, 주석을 위한 클래스 파일 표현(a class file representation for annotations),
그리고 주석 처리 툴로 구성됩니다.

주석은 프로그램 시멘틱상에 직접적으로 영향을 주지 않습니다.
그러나 프로그램들이 툴과 라이브러리에 의해서 다뤄지는 방법으로 영향을 미치기 때문에
작동중인 프로그램의 시맨틱에 차례로 영향을 미칠 수 있습니다.
주석은 소스파일, 클래스 파일, 또는 실행시에 리플렉션으로 읽어낼 수 있습니다.

통상의 어플리케이션 프로그래머는 주석타입을 정의할 필요는 없습니다만, 정의하는 것은 그렇게 어려운 것은 아닙니다.
주석 타입 선언은 표준 인터페이스 선언하는거와 유사합니다.
at-sign(@)는 interface 키워드를 선행합니다.(위치적으로 interface키워드 앞에 놓입니다.)
각 메소드선언은 주석타입의 element를 선언합니다.
메소드선언은 parameters 또는 throws 절을 가져서는 안됩니다.
리턴타입은 primitives, String, Class, enums, annotations, 그리고 앞선타입의 배열들에 한정됩니다.
메소드는 기본값(default values)를 가질 수 있습니다.

주석타입 선언(annotation type declaration)의 예제>

        /**
         * Describes the Request-For-Enhancement(RFE) that led
         * to the presence of the annotated API element.
         */
        public @interface RequestForEnhancement {
            int    id();
            String synopsis();
            String engineer() default "[unassigned]";
            String date();    default "[unimplemented]";
        }

주석타입이 선언되면, 선언을 주석처리할 수 있습니다. 주석은 특별한 종류의 제어자(Modifier)이며,
다른 제어자(public, static, or final과 같은)가 사용되어질 수 있는 곳이면 어디서든 사용가능합니다.
단, 규칙(약정)에 의해 주석은 다른 제어자의 앞에 놓인다.
주석은 주석타입에 따른 at-sign(@)와 element-value 쌍으로 둘러쌓인 리스트로 구성된다.
값들은 컴파일타임 상수(compile-time constants)이여야만 한다.
다음은 주석타입에 해당하는 주석을 가지고 메소드선언한 예입니다.

        @RequestForEnhancement(
            id       = 2868724,
            synopsis = "Enable time-travel",
            engineer = "Mr. Peabody",
            date     = "4/1/3007"
        )
        public static void travelThroughTime(Date destination) { ... }

elements를 가지고 있지 않는 주석타입은 "marker" 주석타입이라 불립니다.

예)
        /**
         * Indicates that the specification of the annotated API element
         * is preliminary and subject to change.
         */
        public @interface Preliminary { }

다음에 보여지는 것처럼 marker 주석내에 괄호를 생략할 수 있습니다.

        @Preliminary public class TimeTravel { ... }

단일요소(single element)를 가지는 주석의 경우, 다음에서 보는것 처럼 element는 value 라고 이름지어집니다.

        /**
         * Associates a copyright notice with the annotated API element.
         */
        public @interface Copyright {
            String value();
        }
        
다음에서 보는 것 처럼, element명이 value인 single-element 주석에서는 element명과 등호(=)는 생략할 수 있습니다.

        @Copyright("2002 Yoyodyne Propulsion Systems")
        public class OscillationOverthruster { ... }

이 모든 것을 함게 묶기 위해 우리는 간단한 주석기반 테스트 프레임워크를 만들 것입니다.
첫번째 메소드가 테스트 메소드이고, 테스팅툴에서 실행가능해야하는 것을 나타내는 marker 주석타입이 필요로 합니다.

        import java.lang.annotation.*;
        
        /**
         * Indicates that the annotated method is a test method.
         * This annotation should be used only on parameterless static methods.
         */
        @Retention(RetentionPolicy.RUNTIME)
        @Target(ElementType.METHOD)
        public @interface Test { }

주석타입 선언은 그 자체가 주석이 되어 있는 것을 주의깊게 관찰하십시요.
이러한 주석은 meta-annotation이라고 불려집니다.
첫번째 (@Retention(RetentionPolicy.RUNTIME))는 이와 같은 타입을 가지는 주석은 VM에 의해서 유지되어지고 있기에
런타임에 리플렉션으로 읽어낼 수 있슴을 나타냅니다.
두번째 (@Target(ElementType.METHOD))는 이 주석타입은
단지 메소드선언만을 주석하기 위해서 사용되어지는 것을 나타냅니다.

다음은 일부 메소드가 상위인터페이스와 주석되어지는 예제 프로그램입니다.

        public class Foo {
            @Test public static void m1() { }
            public static void m2() { }
            @Test public static void m3() {
                throw new RuntimeException("Boom");
            }
            public static void m4() { }
            @Test public static void m5() { }
            public static void m6() { }
            @Test public static void m7() {
                throw new RuntimeException("Crash");
            }
            public static void m8() { }
        }

다음은 테스팅 툴입니다.

        import java.lang.reflect.*;

        public class RunTests {
           public static void main(String[] args) throws Exception {
              int passed = 0, failed = 0;
              for (Method m : Class.forName(args[0]).getMethods()) {
                 if (m.isAnnotationPresent(Test.class)) {
                    try {
                       m.invoke(null);
                       passed++;
                    } catch (Throwable ex) {
                       System.out.printf("Test %s failed: %s %n", m, ex.getCause());
                       failed++;
                    }
                 }
              }
              System.out.printf("Passed: %d, Failed %d%n", passed, failed);
           }
        }

툴은 커맨드라인 인수로 클래스명을 이용하고 Test 주석타입(앞서정의 된)으로 주석된
각 메소드를 호출하기 위해 시도하는 지정된 클래스의 모든 메소드 반복처리 합니다.
하나의 메소드가 Test 주석을 가지고 있는지 깨닫기 위한 리플렉티브한 조회는 녹색으로
강조 표시하고 있습니다. 만약 테스트 메소드 주석이 예외사항을 던진다면, 테스트는 실패된
것으로 간주되어 실패 레포트가 출력됩니다.
마지막으로 요점은 처리(성공)되고 실패되어진 테스트의 수가 프린되어집니다.
다음은 Foo 프로그램에 대해서 테스팅 툴을 실행하면 어떤결과가 나오는지 보여줍니다.

        $ java RunTests Foo
        Test public static void Foo.m3() failed: java.lang.RuntimeException: Boom
        Test public static void Foo.m7() failed: java.lang.RuntimeException: Crash
        Passed: 2, Failed 2

이 테스팅 툴은 알기 쉽게 간단한 것이지만, 주석의 기능(힘)을 설명하고 있고,
그 한계를 극복하기 위해 쉽게 확장할 수 있습니다.
Posted by 아름프로
<< PREV : [1] : [2] : [3] : [4] : [5] : [6] : [7] : [8] : [···] : [18] : NEXT >>

BLOG main image

카테고리

분류 전체보기 (539)
이야기방 (19)
토론/정보/사설 (16)
IBM Rational (9)
U-IT (0)
SOA/WS/ebXML (110)
개발방법론/모델링 (122)
J2SE (34)
J2EE (60)
DataBase (39)
Open Projects (30)
BP/표준화 (50)
Apache Projects (15)
Web/보안/OS (22)
Tools (7)
AJAX/WEB2.0 (1)
Linux/Unix (1)
영어 (0)
비공개방 (0)

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

달력

«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

글 보관함

Total :
Today : Yesterday :