| Developer:
J2EE & Web Services BPEL의
소개와 실습
by Matjaz Juric
직원의 출장 예약 웹 서비스를 위한 비즈니스 프로세스를 생성하고
Oracle BPEL Process Manager 런타임 환경에 deploy하는 방법을 설명합니다.
Business
Process Execution Language for Web Services(BPEL 또는 BPEL4WS)는
웹 서비스 환경에서 비즈니스 프로세스를 정의하고 실행하기 위한 표준 언어입니다. BPEL은 웹 서비스의 composition,
orchestration, coordination을 통해 탑-다운 방식으로 SOA(Service Oriented Architecture)를
구현합니다. BPEL을 이용하면 웹 서비스에 “비즈니스 프로세스(business process)”라 불리는 컴포지트
서비스(composite service)를 쉽게, 그리고 직관적으로 구현할 수 있습니다.
이 문서에서는, 가상적인 기업의 출장 예약 웹 서비스를 위한 비즈니스 프로세스를 생성하고, 생성된 프로세스를 Oracle
BPEL Process Manager 런타임 환경에 deploy하는 방법을 설명합니다.
BPEL의 소개
먼저 몇 가지 배경 지식을 설명하겠습니다. BPEL은 XML과 웹 서비스를 기반으로 하는 표준입니다. BPEL은
SOAP, WSDL, UDDI, WS-Reliable Messaging, WS-Addressing, WS-Coordination,
WS-Transaction 등을 포함하는 웹 서비스 테크놀로지 스택을 지원하기 위해 XML 기반 언어를 사용합니다.
BPEL은 이전의 두 가지 워크플로우 언어, 즉 Web Services Flow Language(WSFL)과 XLANG의
성과를 물려받은 차세대 언어입니다. IBM에 의해 처음 소개된 WSFL은 direct graph의 개념에 기반하고
있습니다. 블록-구조형 언어(block-structured language)인 XLANG은 Microsoft에 의해
설계되었습니다. BPEL은 두 가지 접근방식을 조합하고, 비즈니스 프로세스를 기술하기 위한 라이브러리를 제공합니다.
BPEL의 최초 버전은 2002년 8월 공개되었습니다. 그 이후로 (오라클을 비롯한) 많은 메이저 벤더들이 참여하면서
여러 가지 수정 및 개선 작업이 이루어졌고, 2003년 3월 버전 1.1이 발표되기에 이릅니다. 2003년 4월 BPEL은
표준화를 위해 OASIS(Organization for the Advancement of Structured Information
Standards)에 제출되었고, Web Services Business Process Execution Language
Technical Committee (WSBPEL
TC)가 설립되었습니다. 이러한 노력을 통해 업계에서의 BPEL의 확산 속도가 가속화되기
시작합니다.
기업 내부에서, BPEL은 엔터프라이즈 애플리케이션 통합 작업을 표준화하고, 더 나아가 통합의 범위를 기존의 (고립된)
시스템들로 확장하는 효과를 제공합니다. 또 기업과 기업 간을 연결하는 경우, BPEL은 비즈니스 파트너 간의 통합을
매우 효과적으로 지원합니다. BPEL은 비즈니스 프로세스의 정의를 통해 비즈니스 프로세스의 최적화, 리엔지니어링을
가능하게 하고, 가장 적합한 프로세스를 선택함으로써 기업 환경을 최적화할 수 있도록 합니다. BPEL에 의해 기술된
비즈니스 프로세스 정의는 기존 시스템에 영향을 미치지 않으며, 따라서 업그레이드가 용이합니다. BPEL은 웹 서비스를
통해 비즈니스 기능을 공개해야 하는 환경에서 핵심 테크놀로지로 활용됩니다. 웹 서비스의 확산과 더불어 BPEL의 중요성
역시 계속적으로 증가하는 추세를 보일 것입니다.
Orchestration vs. Choreography
웹 서비스는 일반적으로 특정 애플리케이션 또는 정보 시스템의 기능을 외부에 공개(expose)하는 목적으로 활용됩니다.
따라서 다수의 웹 서비스들을 통합(compose)함으로써, 하부의 애플리케이션과 각 기능들을 통합하는 효과를 얻을
수 있습니다.
웹 서비스의 통합에는 두 가지 방법이 사용됩니다:
- Orchestration
- Choreography
“Orchestration”은 기업의 내부적인 비즈니스 프로세스에 주로 사용되며, 중앙 프로세스(다른 웹 서비스)가
관련 웹 서비스들을 통제하고 각각의 웹 서비스가 실행하는 작업을 조율하는 방식으로 통합 환경을 구현합니다. 관련된
웹 서비스들은, 자신이 하이 레벨 비즈니스 프로세스에 의해 통합된 작업 환경에서 동작하고 있다는 사실을 알지 못합니다.
Orchestration에 가담하는 중앙 프로세스만이 이러한 목표를 인지하고 있습니다. 이처럼 웹 서비스들의 호출
순서와 작업 방법을 명시적으로 정의함으로써 중앙집중화된 orchestration 환경을 구현할 수 있습니다 (그림
1 참고).
 |
| 그림 1: Orchestration을
이용한 웹 서비스의 composition |
“Choreography"는 중앙의 coordinator에 의존하지 않습니다. 대신 choreography에
가담하는 각각의 웹 서비스가 실행 순서와 대상을 명확하게 알고 있습니다. Choreography는 기업 간 비즈니스
프로세스 환경에서의 메시지 교환에 초점을 맞춘 협업 방식입니다. Choreography에 참여하는 모든 개체들은 비즈니스
프로세스, 실행되는 작업, 교환되는 메시지, 메시지 교환의 시점을 명확히 이해하고 있어야 합니다 (그림 2 참고).
 |
| 그림 2: Choreography를
이용한 웹 서비스의 composition |
웹 서비스를 통합하고 비즈니스 프로세스를 실행하려는 경우, orchestration은 choreography에
비해 유연한 패러다임을 가지며 다음과 같은 상대적인 장점을 제공합니다:
- 컴포넌트 프로세스의 조율 작업이 중앙 프로세스에 의해 중앙집중적으로 관리됩니다.
- 각각의 웹 서비스가, 자신이 하이 레벨 비즈니스 프로세스에 의해 통제되고 있다는 사실을 인지하고 있을 필요가
없습니다.
- 문제 발생시 대안적인 시나리오를 적용할 수 있습니다.
BPEL은 orchestration과 choreography를 지원하기
위해, 두 종류의 비즈니스 프로세스 정의 방법을 지원합니다.
- Executable process 비즈니스 프로세스의 상세한 내용을 정의합니다.
“orchestration” 패러다임을 따르며, orchestration 엔진에 의해 실행됩니다.
- bstract business protocol 조직 간의 퍼블릭 메시지(public
message) 교환 방법을 정의합니다. 프로세스 플로우의 상세한 정의를 포함하지 않으며 실행이 불가능합니다.
Abstract business protocol은 “choreograph” 패러다임을 따릅니다.
이제, executable process를 정의하는 과정을 실습해 보겠습니다. 먼저 코드를 다운로드하여 Oracle
BPEL Process Manager에 deploy합니다. 여기에서는 Oracle
BPEL Process Manager가 성공적으로 설치되었고 디폴트 포트(9700)을 사용한다고
가정하겠습니다. 만일 다른 포트를 사용하는 경우에는 샘플 코드를 이에 맞추어 변경해 주어야 합니다.
비즈니스 프로세스의 Build
BPEL 프로세스는, 프로세스에 참여하는 웹 서비스들의 정확한 호출 순서(순차적 또는 병렬적)를 정의하고 있습니다.
BPEL은 조건부 실행문을 지원합니다. 예를 들어, 이전 호출 결과값에 따라 웹 서비스의 호출 여부를 결정할 수 있습니다.
이를 위해 루프를 정의하고, 변수를 선언하고, 변수 값을 복제/할당하고, 에러 핸들러를 정의할 수 있습니다. 이러한
요소들을 조합하여 알고리즘에 기반한 복잡한 비즈니스 프로세스를 정의하는 것이 가능합니다. 실제로 대부분의 비즈니스
프로세스가 다양한 액티비티(activity)를 포함하는 그래프 형태로 표현되기 때문에, Unified Modeling
Language (UML) activity diagram을 이용하여 이러한 구조를 표현하는 것이 유용한 경우가 많습니다.
BPEL 비즈니스 프로세스는 접수된 요청을 처리하기 위해 관련된 웹 서비스들을 호출하고 그 결과를 반환하는 방식으로
동작합니다. BPEL 프로세스가 다른 웹 서비스와 커뮤니케이션을 수행하는 과정에서는 각 웹 서비스에 대한 WSDL
description이 매우 중요하게 활용됩니다.
예를 들어 설명해 보겠습니다. BPEL 프로세스는 여러 개의 스텝(step)으로 구성되며, 각각의 스텝은 “액티비티(activity)”라
불립니다. BPEL은 primitive activity와 structure activity를 모두 지원합니다. “Primitive”
activity는 일반적인 태스크에 사용되는 가장 기본적인 구성요소를 정의합니다. 그 예가 아래와 같습니다:
- <Invoke>: 다른 웹 서비스의 호출
- <receive>: 클라이언트가 메시지를 전달함으로써 비즈니스 프로세스를 호출할 때까지 대기
- <reply>: 동기화 작업의 응답 생성
- <assign>: 데이타 변수의 값 할당
- <throw>: 폴트 및 예외 발생
- <wait>: 일정 시간 대기
- <terminate>: 전체 프로세스의 종료
이러한 액티비티와 다른 액티비티들을 조합하여 비즈니스 프로세스의 각 단계를 정의하는 복잡한 알고리즘을 구현할 수 있습니다.
“Structure” activity를 사용하면 여러 개의 primitive activity를 조합할 수 있습니다. 몇
가지 중요한 예가 아래와 같습니다:
- ·Sequence (<sequence>): 일정한 순서로 호출되는 액티비티의 집합을 정의
- ·Flow (<flow>): 병렬적으로 호출되는 액티비티의 집합을 정의
- ·Case-switch construct (<switch>): 분기 조건의 구현
- · While (<while>): 루프 정의
- ·<pick>: 다양한 실행 경로 중 하나를 선택
또 <partnerLink>를 통해 파트너 링크를 정의하고, <variable>을 통해 변수를
선언할 수 있습니다.
BPEL을 이용하여 비즈니스 프로세스를 정의하는 방법을 이해하기 위해, 직원들의 출장 일정 예약을 위한 비즈니스
프로세스를 정의해 보기로 합시다: 클라이언트는 직원의 이름과 목적지, 출발일자, 복귀일자를 명시하고 비즈니스 프로세스를
호출합니다. BPEL 비즈니스 프로세스는 먼저 직원의 출장 상태(travel status)를 점검합니다 (여기에서는
점검 작업을 수행하는 별도의 웹 서비스가 존재한다고 가정하겠습니다). 다음으로 BPEL 프로세스는 두 항공사(American
Airline, Delta Airline)의 항공권 가격을 대조합니다 (여기에서도 역시 두 항공사가 항공권 가격 조회를
위한 웹 서비스를 제공한다고 가정합니다). 마지막으로 BPEL 프로세스는 가장 낮은 가격을 제시한 항공사의 티켓을
선택하고 클라이언트에 출장 일정을 반환합니다.
다음으로는 비동기식 BPEL 프로세스를 구현할 차례입니다. 직원의 출장 상태를 점검하는 웹 서비스가 동기식으로 호출된다고
가정합시다 이와 같은 유형의 데이타는 바로 조회하여 클라이언트에 반환할 수 있기 때문에 동기식으로 구현하는 것이 타당합니다.
반면, 비행 일정을 확인할 때에는 좀 더 많은 시간이 걸리는 것이 일반적으로, 비행기 티켓의 가격을 조회할 때에는
비동기식 호출(asynchronous invocation)을 사용합니다. 여기에서는 두 항공사가 동일한 형태의 웹
서비스(동일한 포트 타입과 작업)을 사용한다고 가정하겠습니다.
실제 시나리오에서라면, 파트너가 제공하는 웹 서비스를 (그것이 어떠한 유형이든) 그대로 사용할 수 밖에 없을 것입니다.
반면 BPEL 프로세스와 웹 서비스를 동시에 설계할 수 있는 환경이 허용된다면, 어떤 인터페이스를 사용할 것인지 검토할
수 있습니다. 비교적 오랜 시간이 걸리는 작업에는 비동기식 서비스(asynchronous service)를, 바로
결과를 반환할 수 있는 작업에는 동기식 서비스(synchronous service)를 사용하는 것이 좋습니다. 또
비동기식 웹 서비스가 사용되는 경우, BPEL 프로세스 역시 비동기식으로 구현되는 것이 일반적입니다.
BPEL에서 비즈니스 프로세스를 정의하는 과정에서, 기존 서비스를 조합하여 새로운 컴포지트(composite) 웹
서비스를 구현하게 됩니다. BPEL 컴포지트 웹 서비스의 인터페이스는 다른 웹 서비스와 마찬가지로 일련의 포트 타입(port
type)을 사용하여 작업을 수행합니다. BPEL에 정의된 비즈니스 프로세스를 호출하려면, BPEL 정의 결과로 생성된
컴포지트 웹 서비스를 호출해야 합니다. 그림 3은 예제 프로세스의 스키마틱 뷰(schematic view)를 보여주고
있습니다.
 |
| 그림 3: 출장 일정 예약을 위한 예제
BPEL 프로세스 |
샘플 BPEL 프로세스를 생성하기 위한 과정이 아래와 같습니다:
- 먼저, 관련된 웹 서비스의 구조를 이해합니다.
- BPEL 프로세스를 위한 WSDL을 정의합니다.
- 파트너 링크 타입(partner link type)을 정의합니다.
- BPEL 프로세스를 개발합니다.
- 파트너 링크를 정의하고,
- 변수를 선언하고,
- 프로세스 로직 정의(process logic definition)를 작성합니다.
1 단계: 관련 웹 서비스의 인벤토리 작성
BPEL 프로세스 정의 작업을 시작하기 전에, 구현할 비즈니스 프로세스에서 호출하는 웹 서비스들에 대해 먼저 이해할
필요가 있습니다. 이 서비스들은 “파트너 웹 서비스(partner web service)”라 불립니다. 예제에서는
Employee Travel Status 웹 서비스와 American / Delta Airline 웹 서비스가 파트너
웹 서비스에 해당됩니다 (이 예제에 사용되는 웹 서비스는 가상의 것임을 다시 한 번 밝힙니다).
Employee Travel Status 웹 서비스 Employee Travel Status
웹 서비스는 “EmployeeTravelStatusPT” 포트 타입(port type)을 통해 EmployeeTravelStatus
작업(operation)을 수행하고 직원의 출장 상태를 점검합니다. Employee Travel Status 웹 서비스는
직원이 사용할 수 있는 비행기 좌석 등급(economy, business 또는 first)을 반환합니다 (그림 4
참고).
 |
| 그림 4: Employee Travel
Status 웹 서비스 |
Airline 웹 서비스 Airline 웹 서비스는 비동기식으로 수행됩니다. 먼저,
FlightAvailabilityPT 포트 타입을 통해 FlightAvailability 작업을 수행하고 좌석의 예약가능여부를
확인합니다. 웹 서비스는 결과를 반환하기 위해 두 번째 포트 타입, FlightCallbackPT를 사용합니다. 이
포트를 통해서 FlightTicketCallback 작업이 수행됩니다.
Airline 웹 서비스 내부에는 FlightAvailabilityPT 만이 구현되며, FlightCallbackPT는
BPEL 프로세스에 의해 구현됩니다. 웹 서비스 아키텍처의 스키마틱 뷰가 그림 5와 같습니다.
 |
| Figure 5: The Airline
web service |
2 단계: BPEL 프로세스를 위한 WSDL의 정의
다음으로, BPEL 프로세스를 웹 서비스의 형태로 공개하는데 사용할 WSDL을 정의합니다. 이 프로세스에서는 클라이언트로부터
메시지를 전달받고 결과를 반환하는 과정이 수반되므로, 입력 메시지를 위한TravelApprovalPT 포트 타입과
(callback을 사용한 비동기식) 결과 반환을 위한 ClientCallbackPT 포트 타입을 정의합니다 (그림
6 참고).
 |
| 그림 6: BPEL 프로세스를 위한
WSDL |
3 단계: 파트너 링크 타입의 정의
세 번째 단계에서는 파트너 링크 타입(partner link type)을 정의합니다. 파트너 링크 타입은 BPEL
프로세스와 관련 개체들 간의 상호작용을 정의하는데 사용되며, 여기에는 BPEL 프로세스가 호출하는 웹 서비스, 그리고
BPEL 프로세스를 호출하는 클라이언트에 대한 정의가 함께 포함됩니다.
예제에서는, 세 종류의 파트너(클라이언트, Employ Travel Status 서비스, Airline 서비스)가
사용됩니다. 이상적인 환경이라면 각각의 웹 서비스에 (WSDL을 이용하여) 각각의 파트너 링크 타입을 정의할 수 있을
것입니다 (하지만 실제 상황에서는 이러한 경우가 드뭅니다). 다음으로, 각 웹 서비스의 WSDL을 임포트(import)하고
파트너 링크 타입을 정의하는 WSDL을 구현하고, 구현된 WSDL을 사용하여 파트너 웹 서비스에 대한 래핑(wrapping)을
수행합니다. 또는 BPEL 프로세스의 WSDL 안에 모든 파트너 링크를 정의할 수도 있습니다. 하지만 이러한 방법은
encapsulation의 기본 원칙을 위반한다는 이유에서 권장되지 않습니다.
예제에서는 웹 서비스의 WSDL에 세 가지 파트너 링크 타입을 정의하였습니다:
- travelLT: BPEL 프로세스 클라이언트와 BPEL 프로세스 간의 상호작용을
기술하는데 사용됩니다. 이 작업은 비동기식으로 실행됩니다. travelLT 파트너 링크 타입은 BPEL 프로세스의
WSDL에 정의됩니다.
- employeeLT: BPEL 프로세스와 Employee Travel Status
웹 서비스 간의 상호작용을 기술하는데 사용됩니다. 이 작업은 동기식으로 실행됩니다. employeeLT 파트너
링크 타입은 Employee Travel Status 웹 서비스의 WSDL에 정의됩니다.
- flightLT: BPEL 프로세스와 Airline 웹 서비스 간의 상호 작용을
기술하는데 사용됩니다. 이 작업은 동기식으로 실행되며, Airline 웹 서비스는 BPEL 프로세스에 대하여 callback
호출을 수행합니다. flightLT 파트너 타입 링크는 Airline 웹 서비스의 WSDL에 정의됩니다.
각각의 파트너 링크 타입은 한 가지 또는 두 가지의 role을 가지며, 각각의 role에는 role이 사용하는
portType가 정의됩니다. 동기식 작업의 경우 작업이 단방향으로 호출되므로 각각의 파트너 링크에는 하나의 role이
사용됩니다. 예를 들어 BPEL 프로세스가 Employee Travel Status 웹 서비스에 대해 EmployeeTravelStatus
작업을 호출한 경우, (이 작업이 동기식으로 수행되므로) BPEL 프로세스는 작업이 완료될 때까지 기다려 결과를 접수합니다.
비동기식 callback 작업의 경우 두 가지 role이 정의됩니다. 첫 번째 role은 클라이언트가 작업을 호출하는
과정을, 두 번째 role은 callback 작업이 호출하는 과정을 정의하는데 사용됩니다. 예제에서는 BPEL 프로세스와
Airline 웹 서비스가 비동기식 관계를 갖습니다.
지금까지 설명한 것처럼 세 가지 파트너 링크 타입을 정의해야 합니다: 그 중 두 가지는 비동기식으로 수행되므로 2개의
role을 가지며, 나머지 한 가지는 동기식으로 수행되므로 1개의 role을 갖습니다.
파트너 링크 타입은 특별한 네임스페이스를 갖는 WSDL을 통해 정의됩니다 (http://schemas.xmlsoap.org/ws/2003/05/partner-link/).
제일 먼저, 클라이언트가 BPEL 프로세스를 호출할 때 사용하는 “travelLT” 링크 타입을 BPEL 프로세스의
WSDL에 정의해 봅시다. 첫 번째로 BPEL 프로세스를 위한 role을 정의해야 합니다. 클라이언트는 TravelApprovalPT
포트 타입을 사용하여 BPEL 프로세스와 커뮤니케이션을 수행합니다. 두 번째 role인 travelServiceCustomer는
ClientCallbackPT 포트 타입을 통해 BPEL 프로세스가 callback을 수행할 클라이언트를 정의합니다:
<plnk:partnerLinkType name="travelLT">
<plnk:role name="travelService">
<plnk:portType name="tns:TravelApprovalPT" />
</plnk:role>
<plnk:role name="travelServiceCustomer">
<plnk:portType name="tns:ClientCallbackPT" />
</plnk:role>
</plnk:partnerLinkType>
두 번째로 “employeeLT” 포트 타입을 구현할 차례입니다. employeeLT 포트
타입은 BPEL 프로세스와 Employee Travel Status 웹 서비스 간의 커뮤니케이션을 기술하며, Employee
Travel Status 웹 서비스의 WSDL에 정의됩니다. 이 경우 동기식 작업이 수행되므로, employeeTravelStatusService라는
하나의 role만이 필요합니다. BPEL 프로세스는 Employee Travel Status 웹 서비스의 EmployeeTravelStatusPT를
통해 커뮤니케이션을 수행합니다.
<plnk:partnerLinkType name="employeeLT">
<plnk:role name="employeeTravelStatusService">
<plnk:portType name="tns:EmployeeTravelStatusPT" />
</plnk:role>
</plnk:partnerLinkType>
마지막으로 “flightLT” 파트너 링크 타입은 BPEL 프로세스와 Airline 웹 서비스
간의 커뮤니케이션을 기술하는데 사용됩니다. 이 작업은 비동기식으로 수행됩니다. BPEL 프로세스는 Airline 웹
서비스의 작업을 비동기식으로 호출합니다. Airline 웹 서비스는 요청을 처리한 후 BPEL 프로세스에 대해 callback
호출을 수행합니다. 따라서 두 개의 role이 필요합니다. 첫 번째 role은 BPEL 프로세스에 대한 Airline
웹 서비스의 역할(“airlineService”)을 정의합니다. BPEL 프로세스는 FlightAvailabilityPT
포트 타입을 이용하여 비동기식 호출을 수행합니다. 두 번째 role은 Airline 웹 서비스에 대한 BPEL 프로세스의
역할을 정의합니다. BPEL 프로세스는 Airline 웹 서비스에 대해 고객의 역할을 가지므로 “airlineCustomer”라는
role 이름이 사용됩니다. Airline 웹 서비스는 FlightCallbackPT 포트 타입을 사용하여 callback을
수행합니다. flightLT 파트너 링크 타입은 Airline 웹 서비스의 WSDL에 정의됩니다:
<plnk:partnerLinkType name="flightLT">
<plnk:role name="airlineService">
<plnk:portType name="tns:FlightAvailabilityPT" />
</plnk:role>
<plnk:role name="airlineCustomer">
<plnk:portType name="tns:FlightCallbackPT" />
</plnk:role>
</plnk:partnerLinkType>
BPEL 프로세스를 구현하는 과정에서 파트너 링크 타입을 이해하는 것은 매우 중요합니다.
파트너 간의 상호작용을 다이어그램을 통해 표현하는 것이 도움이 될 수도 있습니다. 파트너 링크 타입의 정의가 완료함으로써
준비 단계를 마무리하고, 이제 본격적으로 비즈니스 프로세스를 작성할 차례입니다.
4 단계: 비즈니스 프로세스의 생성
이제 BPEL 프로세스를 작성하기 위한 모든 준비가 완료되었습니다. 일반적으로, BPEL 프로세스는 클라이언트로부터
메시지를 받아 비즈니스 프로세스를 실행하는 형태로 동작합니다. 예제에서는 클라이언트가 TravelRequest 메시지를
전달하여 BPEL 프로세스를 시작합니다. 다음으로 BPEL 프로세스는 Employee Travel Status 웹
서비스를 호출하고, EmployeeTravelStatusRequest 메시지를 전송합니다. 이 호출 작업은 동기식으로
수행되며, BPEL 프로세스는 EmployeeTravelStatusResponse 메시지가 반환될 때까지 대기합니다.
메시지가 반환되면, BPEL 프로세스는 두 종류의 Airline 웹 서비스에 FlightTicketRequest 메시지를
전송함으로써, 두 웹 서비스를 비동기식으로 동시 호출합니다. 각각의 Airline 웹 서비스는 callback을 수행하고
TravelResponse 메시지를 반환합니다. BPEL 프로세스는 가장 낮은 가격을 제시한 항공사를 선택하고 클라이언트에게
TravelResponse 메시지를 전달합니다.
먼저 기본적인 프로세스 정의 구문만을 포함하는 빈 BPEL 프로세스를 생성합니다:
<process name="BusinessTravelProcess" ... >
<partnerLinks>
<!-- The declaration of partner links -->
</partnerLinks>
<variables>
<!-- The declaration of variables -->
</variables>
<sequence>
<!-- The definition of the BPEL business process main body -->
</sequence>
</process>
다음에는 네임스페이스(namespace)를 추가합니다. 예제의 경우, 타겟 네임스페이스와
Employee Travel Status WSDL, Airline WSDL, BPEL 프로세스 WSDL을 액세스하기
위한 네임스페이스를 정의해야 합니다. 또 모든 BPEL 액티비티 태그를 위한 네임스페이스를 선언해야 합니다 (여기서는
디폴트 네임스페이스이므로, 각각의 BPEL 태그 이름을 명기할 필요는 없습니다). BPEL 액티비티 네임스페이스(http://schemas.xmlsoap.org/ws/2003/03/business-process/:)는
다음과 같이 정의됩니다:
<process name="BusinessTravelProcess"
targetNamespace="http://packtpub.com/bpel/travel/"
xmlns="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
xmlns:trv="http://packtpub.com/bpel/travel/"
xmlns:emp="http://packtpub.com/service/employee/"
xmlns:aln="http://packtpub.com/service/airline/" >
...
파트너 링크 이제 파트너 링크를 정의해 봅시다. 파트너 링크는 BPEL 프로세스와 커뮤니케이션하는
다른 개체들을 정의하는데 사용됩니다. 각각의 파트너 링크는 특정 partnerLinkType과 연결되어 있으며, 최대
두 가지 속성을 가집니다:
- myRole: 비즈니스 프로세스의 role을 의미합니다.
- partnerRole: 파트너의 role을
의미합니다.
파트너 링크에서 role을 하나만 정의할 수도 있으며, 동기식 요청/응답 작업에서 이러한 방법이 주로 사용됩니다.
비동기식 작업에서는 두 개의 role이 사용됩니다. 예제에서는 모두 4개의 role이 정의됩니다. 첫 번째 파트너
링크(“client”)는 travelLT 파트너 링크 타입과 연관됩니다. client가 호출하는 BPEL 프로세스의
role(travelService)을 위한 myRole 속성을 정의해야 합니다. 그리고 partnerRole 속성으로는
BPEL 프로세스 클라이언트를 위한 “travelServiceCustomer”를 정의합니다.
두 번째 파트너 링크는 employeeTravelStatus라는 이름으로 불리며 employeeLT 파트너 링크 타입을
사용합니다. 이 경우 BPEL 프로세스와 웹 서비스 간에 동기식 요청/응답이 사용되므로 하나의 role만이 정의됩니다.
이 경우 BPEL 프로세스의 파트너 역할을 담당하는 웹 서비스의 role을 정의해야 하므로 “partnerRole”이
사용됩니다.
마지막 두 개의 파트너 링크는 Airline 웹 서비스와 연관됩니다. 두 가지 웹 서비스의 유형이 동일하므로, 하나의
파트너 링크 타입(flightLT)을 기준으로 두 개의 파트너 링크를 정의할 수 있습니다. 또 비동기식 callback
커뮤니케이션이 사용되므로 두 개의 role을 정의해야 합니다. Airline 웹 서비스에 대한 BPEL 프로세스의
role(myRole)은 “airlineCustomer”로, Airline 웹 서비스의 role(partnerRole)은
“airlineService”로 정의됩니다:
<partnerLinks>
<partnerLink name="client"
partnerLinkType="trv:travelLT"
myRole="travelService"
partnerRole="travelServiceCustomer"/>
<partnerLink name="employeeTravelStatus"
partnerLinkType="emp:employeeLT"
partnerRole="employeeTravelStatusService"/>
<partnerLink name="AmericanAirlines"
partnerLinkType="aln:flightLT"
myRole="airlineCustomer"
partnerRole="airlineService"/>
<partnerLink name="DeltaAirlines"
partnerLinkType="aln:flightLT"
myRole="airlineCustomer"
partnerRole="airlineService"/>
</partnerLinks>
변수 BPEL 프로세스는 변수를 사용하여 메시지를 저장, 변경,
전송합니다. 파트너로부터 주고 받는 각각의 메시지에 대해 변수를 정의해야 합니다. 예제 프로세스에서는 모두 7개의
변수가 필요하며, 다음과 같은 이름으로 정의하기로 합니다: TravelRequest, EmployeeTravelStatusRequest,
EmployeeTravelStatusResponse, FlightDetails, FlightResponseAA, FlightResponseDA,
TravelResponse.
각각의 변수마다 타입(type)을 설정해 주어야 합니다. 변수의 타입에는 WSDL message type, an XML
Schema simple type, XML Schema element 등이 있습니다. 예제에서는 모든 변수에 대해
WSDL message type을 사용합니다:
<variables>
<!-- input for this process -->
<variable name="TravelRequest"
messageType="trv:TravelRequestMessage"/>
<!-- input for the Employee Travel Status web service -->
<variable name="EmployeeTravelStatusRequest"
messageType="emp:EmployeeTravelStatusRequestMessage"/>
<!-- output from the Employee Travel Status web service -->
<variable name="EmployeeTravelStatusResponse"
messageType="emp:EmployeeTravelStatusResponseMessage"/>
<!-- input for American and Delta web services -->
<variable name="FlightDetails"
messageType="aln:FlightTicketRequestMessage"/>
<!-- output from American Airlines -->
<variable name="FlightResponseAA"
messageType="aln:TravelResponseMessage"/>
<!-- output from Delta Airlines -->
<variable name="FlightResponseDA"
messageType="aln:TravelResponseMessage"/>
<!-- output from BPEL process -->
<variable name="TravelResponse"
messageType="aln:TravelResponseMessage"/>
</variables>
BPEL 프로세스 메인 바디 프로세스의 메인 바디(main
body)에서는 파트너 웹 서비스를 호출하는 순서를 정의합니다. 보통 제일 먼저 <sequence>를 사용하여
순차적으로 실행되는 액티비티들을 정의합니다. Sequence에서 비즈니스 프로세스를 실행할 때 사용할 입력 메시지를
정의하기 위해 <receive>를 활용합니다. <receive>는 매치되는 메시지(예제의 경우
TravelRequest 메시지)가 입력될 때까지 대기합니다. 이때 입력 메시지를 <receive> 구문
안에 직접 정의하는 대신, 파트너 링크와 포트 타입, 작업 이름(operation name)을 정의하고 필요한 경우
후속 작업의 메시지 입력에 사용할 변수를 지정합니다.
예제에서는 클라이언트 파트너와 접수되는 메시지를 링크하고, 포트 타입 TravelApprovalPT를 통해 TravelApproval
작업이 호출될 때까지 대기합니다. 접수된 메시지는 TravelRequest 변수에 입력합니다:
<sequence>
<!-- Receive the initial request for business travel from client -->
<receive partnerLink="client"
portType="trv:TravelApprovalPT"
operation="TravelApproval"
variable="TravelRequest"
createInstance="yes" />
...
<receive>는 클라이언트가 TravelApproval 작업을 호출할 때까지
대기하였다가, 접수한 메시지와 출장 일정에 관련한 매개변수를 TravelRequest 변수에 저장합니다. 이 경우
변수와 메시지에 동일한 이름이 사용되었습니다 (하지만 반드시 그래야 하는 것은 아닙니다).
다음으로, Employee Travel Status 웹 서비스를 호출해야 합니다. 그 전에 Employee Travel
Status 웹 서비스를 위한 입력 값을 생성해야 합니다. Employee Travel Status 웹 서비스의 WSDL를
살펴 보면, “employee” part를 포함하는 메시지를 전송해야 함을 알 수 있습니다. 클라이언트에 전송되는
메시지에 employee part를 복사하여 필요한 메시지를 구성할 수 있습니다. 아래와 같이 <assign>
구문을 작성합니다:
...
<!-- Prepare the input for the Employee Travel Status Web Service -->
<assign>
<copy>
<from variable="TravelRequest" part="employee"/>
<to variable="EmployeeTravelStatusRequest" part="employee"/>
</copy>
</assign>
...
이제 Employee Travel Status 웹 서비스를 호출할 준비가 완료되었습니다.
<invoke> 액티비티를 사용하여 동기식 호출을 수행합니다. employeeTravelStatus 파트너
링크를 사용하여 EmployeeTravelStatusPT 포트 타입의 EmployeeTravelStatus 작업을
호출합니다. 입력 메시지는 EmployeeTravelStatusRequest 변수에 저장됩니다. 호출 작업이 동기식으로
수행되기 때문에, 호출 결과는 EmployeeTravelStatusResponse 변수에 바로 저장됩니다.
...
<!-- Synchronously invoke the Employee Travel Status Web Service -->
<invoke partnerLink="employeeTravelStatus"
portType="emp:EmployeeTravelStatusPT"
operation="EmployeeTravelStatus"
inputVariable="EmployeeTravelStatusRequest"
outputVariable="EmployeeTravelStatusResponse" />
...
다음에는 두 가지 Airline 웹 서비스를 호출할 차례입니다. 이번에도 입력 메시지를 생성하여
저장해야 합니다. American / Delta Airline 웹 서비스가 사용하는 FlightTicketRequest
메시지는 두 개의 영역으로 나뉩니다:
- flightData: 클라이언트 메시지(TravelRequest)로부터
가져오는 부분입니다.
- travelClass: EmployeeTravelStatusResponse
변수로부터 가져오는 부분입니다.
아래와 같이 두 개의 <copy>를 포함하는 <assign>
구문을 작성합니다:
...
<!-- Prepare the input for AA and DA -->
<assign>
<copy>
<from variable="TravelRequest" part="flightData"/>
<to variable="FlightDetails" part="flightData"/>
</copy>
<copy>
<from variable="EmployeeTravelStatusResponse" part="travelClass"/>
<to variable="FlightDetails" part="travelClass"/>
</copy>
</assign>
...
입력 데이타에는 Airline 웹 서비스에 전달되어야 하는 데이타가 포함되어 있습니다. 예제에서는
두 가지 데이타가 동일한 포맷을 사용하기 때문에, (단순 copy 명령을 사용하여) 직접 전달하는 것이 가능합니다.
하지만 실제 환경에서라면 변환(transformation) 작업을 수행해야 하는 경우가 대부분입니다. 변환 작업을
수행하려면 <assign> 문에 XPath 표현식을 사용하거나, (XSLT 엔진과 같은) 변환 서비스를
사용하거나, BPEL 서버가 내부적으로 제공하는 변환 기능을 이용해야 합니다.
이제 American / Delta Airline 웹 서비스를 호출할 준비가 완료되었습니다. 여기에서는 비동기식 호출
작업을 병렬적으로 수행합니다. BPEL의 <flow> 액티비티를 이용하면 작업의 병렬 수행이 가능합니다.
각 웹 서비스의 호출 작업은 두 단계로 나뉘어집니다:
- <invoke> 액티비티 – 비동기식 호출을 위해 사용
- <receive> 액티비티 – callback에 대한 대기를 위해 사용
여기에서는 하나의 <sequence> 안에 두 가지 액티비티를 포함시킵니다. American Airline
웹 서비스와 Delta Airline 웹 서비스는 partner link name(“AmericanAirlines”와
“DeltaAirlines”)을 제외하고는 모두 동일한 구성을 갖습니다. 두 가지 웹 서비스 모두 FlightAvailabilityPT
포트 타입을 통해 FlightAvailability작업을 호출하고 FlightDetails 변수에 저장된 메시지를
전송합니다.
callback에 대한 회신은 <receive> 액티비티를 통해 접수합니다. 여기에서도 partner link
name을 이용하여 두 웹 서비스를 구분합니다. <receive> 액티비티는 FlightCallbackPT
포트 타입을 통해 FlightTicketCallback 작업이 호출될 때까지 대기합니다. 그 결과로 반환되는 메시지는
FlightResponseAA와 FlightResponseDA 변수에 저장합니다:
...
<!-- Make a concurrent invocation to AA in DA -->
<flow>
<sequence>
<!-- Async invoke of the AA web service and wait for the callback-->
<invoke partnerLink="AmericanAirlines"
portType="aln:FlightAvailabilityPT"
operation="FlightAvailability"
inputVariable="FlightDetails" />
<receive partnerLink="AmericanAirlines"
portType="aln:FlightCallbackPT"
operation="FlightTicketCallback"
variable="FlightResponseAA" />
</sequence>
<sequence>
<!-- Async invoke of the DA web service and wait for the callback-->
<invoke partnerLink="DeltaAirlines"
portType="aln:FlightAvailabilityPT"
operation="FlightAvailability"
inputVariable="FlightDetails" />
<receive partnerLink="DeltaAirlines"
portType="aln:FlightCallbackPT"
operation="FlightTicketCallback"
variable="FlightResponseDA" />
</sequence>
</flow>
...
이 과정에서 접수된 두 가지 항공권 가격 제안 중
하나를 선택해야 합니다. 이 작업을 위해 <switch> 액티비티를 사용합니다:
...
<!-- Select the best offer and construct the TravelResponse -->
<switch>
<case condition="bpws:getVariableData('FlightResponseAA',
'confirmationData','/confirmationData/Price')
<= bpws:getVariableData('FlightResponseDA',
'confirmationData','/confirmationData/Price')">
<!-- Select American Airlines -->
<assign>
<copy>
<from variable="FlightResponseAA" />
<to variable="TravelResponse" />
</copy>
</assign>
</case>
<otherwise>
<!-- Select Delta Airlines -->
<assign>
<copy>
<from variable="FlightResponseDA" />
<to variable="TravelResponse" />
</copy>
</assign>
</otherwise>
</switch>
...
<case> 구문을 통해 American Airline의 제안가격(FlightResponseAA)이
Delta Airline의 제안가격(FlightResponseDA)보다 크거나 같은지 확인합니다. 이를 위해 BPEL
함수 getVariableData가 사용됩니다. 제안된 가격은 confirmationData message part에
저장되어 있습니다. 따라서 confirmationData message part를 명시하고, 이와 별도로 가격을 확인하기
위한 쿼리 표현식을 명시해야 합니다 (예제에서는 XPath 1.0 표현식이 사용되었습니다).
American Airline이 Delta Airline보다 낮은 가격을 제시한 경우, FlightResponseAA
변수를 TravelResponse 변수에 복사하고, 그 결과를 클라이언트에 반환합니다. 그렇지 않은 경우에는 FlightResponseDA
변수를 복사합니다.
이제 BPEL 비즈니스 프로세스 구현 작업의 마지막 단계로, <invoke> 액티비티를 사용하여 클라이언트에
대한 callback을 반환할 차례입니다. Callback을 위해, 클라이언트 파트너 링크를 사용하고 ClientCallbackPT
포트 타입을 통해 ClientCallback 작업을 호출합니다. 클라이언트에 반환되는 메시지는 TravelResponse
변수에 저장됩니다:
...
<!-- Make a callback to the client -->
<invoke partnerLink="client"
portType="trv:ClientCallbackPT"
operation="ClientCallback"
inputVariable="TravelResponse" />
</sequence>
</process>
이와 같이 하여, BPEL을 이용하여 비즈니스 프로세스를 정의하는 작업을 완료하였습니다. 지금까지 확인하신 것처럼, BPEL을
이용해서 비즈니스 프로세스를 구현하는 작업은 비교적 쉽고 직관적입니다.
5 단계: Deploy 및 테스트
Oracle BPEL Process Manager를 이용해서 BPEL 프로세스를 deploy하려면 각 프로세스마다
process descriptor를 정의해야 합니다. Process descriptor는 BPEL 표준에 정의되어
있지 않으며, 따라서 BPEL 솔루션마다 다른 방식으로 구현됩니다. 구현된 프로세스를 다른 BPEL 엔진에 적용해야
하는 경우, process descriptor만을 수정하면 됩니다. 오라클의 process descriptor는 XML
파일로 구현되며, BPEL 프로세스에 대한 상세한 정보(BPEL 소스 파일명, BPEL 프로세스 명(ID), 파트너
링크 웹 서비스의 WSDL 위치정보, 기타 구성 정보 등)를 기술하고 있습니다. Process descriptor의
디폴트 파일 명은 bpel.xml이며, 필요한 경우 변경할 수 있습니다.
<BPELSuitcase>
<BPELProcess src="Travel.bpel" id="TravelProcessCh4">
<partnerLinkBindings>
<partnerLinkBinding name="client">
<property name="wsdlLocation">
Travel.wsdl
</property>
</partnerLinkBinding>
<partnerLinkBinding name="employeeTravelStatus">
<property name="wsdlLocation">
http://localhost:9700/orabpel/default/Employee/Employee?wsdl
</property>
</partnerLinkBinding>
<partnerLinkBinding name="AmericanAirlines">
<property name="wsdlLocation">
http://localhost:9700/orabpel/default/AmericanAirline/AmericanAirline?wsdl
</property>
</partnerLinkBinding>
<partnerLinkBinding name="DeltaAirlines">
<property name="wsdlLocation">
http://localhost:9700/orabpel/default/DeltaAirline/DeltaAirline?wsdl
</property>
</partnerLinkBinding>
</partnerLinkBindings>
</BPELProcess>
</BPELSuitcase>
이제 BPEL Process Manager를 시작할 준비가 완료되었습니다. BPEL Process
Manager를 시작하려면 Windows 시작 메뉴를 이용하거나, (Oracle BPEL Process Manager가
c:\orabpel에 설치된 경우) c:\orabpel\bin 디렉토리의 startOraBPEL 스크립트를 실행하면
됩니다.
Oracle BPEL Process manager에는 obant라 불리는 Ant 유틸리티가 포함되어 있습니다. obant
유틸리티를 사용하여 복잡한 컴파일 작업 및 deploy 작업을 위한 환경을 설정할 수 있습니다. obant는 표준
Ant를 위한 래퍼(wrapper)로써, 작업에 필요한 환경을 설정하고 표준 Ant Java 태스크를 실행하는 역할을
담당합니다. obant 유틸리티를 이용하려면 먼저 (일반적으로 build.xml이라는 이름을 갖는) 프로젝트 파일을
생성해야 합니다. 예제의 프로젝트 파일 내용이 아래와 같습니다.
<?xml version="1.0"?>
<project name="TravelProcessCh4" default="main" basedir=".">
<property name="deploy" value="default"/>
<property name="rev" value="1.0"/>
<target name="main">
<bpelc home="${home}" rev="${rev}" deploy="${deploy}"/>
</target>
</project>
BPEL 프로세스의 컴파일 및 deploy 작업을 수행하려면, 커맨드 라인에서 obant를
실행하면 됩니다.
이렇게 하여 BPEL 프로세스를 Oracle BPEL Server에 성공적으로 deploy하였습니다. 이제 실행해
봅시다. Oracle BPEL Process Manager의 BPEL Console을 통해 BPEL Server 도메인의
BPEL 프로세스를 실행, 모니터링, 관리, 디버깅할 수 있습니다. BPEL Console은 “http://localhost:9700/BPELConsole/”으로
접근할 수 있습니다. 콘솔에서 프로세스 명을 클릭하고 아래 그림과 같은 입력 폼을 작성한 후 “Post XML Message”
버튼을 클릭합니다:
 |
| Figure 7: BPEL Console
|
이제 프로세스 인스턴스가 비동기적으로 처리되고 있다는 메시지가 화면으로 출력됩니다. 그림 8과 같이 실행 상태의
visual flow를 선택하고 감사 또는 디버깅 작업을 수행할 수 있습니다. 비주얼 플로우를 통해 BPEL 프로세스
인스턴스의 실행 상태를 확인할 수 있습니다. 프로세스의 실행 과정과 상태(running, completed, canceled,
stale)를 모니터링 하는 것이 가능합니다.
 |
| Figure 8: Graphical
view of the instance's flow |
Oracle BPEL Process Manager는 BPEL 프로세스의
감사, 관리, 디버그, deploy 등을 위한 다양한 옵션을 제공합니다. 자세한 정보는 제품관련문서를
참고하시기 바랍니다.
결론
지금까지 BPEL을 통해 웹 서비스의 composition 작업을 수행하는
기본적인 방법을 설명하였습니다. 다음 아티클에서는, fault handling, scope, compensation,
concurrent activity, event handling 등의 고급 개념을 설명하도록 하겠습니다.
Matjaz B. Juric는
컴퓨터/정보 과학 분야의 박사 학위를 소지하고 있으며 Business
Process Execution Language for Web Services (Packt Publishing)의
저자이기도 합니다. Matjaz는 Professional J2EE EAI, Professional EJB, J2EE Design
Patterns Applied, and VB.NET Serialization Handbook (Wrox Press) 등의
저서를 공동 집필하였으며 Java Developer's Journal, Java Report, Java World 등의
전문지에 기사를 기고하고 있습니다. |