기술자료
DBMS, DB 구축 절차, 빅데이터 기술 칼럼, 사례연구 및 세미나 자료를 소개합니다.
SOA 복합 비즈니스 서비스 구현하기, Part 2: 본 시리즈에서는 복합 애플리케이션(composite application) 개발에 관련한 문제들을 다룹니다. 복합 애플리케이션은 기존 SOA 서비스들을 통합하고 다양한 방식으로 구성될 수 있는 새로운 서비스들을 구현합니다. 원래, 우리는 WebSphere Application Developer IE v5.1과, 런타임으로서 WebSphere Business Integration SF를 사용하여 데모용 복합 애플리케이션을 개발했습니다. (본 시리즈 Part 1 참조) WebSphere Process Server v6과 이와 관련한 개발 툴인 WebSphere Integration Developer v6의 릴리스와 함께, Service Component Architecture (SCA)에 기반한 새로운 프로그래밍 모델이 탄생했습니다. 이에 따라, 레거시 프로그래밍 모델을 새로운 모델로 마이그레이션 해야 할 필요성이 대두되었습니다. 이 글에서, 마이그레이션 기간 동안 배웠던 중요한 교훈들을 여러분과 함께 나눕니다. 머리말 바인딩과 관련한 마이그레이션 문제 자바 바인딩과 관련한 문제 Enterprise JavaBean (EJB) 바인딩과 관련한 문제 솔루션 WSDL 인터페이스와 관련한 마이그레이션 문제 soapenc:Array를 사용하지 말 것 솔루션 1 솔루션 2 중복 네임스페이스를 사용하지 말 것 솔루션 XSD와 관련한 마이그레이션 문제 xsd:anyType을 사용하지 말 것 솔루션 BPEL과 관련한 마이그레이션 문제 엔드포인트를 동적으로 설정하기 (첫 번째 문제) 엔드포인트를 동적으로 설정하기 (두 번째 문제) 솔루션 결론 감사의 말 필자소개SOA 복합 비즈니스 서비스 구현하기, Part 2: WebSphere Application Developer-IE v5.1에서 WebSphere Integration Developer v6.0.1로 비즈니스 통합 프로젝트 마이
WebSphere Application Developer-IE v5.1에서
WebSphere Integration Developer v6.0.1로 비즈니스 통합 프로젝트 마이그레이션 하기
Listing 1. WSDL과 자바 바인딩
<service name="LoanTrackingServiceProxyPortTypeService">
이러한 종류의 WSDL이 SCA 모듈로 직접 반입된다면, WebSphere Integration Developer에 의해 기록된 예외나 에러가 없다 하더라도, 반입은 성공적으로 바인딩 할 수 없다. (그림 1) 사실, WebSphere Integration Developer V6는 SOAP 바인딩을 통해 웹 서비스 반입만 지원한다. 따라서, 이러한 반입의 엔드포인트는 비어있게 되고, 모듈이 WPS에 전개되고 호출을 시도한 후에 런타임 예외가 생기게 된다.그림 1. 자바 바인딩을 통한 WSDL 반입
<port binding="tns:LoanTrackingServiceProxyPortTypeJavaBinding"
name="LoanTrackingServiceProxyPortTypeJavaPort">
<java:address className="loantrackingservice.LoanTrackingServiceProxy"/>
</port>
</service>
<service name="LoanTrackingService">
이것은 앞서 언급했던 것과 같은 이유로 실행하는 동안 예외가 발생될 것이다. (그림 2)그림 2. EJB 바인딩을 통한 WSDL 반입
<port binding="binding1:LoanTrackingServiceEJBBinding"
name="LoanTrackingServiceEJBPort">
<ejb:address className="loantrackingservice.LoanTrackingServiceHome"
jndiName="ejb/loantrackingservice/LoanTrackingServiceHome"/>
</port>
</service>
<complexType name="ArrayOfLoanRequestBean">
<complexContent>
<restriction base="soapenc:Array">
<all/>
<attribute ref="soapenc:arrayType" wsdl:arrayType="xsd1:LoanRequestBean[]"/>
</restriction>
</complexContent>
</complexType>
Listing 4는 데이터 객체의 루트 유형이 soapenc:Array 인 상황 예제이다. sampleElements DataObject가 두 번째 스키마를 사용하여 어떻게 생성되는지에 주목하라. DataObject의 유형이 첫 번째로 획득되고, sampleStructElement 의 프로퍼티가 획득된다. (Listing 5) 이것은 플레이스홀더 프로퍼티이고, DataObject를 시퀀스에 추가하기 위해 유효 프로퍼티를 얻기 위해서만 사용된다.Listing 4. WSDL 코드 샘플
<s:schema elementFormDefault="qualified" targetNamespace="http://soapinterop.org/xsd">
Listing 5. 웹 서비스용 클라이언트 코드 샘플
<s:import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
<s:import namespace="http://schemas.xmlsoap.org/wsdl/" />
<s:complexType name="SOAPStruct">
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" form="unqualified" name="varInt"
type="s:int" /> <s:element minOccurs="1" maxOccurs="1" form="unqualified"
name="varString" type="s:string" />
<s:element minOccurs="1" maxOccurs="1" form="unqualified"
name="varFloat" type="s:float" />
</s:sequence>
</s:complexType>
<s:complexType name="ArrayOfSOAPStruct">
<s:complexContent mixed="false">
<s:restriction base="soapenc:Array">
<s:attribute wsdl:arrayType="s0:SOAPStruct[]" ref="soapenc:arrayType" />
</s:restriction>
</s:complexContent>
</s:complexType>
</s:schema>
<wsdl:message name="echoStructArraySoapIn">
<wsdl:part name="inputStructArray" type="s0:ArrayOfSOAPStruct" />
</wsdl:message>
<wsdl:message name="echoStructArraySoapOut">
<wsdl:part name="return" type="s0:ArrayOfSOAPStruct" />
</wsdl:message>
<wsdl:operation name="echoStructArray">
<wsdl:input message="tns:echoStructArraySoapIn" />
<wsdl:output message="tns:echoStructArraySoapOut" />
</wsdl:operation>SampleElements.xsd
<schema targetNamespace="http://sample/elements" xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://sample/elements">
<element name="sampleStringElement" type="string"/>
<element name="sampleStructElement" type="any"/>
</schema>
// Create the input DataObject and get the SDO sequence for the any element
DataFactory dataFactory=DataFactory.INSTANCE;
DataObject arrayOfStruct = dataFactory.create(
"http://soapinterop.org/xsd","ArrayOfSOAPStruct");
Sequence sequence=arrayOfStruct.getSequence("any");
// Get the SDO property for sample element we want to use here to populate the sequence
// We have defined this element in an XSD file, see SampleElements.xsd
DataObject sampleElements=dataFactory.create("http://sample/elements", "DocumentRoot");
Property property = sampleElements.getType().getProperty("sampleStructElement");
//Add the elements to the sequence
DataObject item=dataFactory.create("http://soapinterop.org/xsd", "SOAPStruct");
item.setInt("varInt", 1);
item.setString("varString", "Hello");
item.setFloat("varFloat", 1.0f);
sequence.add(property, item);
item=dataFactory.create("http://soapinterop.org/xsd", "SOAPStruct");
item.setInt("varInt", 2);
item.setString("varString", "World");
item.setFloat("varFloat", 2.0f);
sequence.add(property, item);
//Invoke the echoStructArray operation
System.out.println("[client] invoking echoStructArray operation");
DataObject echoArrayOfStruct =
(DataObject)interopTest.invoke("echoStructArray", arrayOfStruct);
// Display the results
if (echoArrayOfStruct!=null)
{
sequence=echoArrayOfStruct.getSequence("any");
for (int i=0, n=sequence.size(); i<n; i++)
{
item=(DataObject)sequence.getValue(i);
// Create the input DataObject and get the SDO sequence for the any element
DataFactory dataFactory=DataFactory.INSTANCE;
DataObject arrayOfStruct =
dataFactory.create("http://soapinterop.org/xsd","ArrayOfSOAPStruct");
Sequence sequence=arrayOfStruct.getSequence("any");
// Get the SDO property for sample element we want to use here to populate the sequence
// We have defined this element in an XSD file, see SampleElements.xsd
DataObject sampleElements=dataFactory.create("http://sample/elements",
"DocumentRoot");
Property property = sampleElements.getType().getProperty("sampleStructElement");
//Add the elements to the sequence
DataObject item=dataFactory.create("http://soapinterop.org/xsd", "SOAPStruct");
item.setInt("varInt", 1);
item.setString("varString", "Hello");
item.setFloat("varFloat", 1.0f);
System.out.println("[client] item varInt = "+ item.getInt("varInt")+"
varString="+item.getString("varString")+" varFloat="+item.getFloat("varFloat"));
}
<wsdl:definitions xmlns:tns="http://loanrequest/LoanRequest" ......
Listing 7. LoanRequest2.WSDL
targetNamespace="http://loanrequest/LoanRequest">
<message name="processLoanRequest">
<part name="loanAmount" type="xsd:decimal"></part>
<part name="customerId" type="xsd:string"></part>
<part name="bankId" type="xsd:string"></part>
<part name="ssn" type="xsd:string"></part>
<part name="processConfig" type="tns:ProcessConfig"></part>
<part name="productId" type="tns:ProductId"></part>
</message>
<wsdl:definitions xmlns:tns="http://loanrequest/LoanRequest" ......
targetNamespace="http://loanrequest/LoanRequest">
<message name="processLoanRequest">
<part name="loanAmount" type="xsd:decimal"/>
<part name="customerId" type="xsd:string"/>
<part name="bankId" type="xsd:string"/>
<part name="ssn" type="xsd:string"/>
<part name="configParams" type="tns:ConfigParams"/>
</message>
EJB에서 생성된 WSDL과 XSD의 경우, 대상 네임스페이스가 고유한 것인지를 확인하여(자바 클래스 이름과 패키지 이름은 대상 네임스페이스를 만드는데 사용된다.) WebSphere Process Server V6으로 마이그레이션 할 때 충돌이 생기지 않도록 한다.
예를 들어, 자바에서 getVariableReturn 을 설정하기 위해 Boolean 값을 사용하려고 하면 WebSphere Process Server 런타임에서 예외가 던져진다. (그림 4)그림 4. anyType에서 생신 예외
//There will be a class cast error caused by the value item which type is anyType ; setDecisionVar.set("getVariableReturn",(Object)(new Boolean(true));
String ep = getApproveCheckRequest().getApprovalExtensionEP();
Listing 9. WebSphere Integration Developer의 동적인 엔드포인트 설정 코드
com.ibm.websphere.srm.bpel.wsaddressing.AttributedURI address = new AttributedURI();
com.ibm.ws.webservices.engine.types.URI addressValue = new URI(ep);
com.ibm.websphere.srm.bpel.wsaddressing.EndpointReferenceType
e = new EndpointReferenceType();address.setValue(addressValue);e.setAddress(address);
this.setPartnerLinkLoanApprovalExtension(e);
//Get the new address of approvalExtension parnter
레퍼런스 파트너용 엔드포인트를 설정하는 코드가 업데이트 되었지만, 파트너가 하나의 컴포넌트로 연결되었다면(런타임 동안 동적으로 리셋되기 전에 바인딩이 여기에 할당되었다면), 엔드포인트 변경은 효과가 없다. 런타임에서, 호출은 기본 엔드포인트로 가게 될 것이다.
String ep = approveCheckRequest.getString("approvalExtensionEP");
System.out.println("Setting approval extension endpoint to: " + ep);if (ep != null && ep.length() > 0) {
ServiceManager sm = ServiceManager.INSTANCE;
Service s = (Service)sm.locateService("LoanApprovalExtension");
EndpointReference endPoint = s.getEndpointReference();//Update the endpoint address for the partner "LoanApprovalExtension"
endPoint.setAddress(ep);
}