SOA 베스트 프랙티스: BPEL Cookbook

다이내믹 BPEL 프로세스의 구현
Sean Carey

런타임에 엔드포인트 레퍼런스(endpoint reference)를 조작하여 다이내믹 바인딩 환경을 구현하는 방법을 설명합니다.

전체 BPEL Cookbook 목록 보기
아티클 관련 다운로드:
Oracle BPEL Process Managera 및 Designer

웹 서비스와 SOA(service-oriented architecture)는 서로 다른 비즈니스 프로세스 및 애플리케이션 간의 상호연동을 통해 비즈니스 프로세스를 수비게 확장할 수 있게 해 줍니다. BPEL 프로세스는 이러한 상호연동 과정을 파트너 링크(partner link)를 통해 정의합니다. 파트너 링크는 인터페이스(메시지 및 수행 작업), 전송 프로토콜, 그리고 사용 가능한 서비스의 위치 등에 대한 정의를 포함하고 있습니다.

기초적인 프로세스 설계 과정에서는 파트너 링크를 정적(static)으로 정의하는 것이 일반적입니다. 각 파트너 링크는 개발자가 디자인 타임에 지정한 단일 외부 프로세스를 참조합니다. 하지만 대규모 시스템에서는 비즈니스 프로세스가 보다 복잡한 구성을 갖습니다. 다수의 외부 서비스와 다수의 파트너 링크가 서로 연동하기도 하고, 파트너 링크들 중 일부는 디자인 타임에 정의되지 않을 수도 있습니다. 이와 같은 경우 파트너 링크의 선택에 관련한 로직은 비즈니스 프로세스 내부에 구현되어야 하며, 이로 인해 프로세스가 불필요하게 복잡해질 수 있습니다. 또 파트너 링크가 계속적으로 추가되면서 프로세스의 규모가 감당할 수 없는 수준으로 커질 수 있으며, 파트너 링크에 대해 변경 작업을 수행할 때마다 전체 비즈니스 프로세스를 수정해야 하는 문제가 생깁니다.

다행스러운 것은, BPEL 언어가 파트너 링크의 다이내믹 바인딩(dynamic binding)을 지원한다는 사실입니다. 다이내믹 바인딩은 개발자가 설정 파일을 통해, 또는 런타임 입력을 통해 새로운 서비스를 추가할 수 있게 합니다. 이러한 방법으로 전체 부모-자식 관계(parent-child relationship)을 디자인 단계에 예측하고 관리해야 할 필요성을 제거할 수 있습니다.

BPEL Cookbook 시리즈의 이번 연재에서는, 시스템이 파트너 링크를 런타임에 다이내믹하게 관리하도록 함으로써, 부모 프로세스와 서브 프로세스 간의 관계에 발생하는 변경 사항으로부터 BPEL 프로세스를 효과적으로 격리하는 방안에 대해 설명하기로 합니다. 또 다수의 BPEL 프로세스를 순차적 또는 병렬적인 방식으로 다이내믹하게 호출하는 방법에 대해서도 소개하겠습니다.

다이내믹 바인딩 개요

고전적인 프로그래밍 세계의 오브젝트 지향형 분석 및 설계 방법과 마찬가지로, 파트너 링크의 다이내믹 바인딩은 코드의 모듈화(modularization)과 프로세스 간의 런타임 바인딩(run-time binding)을 가능하게 합니다. 이와 같은 방식의 장점을 요약하면 아래와 같습니다:
  • 기능적인 컴포넌트를 개별 작업 단위로 분할함으로써, 팀 지향적인(team-oriented) 개발 환경을 지원합니다.
  • 부모 프로세스(parent process)를 수정하고 다시 deploy하는 과정을 거치지 않고도 추가적인 서브프로세스 컴포넌트를 생성하고 deploy할 수 있게 합니다.
  • 개별적인 중복 프로세스(overlapping process)들을 사용, 관리, 개선할 필요성이 줄어듭니다.
  • 부모 프로세스는 서브프로세스의 변경 및 개선사항을 자동으로 액세스할 수 있습니다.
간단하게 말해, 다이내믹 프로세스는 디자인 타임에 정의되지 않은 상황에 시스템이 적응할 수 있게 합니다. 예를 들어, 데이터 컨텐트에 따라 프로세스 플로우가 결정될 수 있습니다. 런타임에 관계형 데이터베이스와 같은 외부 데이터 소스를 호출하여 프로세스 플로우를 정의하는 것도 가능합니다.

다이내믹 프로세싱은 하이 레벨 프로세스 플로우의 개발 책임과 관리 책임이 분명하게 구분된 조직에서 매우 유용하게 활용됩니다. 개발 팀은 BPEL 프로세스의 세부 사항을 이해하고 프로세스 컴포넌트를 생성하는 역할을 담당하며, 비즈니스 애널리스트 또는 기술지원 팀과 같은 도메인 전문가는 (파트너 링크, 네임스페이스, WSDL, XPATH 등의 기술적인 세부 사항을 이해할 필요 없이) 이러한 컴포넌트를 개별 워크플로우로 조합할 수 있습니다.

다이내믹 BPEL 프로세스의 구현

앞에서 설명한 것처럼, 파트너 링크는 비즈니스 프로세스 또는 다른 서비스에 대한 인터페이스를 기술하는 용도로 사용됩니다. BPEL 프로세스는 파트너 링크에 저장된 정보를 이용하여 이러한 외부 서비스들을 호출하게 됩니다.

파트너 링크는 WSDL의 portTypes를 이용하여 서비스 인터페이스를 구성하는 작업 및 메시지 타입을 정의합니다. 그림 1에서 확인할 수 있듯, portTypes는 또 서비스 커뮤니케이션에 사용되는 전송 프로토콜(“binding”)과 서비스의 위치(“service”)를 간접적으로 정의하고 있습니다.

그림 1 portTypes의 실행 과정

정적인 BPEL 프로세스에서는, 파트너 링크 정보가 디자인 타임에 정의됩니다. 하지만, 모든 파트너 링크 정보를 미리 알 수 없는 경우가 있을 수 있습니다. 이러한 경우에는 개발자가 데이터 및 기타 다이내믹 요구사항을 런타임에 반영해 주어야만 합니다.

대출 처리 과정을 예로 들어 설명해 보겠습니다. 사용자는 지역, 대출 금액, 신용 히스토리 등의 입력 데이터를 기반으로 대출 제공자(loan provider)를 선택하고자 합니다. 이러한 데이터는 런타임에 이전에 확인이 불가능합니다. 또 다수의 대출 제공자가 존재하는 경우라면 전체 서비스를 정적으로 관리하도록 프로세스를 모델링하기는 더더욱 어려울 것입니다.

대출 제공자를 다이내믹하게 선택하도록 함으로써 이러한 문제를 해결할 수 있습니다. WS-Addressing 표준은 엔드포인트 레퍼런스 (endpoint reference)라 불리는 메커니즘을 제공합니다. 엔드포인트 레퍼런스는 WSDL 내에서 사용 가능한 서비스 중 하나를 선택하거나, 런타임에 새로운 서비스를 정의하는 것을 가능하게 합니다. 비즈니스 프로세스가 portType에 정의된 인터페이스 정보에 정적으로 의존하는 반면, 엔드포인트 레퍼런스는 (서비스에 대한 바인딩의 매핑을 통해) 서비스 위치를 다이내믹하게 재정의할 수 있게 합니다. 쉽게 말해, 엔드포인트 레퍼런스는 WSDL의 정적인 서비스 요소를 대체하는 다이내믹 참조로 활용됩니다. 프로세스 설계담당자는 서비스가 인터페이스 표준을 준수하는 한, 어떤 서비스를 호출해야 하는지 미리 결정할 필요가 없습니다. Oracle BPEL Process Manager에서 제공되는 DynamicPartnerLink 샘플을 통해 이 개념을 보다 쉽게 이해할 수 있을 것입니다. 이 샘플을 단계별로 살펴보면서, 다이내믹 프로세스를 구현하는 방법을 배워보기로 합시다. (참고: 이 샘플을 시작하기 전에 먼저 표준 LoanFlow 튜토리얼의 내용을 이해하실 것을 권유 드립니다.)

DynamicPartnerLink 샘플의 이해

DynamicPartnerLink 샘플은 파트너 링크 및 엔드포인트 레퍼런스의 개념을 이해하는데 매우 유용한 리소스입니다. DynamicPartnerLink 샘플의 3개 loan service provider (United, Star, American) 중 하나를 선택하고, 프로세스의 입력에 따라 적절한 서비스를 다이내믹하게 호출하게 됩니다.

여기에서는 Oracle BPEL Process Manager 10.1.2 GA Release에서 제공하는 샘플을 사용하기로 합니다. 샘플 파일은 [BPEL_HOME]\samples\references\DynamicPartnerLink 디렉토리에 위치하고 있습니다. 아래 예제 코드는 버전 10.1.2의 Patch 1 환경에서 개발 및 테스트되었습니다.

참고: Dynamic Partner Link 샘플을 처음 로드하여 deploy하는 경우, Oracle JDeveloper Visual Designer에서 코드를 변경하지 않고 원본 그대로의 상태로 deploy하도록 합니다. 코드를 변경하고 다시 저장하는 경우, JDeveloper는 BPEL 코드를 표준 XML 레이아웃으로 재포맷하고 newline 문자를 삽입합니다. JDeveloper는 <EndpointReference> 데이터 내부의 <Address> 태그와 <ServiceName> 태그를 변경하고, </Address> 태그와 </ServiceName> 태그의 앞에 newline 문자를 추가합니다. 이렇게 추가된 newline 문자 때문에 바인딩이 해제되는 결과가 초래됩니다. 이러한 문제를 해결하려면 service와 address의 닫기 태그에 추가된 newline 문자를 제거해야 합니다. 뒷부분에서 JDeveloper의 포맷 재적용 결과에 구애 받지 않고 엔드포인트 레퍼런스를 적용하는 또 다른 방법을 소개하도록 하겠습니다.

샘플을 실행하면, 콘솔을 통해 Loan Flow 데모를 위한 애플리케이션 데이터(SSN, 이메일 등)와 “provider” 필드의 입력을 요구 받게 됩니다. provider 문자열로는 ”united”, “american” 또는 “star” 중 하나를 선택하여 입력합니다. 세 가지 문자열을 모두 적용하여 어떻게 동작하는지 확인하도록 합니다. 프로세스는 해당되는 loan provider를 다이내믹하게 호출합니다. provider 필드에 다른 문자열을 입력하거나 아무런 값도 입력하지 않고 테스트해 봅시다.
다이내믹 프로세스의 동작 원리를 이해하기 위해서는 먼저 DynamicPartnerLink.bpel 파일을 분석해 볼 필요가 있습니다. 이 파일에서 가장 먼저 확인해야 할 부분은 loan service 파트너 링크입니다:
<partnerLink name="LoanService" partnerLinkType="services:LoanService" 
  myRole="LoanServiceRequester" partnerRole="LoanServiceProvider"/>
개별적인 loan service (UnitedLoan 등)을 정의하는 대신, 제너릭(generic)한 loan service name과 type이 사용되었습니다 (services:LoanService). LoanService 파트너 링크는 LoanService.wsdl 파일에 정의되어 있습니다. 이 파일을 bpel.xml 파일의 <partnerLinkBindings> 섹션에 아래와 같이 추가함으로써 임포트(import)할 수 있습니다:
<partnerLinkBinding name="LoanService">
  <property name="wsdlLocation">LoanService.wsdl</property>
</partnerLinkBinding>
아래와 같이 LoanService.wsdl 파일 내에서 각 loan provider가 <service>로 등록되어 있음을 확인할 수 있습니다:
<service name="StarLoan">
 <port name="LoanServicePort" binding="tns:LoanServiceBinding">
  <soap:address location="http://localhost:9700/orabpel/default/StarLoan"/>
 </port>
</service>
  
<service name="UnitedLoan">
 <port name="LoanServicePort" binding="tns:LoanServiceBinding">
  <soap:address location="http://localhost:9700/orabpel/default/UnitedLoan"/>
 </port>
</service>  
  
<service name="AmericanLoan">
 <port name="LoanServicePort" binding="tns:LoanServiceBinding">
  <soap:address location="http://localhost:9700/orabpel/default/AmericanLoan"/>
 </port>
</service>  
여기서 실제로 “LoanService”라는 이름을 갖는 서비스가 존재하지 않는다는 사실을 이해하는 것이 중요합니다. LoanService는 실재하는 loan provider 서비스(UnitedLoan, AmericanLoan, StarLoan)를 선택하기 위한 템플릿의 형태로 존재합니다. 이와 같은 방법은, 모든 서비스가 템플릿 WSDL에 정의된 동일한 인터페이스(동일한 데이터 타입, 메시지, 롤, 포트, 파트너 링크 타입 등)를 지원하는 경우에만 효과가 있습니다. 템플릿 인터페이스를 정의할 때에는 특히 주의해야 합니다. 템플릿 인터페이스의 변경 내용이 여러 프로세스에 영향을 미칠 수 있기 때문입니다.

LoanService.wsdl 파일은 부모 프로세스(parent process)가 다이내믹 호출에 사용하는 모든 서비스 옵션을 정의하고 있습니다. 이와 같은 모델에서는 새로운 서비스가 추가될 때마다 WSDL 파일을 다시 deploy해야 합니다. 하지만 새로운 서비스가 추가될 때마다 부모 프로세스에 새로운 파트너 링크와 라우팅 로직을 추가해야 하는 환경에 비해서는 진일보한 것으로 볼 수 있습니다. (뒷부분에서 WSDL 파일로부터 서비스 엔드포인트를 해제하는 방법에 대해서도 설명합니다.)

다시 DynamicPartnerlink.bpel 파일로 돌아가서 partnerReference 변수를 살펴봅시다:
<variable name="partnerReference" element="wsa:EndpointReference"/>
이 변수는 EndpointReference 타입으로 정의되며, BPEL 파일의 최상위에 정의된 wsa: 네임스페이스를 갖습니다. 네임스페이스는 다음과 같이 정의됩니다.
xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing"
WS-Addressing 표준은 EndpointReference 타입을 위한 스키마를 제공합니다. 이 타입의 변수를 파트너 링크에 <assign>하는 방식으로 address 및 service 정보를 수정할 수 있습니다. 따라서 파트너 링크를 런타임에 변경하는 것이 가능해집니다.

DynamicPartnerLink 프로세스는 기본적으로 “switch” 구문으로 구성되어 있습니다. 이 프로세스는 호출자에 의해 전달된 “provider” 문자열을 점검한 뒤, 요청 서비스에 관련된 정보를 저장하기 위한 partnerReference 변수에 EndpointReference xml 데이터 구조를 할당합니다. “switch” 구문이 실행되고 나면, partnerReference 변수가 LoanService 파트너 링크에 할당되고 파트너 링크가 호출됩니다.

"united" 가 입력 문자열로 사용된 경우의 작업 실행 과정이 아래와 같습니다:

<assign>
 <copy>
  <from>
   <EndpointReference xmlns="http://schemas.xmlsoap.org/ws/2003/03/addressing">
   <Address>http://localhost:9700/orabpel/default/UnitedLoan</Address>
   <ServiceName 
     xmlns:ns1="http://services.otn.com">ns1:UnitedLoan</ServiceName>
   </EndpointReference>
  </from>
  <to variable="partnerReference"/>
 </copy>
</assign>
<from> 태그와 </from> 태그 사이의 모든 구문은 partnerReference 변수에 할당할 XML 문자열입니다. 이 데이터는 LoanService partnerReference 변수를 파트너 링크에 할당하는 과정에서 파트너 링크에 정의된 address 및 service 정보보다 우선하여 적용됩니다.

지금까지 LoanService 파트너 링크와 LoanService.wsdl 파일을 이용하여 서비스를 런타임에 선택하는 방법에 대해서 알아보았습니다. 이제 다이내믹 프로세스의 구현 방법에 대해 살펴보기로 합시다.

다이내믹 BPEL 프로세스의 생성

다이내믹 BPEL 프로세스를 생성하는 방법을 처음부터 설명해 보기로 하겠습니다.

1. 새로운 BPEL 프로젝트의 생성.
JDeveloper에서 asynchronous BPEL Process Project를 생성하고 이름을 “MyDL”로 설정합니다.

2. DynamicPartnerLink 샘플에서 LoanService.wsdl 파일을 임포트
DynamicPartnerLink 샘플로부터 LoanService.wsdl 파일을 MyDL 프로젝트의 작업 디렉토리로 복사합니다. (디폴트 작업 디렉토리는 “[BPEL_HOME]\integration\jdev\jdev\mywork\Workspace1\MyDL”입니다.) (이와 같은 방법을 사용하여 다이내믹 WSDL 및 서브프로세스 서비스를 생성하는데 드는 시간과 수고를 덜 수 있습니다.) 그런 다음, Application Navigator에서 MyDL 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 Add to Project...를 선택합니다. 디렉토리에서 LoanService.wsdl 파일을 선택하고 OK를 클릭합니다.

아직 LoanService.wsdl 파일이 bpel.xml 파일에 추가되지 않은 상태입니다. 나중에 EndpointReference 변수를 구현하기 전까지는 이 작업이 필요하지 않습니다.

3. loan service 파트너 링크 템플릿의 생성.
마우스 오른쪽 버튼을 클릭한 다음 Create Partner Link....를 선택합니다. 그림 2와 같이 대화상자에 입력합니다. WSDL 파일의 위치를 지정하기 위해 (플래시라이트 버튼 왼쪽에 있는) Browse WSDL Files from Local File System 버튼을 클릭하고, MyDL 프로젝트 디렉토리에서 LoanService.wsdl 파일을 선택합니다. 입력이 완료되면 OK를 클릭하여 파트너 링크를 생성합니다.

그림 2 "Create Partner Link" 대화상자

4. DynamicLoanService 파트너 링크를 호출하기 위한 invoke/receive 액션을 생성.
컴포넌트 팔레트에서 receive 액션과 invoke 액션을 드래그하여 프로세스에 (receiveInput와 callbackClient 액션의 사이에) 드롭합니다. invoke에서 화살표를 끌어 DynamicLoanService 파트너 링크에 연결한 다음 input 변수를 생성합니다. receive 액션에 대해 동일한 작업을 반복합니다. 변수 이름은 각각 loanInput와 loanOutput으로 설정합니다.

5. loanInput 변수에 입력할 데이터 설정
사용자로부터의 loan input 데이터를 얻기 위해서는 일반적으로 MyDL.wsdl 파일을 수정하는 방법이 사용됩니다. 여기에서는 작업 편의상 loanInput 변수에 입력할 데이터를 하드코딩하는 방법을 사용하기로 하겠습니다. receiveInput 액션에 assign을 생성하고, 아래와 같이 loanInput의 SSN 엘리먼트에 "123456789"의 값(숫자가 아닌 문자열이므로 인용 기호를 반드시 붙여야 합니다)을 입력하는 copy rule을 생성합니다:

<assign name="PopulateSSN">
 <copy>
  <from expression="'123456789'"/>
  <to variable="loanInput" part="payload" query="/ns2:loanApplication/ns2:SSN"/>
 </copy>
</assign>
6. partnerReference 변수의 생성
Structure 창에서 Variables 트리와 Process 트리를 순서대로 확장하고 Variables 아이템을 선택합니다 (그림 3 참고).

그림 3 "Variables" 트리의 확장

Variables를 마우스 오른쪽 버튼으로 클릭하고 Create Variable....를 선택합니다. 변수의 이름을 "partnerReference"로, 타입을 "Element." 로 설정합니다. Element 박스 옆에 위치한 flashlight 아이콘을 클릭하여 Type Chooser를 엽니다. Project WSDL Files → LoanService.wsdl → Inline Schemas → schema에서 "EndpointReference" 타입을 선택합니다 (그림 4 참고).

그림 4 "EndpointReference"의 선택

7. partnerReference 변수의 설정.
DynamicLoanService invoke의 앞에 다시 assign을 생성하고, 이 assign을 이용하여 partnerReference 변수를 설정합니다. 여기에서는 UnitedLoan 서비스로 하드코딩 하지만, 다음 섹션에서 다이내믹 프로세스로 변경하게 될 것입니다.

여기에서는 EndpointReference xml 데이터를 재포맷(reformat)함으로써, DynamicPartnerLink 샘플에서 발생할 수 있는 문제를 예방할 수 있습니다. 재포맷된 빈 EndpointReference에 partnerReference 변수의 데이터를 입력하는 copy rule을 생성합니다:
<EndpointReference xmlns="http://schemas.xmlsoap.org/ws/2003/03/addressing" 
  xmlns:ns1="http://services.otn.com">
     <Address/>
     <ServiceName/>
</EndpointReference>
위 정보를 입력하기 전에, copy rule의 “from” 블록에서 “XML Fragment” 타입을 선택해야 합니다. partnerReference에 대한 네임스페이스 정보를 설정하기 위해서는 이 카피 작업을 반드시 수행해야 합니다. partnerReference 변수가 DynamicLoanService 파트너 링크로 복사되고 나면 별도의 XML 다큐먼트로 취급되기 때문입니다. 이와 같이 하지 않는 경우, partnerReference 변수를 파트너 링크에 할당하는 과정에서 null pointer 에러가 발생하게 됩니다.

이제 표준 copy rule을 이용하여 partnerReference 변수의 ServiceName 및 Address 엘리먼트에 데이터를 입력할 수 있습니다. 이때 빈 엔드포인트 레퍼런스에 정의된 것과 동일한 서비스 네임스페이스(ns1)를 명시해야 합니다. <assign> 구문의 작성 예가 아래와 같습니다.
<assign name="SetupPartnerlink">
  <copy>
    <from>
      <EndpointReference 
        xmlns="http://schemas.xmlsoap.org/ws/2003/03/addressing" 
         xmlns:ns1="http://services.otn.com">    
        <Address/>    
        <ServiceName/>
      </EndpointReference>
    </from>
    <to variable="partnerReference"/>
  </copy>
  <copy>
    <from expression="'ns1:UnitedLoan'"/>
    <to variable="partnerReference" query="/ns3:EndpointReference/ns3:ServiceName"/>
  </copy>
  <copy>
    <from expression="'http://localhost:9700/orabpel/default/UnitedLoan'"/>
    <to variable="partnerReference" query="/ns3:EndpointReference/ns3:Address"/>
  </copy>
</assign>
또, partnerReference 변수가 사용되는 이 시점이 경과하기 전까지는 LoanService.wsdl 파일이 bpel.xml 파일에 추가되지 않음을 참고하시기 바랍니다. (그런 뒤에야 EndpointReference 스키마에 대한 액세스가 가능해집니다.)

8. partnerReference 변수를 DynamicLoanService 파트너 링크에 복사
SetupPartnerlink 액션과 DynamicLoanService의 <invoke> 사이에 새로운 <assign>을 생성합니다. 새로운 copy rule을 생성하고 그림 5와 같이 설정합니다.

그림 5 새로운 copy rule의 생성

이 과정이 완료되고 나면, 다이내믹 BPEL 프로세스가 생성됩니다. 프로세스는 하드코딩된 어드레스 정보를 포함하고 있습니다. 7번째 단계에서 생성한 두 가지 copy rule을 런타임에 수집된 정보로 대체함으로써 완전한 다이내믹 BPEL 프로세스로 변경할 수 있습니다. BPEL 프로세스 다이어그램이 그림 6과 같습니다.

그림 6 새로운 BPEL 프로세스

다이내믹 프로세스의 효율성 개선

앞의 예제에서 확인한 것처럼, LoanService.wsdl 파일은 런타임에 다이내믹하게 호출 가능한 서비스 목록을 포함하고 있습니다. 새로운 서비스가 추가될 때마다 비즈니스 프로세스를 변경할 필요가 없게 만든다면, 비즈니스 프로세스의 다이내믹한 속성은 더욱 강화될 것입니다. 이를 위해 새로운 서비스를 WSDL 내에 정의하고, 새로운 서비스가 추가될 때마다 WSDL을 다시 deploy하는 방법을 사용할 수 있습니다.

여기서 프로세스의 다이내믹한 속성을 한 단계 더 끌어올릴 수 있습니다. WSDL 기반 접근방식은 새로운 서비스의 위치를 디자인 타임에 미리 알고 있어야 한다는 요구사항을 갖습니다. 하지만 프로세스를 WSDL로부터 독립적으로 만든다면, 서비스를 추가할 때마다 WSDL을 다시 deploy할 필요가 없을 것입니다.

런타임의 주소 종속성(address dependency) 제거. 서비스 주소(service address)는 자주 변경될 가능성이 높습니다. 런타임의 다이내믹 프로세스가 주소에 종속되지 않도록 구현하는 것이 가능합니다. 서비스 주소를 제외한 서비스 네임만을 할당하고, 서비스 주소는 WSDL에서 가져오는 방법을 사용하면 됩니다. 이 방법을 실습해 보기 위해, 템플릿 copy rule의 XML 구문에서 주소와 관련된 부분(<Address/>)을 삭제합니다. 이전 설정을 뒷부분에서 다시 복원해야 하므로, 이 작업을 수행하기 전에 MyDL.bpel 파일을 백업해 두도록 합니다. 또, SetupPartnerLink <assign> 구문에서 주소에 관련된 copy rule을 삭제합니다. 변경된 SetupPartnerlink <assign>이 아래와 같습니다:

<assign name="SetupPartnerlink">
  <copy>
    <from>
      <EndpointReference xmlns="http://schemas.xmlsoap.org/ws/2003/03/addressing" 
           xmlns:ns1="http://services.otn.com">    
        <ServiceName/>
      </EndpointReference>
    </from>
    <to variable="partnerReference"/>
  </copy>
  <copy>
    <from expression="'ns1:UnitedLoan'"/>
    <to variable="partnerReference" query="/ns3:EndpointReference/ns3:ServiceName"/>
  </copy>
</assign>
이제 MyDL 프로세스를 다시 deploy하고 실행합니다. 주소 정보가 제거되었음에도 UnitedLoan 서브프로세스에 대한 호출이 성공적으로 수행됨을 확인할 수 있을 것입니다. BPEL 콘솔의 process tree 뷰에서 이 과정을 확인할 수 있습니다. 이 실험을 통해, 서비스의 변경된 주소 정보를 포함하는 새로운 WSDL을 deploy하기만 하면 다이내믹 프로세스의 실행 방법을 변경할 수 있음이 검증되었습니다. 그 대신 새로운 서비스를 추가할 때마다 WSDL을 변경하고 다시 deploy해야 한다는 문제가 남습니다.

서비스의 WSDL 종속성 제거. 관리해야 하는 서비스의 수가 많은 상황에서 서비스 주소가 매우 빈번하게 변경되는 경우, WSDL 파일을 자주 업데이트해야 하는 것이 문제가 될 수 있습니다. 프로세스가 런타임에 엔드포인트 레퍼런스의 주소를 명시하도록 함으로써 이러한 문제를 해결할 수 있습니다.

MyDL.bpel 파일을 다시 (주소 관련 copy rule을 포함하는) 원래 버전으로 복구합니다. 이번에는 주소 정보를 제거하는 대신, 템플릿의 XML과 ServiceName copy rule로부터 서비스 정보를 제거합니다. 수정된 <assign>이 아래와 같습니다:

<assign name="SetupPartnerlink">
  <copy>
    <from>
      <EndpointReference xmlns="http://schemas.xmlsoap.org/ws/2003/03/addressing" 
          xmlns:ns1="http://services.otn.com">
        <Address/>
      </EndpointReference>
    </from>
    <to variable="partnerReference"/>
  </copy>
  <copy>
    <from expression="'http://localhost:9700/orabpel/default/UnitedLoan'"/>
    <to variable="partnerReference" query="/ns3:EndpointReference/ns3:Address"/>
  </copy>
</assign>
수정된 샘플을 실행하면, 서비스 네임이 명시되지 않았음에도 UnitedLoan 서비스가 성공적으로 호출됨을 확인할 수 있을 것입니다. WSDL의 목록에 등록되지 않은 서비스라 하더라도 서비스의 주소를 런타임에 확인할 수만 있다면, 더미 서비스(dummy service)를 통해 DynamicPartnerLink를 생성하고 서비스를 호출하는 것이 가능합니다. 이때 주소를 명시하지 않으면, WSDL의 디폴트 서비스 주소가 사용됩니다. 따라서 디폴트 서비스를 (에러 로깅 및 경고 전송 기능을 제공하는) 실제 BPEL 프로세스로 지정해 두는 것도 좋은 방법입니다.

이러한 기능을 예외 처리를 위한 프레임워크의 구현을 위해 사용할 수도 있습니다. 특정 서비스에 대해 두 개 이상의 주소가 존재하는 경우(예: 서비스 이중화를 위해 로컬 서버와 원격 서버가 동시에 서비스를 제공하는 경우) 첫 번째 주소에 대한 호출이 실패했을 때 예외 처리기(exception handler)를 이용하여 엔드포인트 레퍼런스의 주소를 무시하고 서비스 호출을 재시도하도록 함으로써 두 번째 주소로 롤오버(roll-over)할 수 있습니다.


다수의 다이내믹 프로세스를 호출. 경우에 따라 다수의 서브프로세스에 하나의 데이터 셋을 순차적 또는 병렬적으로 전달해야 할 수도 있습니다. 이와 같은 작업을 위해 WHILE 루프를 이용할 수 있습니다.


간단한 예를 들어 설명해 보기로 하겠습니다. Loan Service Provider의 서비스 가능 여부는 요일에 따라 달라지며, 이 정보는 데이터베이스에 저장되어 있습니다. 월요일에 대출 요청이 발생하였고, 데이터베이스는 사용 가능한 Loan Service Provider(United와 Star)의 목록을 반환합니다. 대출 요청을 처리하기 위해서는, United와 Star의 서브프로세스가 (순차적 또는 병렬적으로) 호출되어야 합니다. 데이터베이스 쿼리는 다음과 같은 결과를 반환합니다:
<dbOutput>
 <part xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="response-
   headers">null</part> 
 <part xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   name="DynamiclinksCollection">
 <n:DynamiclinksCollection
    xmlns:n=http://xmlns.oracle.com/pcbpel/adapter/db/top/MyDynamicLink
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Dynamiclinks>
   <address>http://localhost:9700/orabpel/default/UnitedLoan</address> 
   <day>monday</day> 
   <uid>1</uid> 
  </Dynamiclinks>
  <Dynamiclinks>
   <address>http://localhost:9700/orabpel/default/StarLoan</address> 
   <day>united</day> 
   <uid>4</uid> 
 </Dynamiclinks>
</n:DynamiclinksCollection>
</part>
</dbOutput>
이 작업을 순차적으로 호출하려면 while 루프를 생성해야 합니다. while 루프는 쿼리 결과에서 주소 정보를 가져오고 각 서비스에 대해 다이내믹 invoke/receive 액션을 수행합니다.
<!-- first setup the counter variable "i" -->
<assign name="CounterReset">
  <copy>
    <from expression="1"/>
    <to variable="i"/>
  </copy>
</assign>

<!-- while loop goes until all link collection notes are done -->
<while name="LoanLoop" condition="bpws:getVariableData('i') <=
      count(bpws:getVariableData('dbOutput','DynamiclinksCollection',
        '/ns3:Dynamiclin ksCollection/Dynamiclinks'))">
    <sequence name="Sequence_1">

<!-- reset the endpoint with the usual xml fragment -->
    <assign name="ClearEndpoint">
      <copy>
        <from>
          <EndpointReference 
             xmlns="http://schemas.xmlsoap.org/ws/2003/03/addressing" 
             xmlns:ns1="http://services.otn.com">
            <Address/>
          </EndpointReference>
        </from>
        <to variable="partnerReference"/>
      </copy>
    </assign>

<!-- set the address in the endpoint variable 
	based on the current node -->
    <assign name="SetEndpoint">
      <copy>
        <from variable="dbOutput" part="DynamiclinksCollection"
		     query="/ns3:DynamiclinksCollection/Dynamiclinks
             [number(bpws:getVariableData('i'))]/address"/>
        <to variable="partnerReference"
          query="/wsa:EndpointReference/wsa:Address"/>
      </copy>
    </assign>

<!-- copy the endpoint variable into the partner link -->
    <assign name="DoPartnerlink">
      <copy>
        <from variable="partnerReference"/>
        <to partnerLink="LoanService"/>
      </copy>
    </assign>
<!-- invoke the partner link -->
    <invoke name="Invoke_2" partnerLink="LoanService" 
       portType="ns2:LoanService" operation="initiate" 
       inputVariable="loanInput"/>

<!-- be sure to increment your counter or you have an infinite loop -->
    <assign name="CounterIncrement">
      <copy>
        <from expression="bpws:getVariableData('i')+1"/>
        <to variable="i"/>
      </copy>
    </assign>
  </sequence>
</while>
위의 예에서는 비동기식 서비스(asynchronous service)를 호출하였습니다. WHILE 루프의 <invoke>에서 <receive>를 제거하고, <receive> 액션을 위한 WHILE 루프를 구현함으로써, <receive> 액션을 병렬적으로 호출하는 것도 가능합니다. 각각의 호출 프로세스에 대한 응답은 <receive>가 실행될 때까지 큐에 저장됩니다. <receive> 태스크는 접수된 데이터를 수신된 순서대로 저장합니다. 이와 같은 방법으로 “long-running” 태스크로 인해 “short-running” 태스크의 응답이 지연되는 문제를 방지할 수 있습니다.

모든 비동기식 응답이 수신되기 전에 <receive> while 루프에서 빠져나가는 것은 권장되지 않습니다.

결론

지금까지 확인한 것처럼, 엔드포인트 레퍼런스를 이용한 다이내믹 바인딩을 통해 BPEL 프로세스의 민첩성을 개선하고 비즈니스 환경의 변화에 보다 신속하게 대처하는 것이 가능합니다. 비즈니스 로직과 파트너 주소를 분리(decoupling)함으로써, 프로세스의 적응성과 호환성을 한층 개선할 수 있습니다.


Sean CareySean Carey는 EDI 호스팅 업계의 리더 업체인 SPS Commerce의 소프트웨어 설계 전문가입니다. Sean은 미션 크리티컬 전자상거래 환경 구축에 7년 가까운 경험을 갖고 있으며, 15년의 소프트웨어 설계 경험을 보유하고 있습니다.

여러분의 의견을 보내주십시오.
E-mail this page
Printer View Printer View