출처:http://www.ibm.com/developerworks/kr/library/ws-intwsdl2/#N103D7
WSDL로 웹 서비스 전개하기, Part 2: Simple Object Access Protocol (SOAP)
SOAP으로 WSDL 애플리케이션 전개하기
요약:Simple Object Access Protocol (SOAP)은 원격 객체로의 액세스를 규정한다. 원격 객체들의 예제는 간단하거나 Enterprise JavaBeans components와 COM/COM+ 객체들이다. 이러한 객체들은 다른 엔터프라이즈 내부에 존재하고 인터넷의 어딘가에 존재하고 있다. SOAP 통신은 인터넷을 통해 작동하고 다른 엔터프라이즈 사이에서 정보를 교환하는 메커니즘이다. 이 글에서, Bial은 SOAP을 자세하게 다룬다. 객체들이 SOAP을 사용하여 기능을 나타내는 방법, SOAP 객체를 호출하는 방법, SOAP 인식 애플리케이션 사이에 정보를 교환하는 방법을 설명한다.
원문 게재일: 2002 년 11 월 21 일 (출판일: 2002 년 3 월 01 일)
난이도: 초급
WSDL은 웹 서비스 인터페이스를 설명한다. 웹 서비스 소유자는 SOAP을 사용하여 그들의 인터페이스를 구현한다. 따라서 WSDL 서비스는 실제로 SOAP 서비스로서 존재한다. 웹 서비스 사용자가 WSDL 파일을 갖고 있으면, 그 사용자는 인터페이스 세부사항을 알고있는 것이다. 사용자는 웹 서비스와 통신하기 위해 SOAP을 사용하고 있다.
SOAP을 사용하여 인터넷을 통해 원격 WSDL 인터페이스와 액세스로 노출할 수 있는 객체로서 웹 서비스를 생각해보라. 서비스는 객체이기 때문에, 각 서비스의 호출에 대한 각 서비스의 행동과 관련된 속성이 있어야 한다. SOAP 메시지들은 HTTP를 통해 작동하는 XML 문서이다.
Business-to-business (B2B)와 application-to-application (A2A) 요구사항에는 기업은 정보를 공유하기 위하여 서로 통신한다고 명시하고 있다. 이러한 개념은 B2B, 워크플로우, 엔터프라이즈 통합에 쓰이고 있다. 예를 들어 고객의 요구사항을 수행하기 위해 공급자의 서비스를 호출해야 하는 기업들의 수직적인 공급 체인을 생각해보자. 몇몇 공급자들은 공급 체인으로 더 들어가서 다른 기업들의 서비스를 호출해야 한다.
그와 같은 애플리케이션에서 상호운용성(interoperability)이 가장 중요하다는 것은 명백하다. 하나의 기업은 단지 한 끝의 SOAP 통신 채널을 구현한다. 다른 끝은 인터넷의 어느 지점의 누군가가 될 것이다.
기업간 통합과 상호운용성은 소프트웨어 엔지니어와 기업들에게 있어서 지난 몇 년간 도전적인 일이였다. 플랫폼 의존성 또한 통합과 상호 운용성을 성취하는 데 있어서 큰 문제였다. SOAP은 기업간 통합과 상호 운용성을 이루는 데 있어서 가장 단순한 메커니즘이다.
SOAP에 대한 기본적인 이해와 목표를 가지고 이제 나는 아키텍쳐로 논의의 방향을 바꾸려 한다. 그림 1을 보면 전형적인 SOAP 통신 아키텍쳐의 컴포넌트를 알 수 있다:
- SOAP 클라이언트
- SOAP 서버
- 실제 서비스
그림 1. 전형적인 SOAP 통신 아키텍쳐의 컴포넌트
|
SOAP 클라이언트는 SOAP을 인식하는 머신이며, HTTP를 통해서 SOAP 서버로 SOAP 요청을 만들어 보낼 수 있다. SOAP 요청은 SOAP 메시지의 한 유형이다; 일반적으로 두 개의 SOAP 메시지 유형이 있다: SOAP 요청은 SOAP 클라이언트가 SOAP 서버에 보내는 것이고 SOAP 응답은 SOAP 서버가 응답 시 SOAP 클라이언트로 보내는 것이다. Listing 1은 전형적인 SOAP 요청이고, Listing 2는 SOAP 응답이다.
Listing 1: SOAP 요청
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" > <SOAP-ENV:Body> <m:getListOfModels xmlns:m = "uri reference" > </m:getListOfModels> </SOAP-ENV:Body></SOAP-ENV:Envelope> |
SOAP 서버 역시 SOAP 인식 머신이며 SOAP 클라이언트에서 요청을 수락하여 적절한 응답을 만들어 낼 수 있다. 이렇게 암호화된 응답은 요청을 했던 SOAP 클라이언트로 돌아간다. SOAP 서버 내부에서는 세 개의 엔터티가 있다:
- 서비스 매니저
- 전개된 서비스 리스트
- XML 트랜슬레이터
서비스 매니저는 요청에 대해 서비스를 관리하는 책임이 있다. Listing 1의 SOAP 요청을 보면, <m:getListOfModels xmlns:m="urn:MobilePhoneservice" >
엘리먼트는 서비스의 이름을 포함하고 있다. 서비스 매니저는 SOAP 서비스의 이름을 읽는다. SOAP 서비스는 SOAP 클라이언트가 호출하여 SOAP 서버에 필요로 하는 서비스가 있는지의 여부를 점검하길 원하는 서비스이다. 그 끝쪽에서는, 전개된 서비스 리스트를 점검한다. 이 리스트는 SOAP 서버가 호스팅하고 있는 모든 서비스 리스트이다. 서비스가 있다면, 서비스 매니저는 SOAP 요청을 XML 트랜슬레이터로 전달한다. XML 트랜슬레이터는 XML 구조의 SOAP 요청을 실제 서비스를 구현하는데 쓰인 프로그래밍 언어 구조로 바꾼다. 또한 실제 서비스의 응답을 XML 구조의 SOAP 응답으로 바꾸는 책임도 있다. Listing 2 SOAP 응답이 설명되어 있다.
Listing 2: SOAP 응답
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <m:getListOfModelsResponse xmlns:m="urn:MobilePhoneservice"> <Model>M1</Model> <Model>M2</Model> <Model>M3</Model> </m:getPriceResponse> </SOAP-ENV:Body></SOAP-ENV:Envelope> |
그림 1에서 실제 서비스(actual service)라고 쓰여진 부분은 실제 서비스가 존재하고 있는 위치이다. 서비스 구현은 COM 컴포넌트나 JavaBeans 컴포넌트의 형태로 된다. XML 트랜슬레이터는 XML 구조를 적절한 메소드 호출로 번역한다. XML 트랜슬레이터가 실제 서비스 구현의 메소드를 호출하면 메소드는 본연의 작업을 수행하고 결과 정보를 XML 트랜슬레이터로 리턴한다.
그림 1에서 화살표를 보면 XML 트랜슬레이터가 실제 서비스로 향하고 있는 것을 알 수 있다. 이 화살의 양 끝은 같은 기업내에 있는데, 이것은 같은 조직은 통신의 양 끝에서 인터페이스를 통한 콘트롤을 가진다는 것을 의미한다. 이것을 SOAP 클라이언트와 SOAP 서버 사이의 화살표와 비교하라. 엔터프라이즈의 영역이 교차되어있다. 이것은 실제로 SOAP의 목적이다.
SOAP 클라이언트가 SOAP 서버로 SOAP 메시지를 보낼 때 HTTP 전송 프로토콜을 사용한다. 이를 SOAP Binding with HTTP라고 한다. SOAP 서버가 메시지를 받으면, 서버는 메시지를 서비스 매니저로 넘긴다. 이것은 SOAP 메시지에서 요청된 서비스에 대해 전개된 서비스 리스트들을 점검한다. 요청 서비스를 찾을 수 없으면, 이것은 요청 실패 응답을 SOAP 클라이언트로 보낸다. 서비스가 가능하면 콘트롤은 서비스 매니저에서XML 트랜슬레이터로 전송된다. 이것은 적절한 언어 변환을 수행하고 실제 서비스 구현에 액세스 한다. 서비스 구현은 요청을 처리하고 결과를 XML 트랜슬레이터로 보낸다. XML 트랜슬레이터는 이것을 SOAP 클라이언트가 이해 할 수 있는 SOAP 응답 (XML 문서)으로 변환한다. HTTP binding은 SOAP 응답을 전송하는데 사용된다.
HTTP으로 SOAP을 바인딩하거나 HTTP를 통해 SOAP을 실행할 때, 실제로 SOAP 요청과 응답에 HTTP를 추가해야 한다. Listing 1은 전형적인 SOAP 요청의 구조인 반면 Listings 3, 4, 5, 6 은 Listing 1에 HTTP 헤더가 추가되었다는 것을 나타내는 완전한 HTTP 요청이다. 이와 비슷하게, Listing 7 은 Listing 2의 SOAP 응답에 상응하는 완전한 HTTP 응답이다.
HTTP을 통해 SOAP을 사용할 때마다, Content-Type 필드는 text/xml 이어야 한다. Listing 3 부터 Listing 7을 참조하라.
HTTP 요청 메소드인 POST와 함께 SOAP을 사용할 수 있다. SOAP HTTP 요청을 보내기 위해, SOAPAction 헤더 필드를 HTTP에 공급해야 한다.
SOAPAction은 SOAP 요청의 의도를 정의한다. 서버 (예를들어 HTTP에서 SOAP 요청 메시지를 필터링하는 방화벽)는 SOAPAction의 값을 결정하는데 사용할 수 있다.
HTTP 클라이언트는 SOAP HTTP 요청이 발생할 때 이 헤더 필드를 사용한다. SOAPAction은 다음 값 중 하나를 가질 수 있다: SOAPAction: "URI-Reference"
SOAPAction: "filename"
SOAPAction: ""
SOAPAction:
Listing 3: SOAPAction 헤더 필더의 URI 레퍼런스
POST /Vendors HTTP/1.1Host: www.mobilephoneservice.comContent-Type:"text/xml";Charset="utf-8"Content-Length: nnnnSOAPACtion:"www.mobilephoneservice.com/Vendors/MobilePhoneservice#getListOfModels"<?xml version="1.0"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" > <SOAP-ENV:Body> <m:getListOfModels xmlns:m="urn:MobilePhoneservice" > </m:getListOfModels> </SOAP-ENV:Body></SOAP-ENV:Envelope> |
Listing 3의 SOAPAction에는 다음과 같은 URI Reference가 포함되어 있다: www.mobilephoneservice.com/Vendors/MobilePhoneservice#getListOfModels
이 SOAPAction은 두 가지를 나타낸다. 첫 번째는 특정 SOAP 전개의 주소를 나타낸다: www.mobilephoneservice.com/Vendors/MobilePhoneservice
두 번째는 메소드 이름을 부여해주는 식별자이다( #getListOfModels
).
Listing 4: SOAPAction 헤더 필드의 파일 이름
POST /Vendors HTTP/1.1Host: www.mobilephoneservice.comContent-Type:"text/xml";Charset="utf-8"Content-Length: nnnnSOAPAction:"MobilePhoneservice#getListOfModels"<?xml version="1.0"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" > <SOAP-ENV:Body> <m:getListOfModels xmlns:m="urn:MobilePhoneservice" > </m:getListOfModels> </SOAP-ENV:Body></SOAP-ENV:Envelope> |
Listing 4 의 SOAPAction에는 파일 이름 ( MobilePhoneservice#getListOfModels
)이 포함되어 있다. MobilePhoneservice
파일은 호스트 URI ( www.mobilephoneservice.com/Vendors
)에 나타나야 한다. 이 호스트 URI는 HTTP 헤더 ( www.mobilephoneservice.com
)의 호스트 필드와 폴더 이름 /Vendors
의 조합이다.
Listing 5: SOAPAction 헤더의 빈 스트링
POST /Vendors HTTP/1.1Host: www.mobilephoneservice.comContent-Type:"text/xml";Charset="utf-8"Content-Length: nnnnSOAPAction:""<?xml version="1.0"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" > <SOAP-ENV:Body> <m:getListOfModels xmlns:m="urn:MobilePhoneservice" > </m:getListOfModels></SOAP-ENV:Body></SOAP-ENV:Envelope> |
Listing 5의 SOAPAction에는 빈 스트링 ("")이 있다. 이 비어있는 스트링 값은 SOAP의 목적이 Host URI (www.mobilephoneservice.com/Vendors
)와 같다는 것을 나타내고 있다.
Listing 6: SOAPAction 헤더에 값이 없음
POST /Vendors HTTP/1.1Host: www.mobilephoneservice.comContent-Type:"text/xml";Charset="utf-8"Content-Length: nnnnSOAPAction:<?xml version="1.0"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" > <SOAP-ENV:Body> <m:getListOfModels xmlns:m ="urn:MobilePhoneservice" > </m:getListOfModels></SOAP-ENV:Body></SOAP-ENV:Envelope> |
Listing 6 에는 SOAPAction에 대한 값이 없다. 이것은 메시지의 목적에 대한 정보가 없다는 것을 나타낸다.
두 가지 가능한 SOAP 응답 유형중 하나가 될 수 있다:
- SOAP 결과를 만들어내는 성공적인 SOAP 작동
- SOAP 실패 메시지가 된 성공하지 못한 SOAP 작동
Listing 7: HTTP 헤더가 있는 성공적인 SOAP 응답
HTTP/1.1 Content-Type:"text/xml"; Charset="utf-8"Content-Length: nnnn<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" ><SOAP-ENV:Body> <m:getListOfModelsResponse xmlns:m = "URI-Reference"> <model>m1</model> <model>m2</model> </m:getListOfModels></SOAP-ENV:Body> |
Listing 7은 SOAP 서버에서 상당한 결과를 얻게된 첫 번째 유형이다.
Listing 8은 전형적인 SOAP 실패 메시지이다. SOAP HTTP 응답은 HTTP에서 상태 정보를 통신하는데 사용되는 HTTP 상태 코드의 구조 뒤에 온다. 요청을 처리하는 동안 발생한 SOAP 에러의 경우, SOAP HTTP 서버는 HTTP 500 "Internal Server Error"를 발생시킨다.
Listing 8: HTTP 헤더가 있는 전형적인 SOAP 실패 메시지
HTTP/1.1 500 Internal Server ErrorContent-Type: "text/xml"; Charset="utf-8"Content-Length: nnnn<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" > <SOAP-ENV:Body> <SOAP-ENV:Fault> <faultstring>Failed to process the request</faultstring> </SOAP-ENV:Fault> </SOAP-ENV:Body></SOAP-ENV:Envelope> |
HTTP는 SOAP 메시지를 바인딩하는 유일한 솔루션이 아니다. HTTP가 적합하지 않을 경우 SOAP 바인딩에 SMPT 같은 메커니즘을 사용할 수 있다. SOAP을 SMTP에 바인딩하면서, 한 방향 전송 루트를 만들 수 있다. 두 개의 한 방향 메시지는 요청/응답 통신을 만드는데 사용할 수 있다. SMTP로 SOAP 메시지를 보내려면, 다음 절차를 거쳐야 한다:
- MIME-Version 헤더 필더 사용
MIME-Version 은 다른 MIME 버전들을 차별화하기 위해 버전 번호를 사용한다. 이것은 메일 프로세싱 에이전트 (POP 서버)가 구 버전과 신 버전에서 만들어진 메일 메시지들을 구별할 수 있도록 한다. Listing 9 에는 MIME-Version 헤더 필더를 사용했다. - Content-Type 헤더 필더 사용:
Content-Type 은 메시지 바디서 서 데이터 유형을 식별하는 데 사용된다. SOAP 메시지의 경우 Content-Type은 "text/xml" 값을 가져야 한다. Listing 9 은 Content-Type을 사용한 것이다. - Content-Transfer-Encoding 필드의 사용:
Content-Transfer-Encoding은 전송 인코딩 유형을 지정하는데 사용된다. 이를 테면 전송하고자 하는 데이터가 캐릭터 포맷인지 또는 바이리 리 포맷인지를 지정하는 것이다. Listing 9는 Quoted-Printable 인코딩을 사용한다. 이것은 메일 전송 에이전트가 결과 옥텟을 수정하지 않는 방식으로 데이터를 암호화한다. Listing 9에는 Content-Transfer-Encoding을 사용한다.
Listing 9: 이메일과 SOAP
TO: <info@waxsys.com>From: <abc@punjab.com>Reply-To: <abc@punjab.com>Date: SAT, 2 Feb 2002 16:00:00 Message-Id: <4FAB345C8D93E93B7A6E9@punjab.com>MIME-Version: 1.0Content-Type: text/xml; charset=utf-8Content-Transfer-Encoding: QUOTED-PRINTABLE<?xml version ="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <prnt:echoString xmlns:prnt="http://waxsys.com"> <msgString>Put your mail Message</msgString> </prnt:echoString> </SOAP-ENV:Body></SOAP-ENV:Envelope> |
SOAP 메시지는 선택적인 SOAP Header와 의무적인 SOAP Body를 가진 의무적인 SOAP Envelope으로 구성되어 있는 XML 문서이다.
Envelope:
Envelope은 SOAP 메시지를 나타내는 상위 엘리먼트이다. 이 엘리먼트는 SOAP 메시지를보내기 위해 나타난다. Envelope은 SOAP 네임스페이스 식별자인 http://schemas.xmlsoap.org/soap/envelope/
를 사용하는 데 이는 필수적이다. Envelope이 잘못된 네임스페이스를 포함하고 있으면, Envelope 네임스페이스 버전과 관련한 에러가 만들어진다. Listing 10은 빈 Envelope이다. 편지를 "우편으로 부치기(post)" 전에 "편지(letter)"가 포함되어야 한다는 것을 강조하기 위해서 "empty envelope" 이라고 한다. SOAP 스키마에서 "letter"는 "SOAP Body"로 간주되며 HTTP POST는 전송 메커니즘이다.
Listing 10: 비어있는 SOAP Envelope
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"></SOAP-ENV:Envelope> |
Header:
SOAP Header는 선택적이다. SOAP Envelope 내부에 SOAP 바디를 직접 래핑(wrap)하여 헤더를 함께 스킵할 수 있다. 헤더는 SOAP 메시지의 기능을 확장하는 메커니즘을 제공한다. 예를 들어, 인증(authentication)은 SOAP Header 엔트리와 함께 제공되는 전형적인 확장이다. 이 경우 인증 프레임웍이 있어서 저 수준 전송으로서 SOAP을 사용한다. Listing 11에서 SOAP의 헤더 구현을 참조하라.
Listing 11: SOAP Envelope에서의 헤더 구현
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header> <m:Order xmlns:m="some URI" SOAP-ENV:mustUnderstand="1"> </m:Order></SOAP-ENV:Header></SOAP-ENV:Envelope> |
Body:
Body 엘리먼트는 보내고자 하는 실제 메시지를 포함하게 된다. 이것은 의무적인 엘리먼트 이며 자식 엘리먼트는 일반적으로 사용자 정의의 네임스페이스에 속해있다. Listing 12 는 사용자 정의 네임스페이스 "u"
를 나타내는 SOAP 메시지이다. Body 엘리먼트는 의무적인 정보의 콘테이너이다. 엘리먼트는 SOAP 메시지에 나타나야 하며 직접적인 SOAP Envelope 엘리먼트의 자식 엘리먼트도 되어야 한다. SOAP 헤더 엘리먼트 뒤에 따라와야 한다. Header 엘리먼트가 나타나지 않으면 Envelope 엘리먼트 뒤에 직접 따라와야 한다. 바디는 자식 엘리먼트를 포함하고 있고 네임스페이스가 보장된다.
Listing 12: SOAP Envelope의 Header와 Body
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header> <m:Order xmlns:m="some URI" SOAP-ENV:mustUnderstand="1"> </m:Order></SOAP-ENV:Header><SOAP-ENV:Body> <u:GetPrice xmlns:u="some URI" > <model>m1</model> </u:GetPrice></SOAP-ENV:Body></SOAP-ENV:Envelope> |
Fault의 하위 엘리먼트는:
faultcode
(fault 확인)faultstring
(fault 설명)faultactor
(fault 원인 확인)detail
(에러에 대한 상세한 설명)
Listing 13은 전형적인 fault 메시지이다.
Listing 13: 애플리케이션 에러가 발생할 때 SOAP Fault 사용하기
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header><m:Order xmlns:m="some URI" SOAP-ENV:mustUnderstand="1"></m:Order></SOAP-ENV:Header><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>Not necessary information</faultstring><detail> <d:faultdetail xmlns:d = "uri-referrence"> <msg> application is not responding properly. </msg> <errorcode>12</errorcode> </d:faultdetail></detail></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope> |
SOAP 메시지(요청과 응답)의 일반적인 신택스를 설명하면서, Part 1의 MobilePhoneservice를 SOAP으로 요청하는 방법을 설명하겠다. Part 1에서는 MobilPhoneservice를 설명하는 완벽한 WSDL 인터페이스를 설계했다. Mobile Company는 MobilePhoneservice에 두 가지 메소드를 제공한다. 하나는 getListOfModels()
이고 다른 하나는 getPrice(modelNumber)
이다. GetListOfModels()
는 매개변수를 취하지 않지만 Mobile 모델 리스트를 리턴하는 반면 getPrice(modelNumber)
는 매개변수 modelNumber
를 취하고 요청된 모델의 price
를 리턴한다. SOAP 요청 형식으로 문서화 하겠지만 우선 SOAP 요청과 응답의 일반적인 형식을 보여주겠다.
Listing 14: SOAP 요청의 일반적인 형식
<SOAP-ENV:Envelope xmlns:SOAP-ENV ="SOAP schema's URI"<SOAP-ENV:Body> <Instance:"Method Name" xmlns:Instance= "URI where method is located"> <parameter1>value</parameter1> <parametern>value</parametern> </Instance:"Method Name"></SOAP_Envelop:Body></SOAP-ENV:Envelope> |
하나의 SOAP 요청 또는 응답은 서비스의 한 메소드를 지정할 수 있다. SOAP 요청을 포함하는 envelop의 일반적인 형태는 Listing 14의 형식을 취한다. 이러한 일반적인 형식을 Listing 16의 getListOfModels()
메소드 호출 요청과 비교하라. Listing 16 에서, 메소드와 URI에 대한 이름을 제공했다. getListOfModels()
에 요구되는 매개변수가 없기 때문에, <m:getListOfModels>
는 Listing 16에서 빈 엘리먼트이다.
Listing 15: SOAP 응답의 일반적인 형식
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body> <Instance:"Method Name"+"Response" xmlns:Instance="URI where method is located"> <return> <responseparameter1>value</responseparameter1> <responseparametern>value</responseparametern> </return> </Instance: "Method Name"+"Response"></SOAP-ENV:Body></SOAP-ENV:Envelope> |
Listing 15는 일반적인 SOAP 응답이다. Apache SOAP 서버는 "Response" 키워드를 메소드 이름의 끝에 추가하고 직접적인 자식 메소드 엘리먼트로서 <return>
엘리먼트에 리턴 값을 집어넣는다. 리턴 값이 복잡한 구조이면 <return>
엘리먼트는 하나 이상의 <item>
엘리먼트를 포함한다. Listing 15와 Listing 17을 비교하면, getListOfModels()
메소드에서 실제 응답이다. Listing 17에는 Vector 데이터 유형으로서 아이템 리스트를 포함하고 있다. 이것은 리턴 매개변수이다. Listings 18과 19 는 MobilePhoneservice의 getPrice()
에 대한 SOAP 요청과 응답을 나타낸다.
Listing 16: getListOfModels() 메소드를 호출하는 SOAP 요청
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body> <m:getListOfModels xmlns:m = "www.mobilphoneservice.com" > </m:getListOfModels></SOAP-ENV:Body></SOAP-ENV:Envelope> |
Listing 17: Listing 16의 요청에 대한 SOAP 응답
<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"><SOAP-ENV:Body> <ns1:getListOfModelsResponse xmlns:ns1="urn:MobilePhoneservice" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <return xmlns:ns2="http://xml.apache.org/xml-soap" xsi:type="ns2:Vector"> <item xsi:type="xsd:string">M1</item> <item xsi:type="xsd:string">M2</item> <item xsi:type="xsd:string">M3</item> <item xsi:type="xsd:string">M4</item> <item xsi:type="xsd:string">M5</item> </return> </ns1:getListOfModelsResponse></SOAP-ENV:Body></SOAP-ENV:Envelope> |
Listing 18: getPrice 메소드에 대한 SOAP 요청
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"><SOAP-ENV:Body> <m:getPrice xmlns:m ="www.mobilphoneservice.com"> <modelNumber xsi:type ="xsd:String">M1</modelNumber> </m:getPrice></SOAP-ENV:Body></SOAP-ENV:Envelope> |
Listing 19: Listing 18의 요청에 대한 SOAP 응답
<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"><SOAP-ENV:Body> <ns1:getPriceResponse xmlns:ns1="urn:MobilePhoneservice" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <return xsi:type="xsd:string"> 5000 </return> </ns1:getPriceResponse></SOAP-ENV:Body></SOAP-ENV:Envelope> |
이제 Apache SOAP 서버에서 WSDL 서비스를 전개할 것이다. Apache SOAP 툴킷은 전개 설명 파일에서 WSDL 서비스 정보를 유지한다. 전개 디스크립터에는 WSDL 서비스의 이름과 이것이 포함하고 있는 모든 메소드가 포함되어 있다. 전개 디스크립터는 런타임시 SOAP 서버에 이러한 이름들을 제공한다. 같은 전개 디스크립터 파일은 인터페이스를 구현하는 JavaBean 컴포넌트의 주소를 포함하고 있다.
Listing 20: 전개 디스크립터 뼈대
<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment" id="URN:SERVICE-URN"><isd:provider type="java" scope="Request" methods="EXPOSED-METHODS"> <isd:java class="IMPLEMENTING-CLASS"/> </isd:provider><isd:faultListener>org.apache.soap.server.DOMFaultListener</isd:faultListener></isd:service> |
Listing 20은 세 비트의 정보를 필요로하는 전개 디스크립터 뼈대(skeleton) 이다 (URN:SERVICE-URN, EXPOSED-METHODS, IMPLEMENTING-CLASS). WSDL 기반의 서비스 전개 디스크립터로서 사용하기 위해서이다. URN:SERVICE-URN은 전개된 서비스의 이름이다. 이 경우, "urn:MobilePhoneservice"
가 된다. EXPOSED-METHODS는 서비스에서 제공된 메소드의 리스트를 분리했던 단일 공간이다. 전개 할 때 getListOfModels getPrice
가 된다.
IMPLEMENTING-CLASS는 완벽한 경로를 가진 자바 클래스 이름이다. (예를 들어, samples.phonequote.MobilePhoneservice
). 이 경우 애플리케이션을 테스트 하면서 다음 디렉토리 구조를 갖는다:
Apache SOAP server: C:\foo\SOAP-2_2
Mobile phone service implementation: C:\foo\SOAP-2_2\samples\phonequote\MobilePhoneservice
IMPLEMENTING-CLASS 경로는 SOAP 툴킷을 설치한 디렉토리를 나타낸다. 나는 아직 자바 클래스의 실제 구현을 제공하지 않았다. 이것은 비지니스 로직에 의존하고 무엇이든 될 수 있다.
Listing 21: MobilePhoneservice용 전개 디스크립터
<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment"id="urn:MobilePhoneservice"><isd:provider type="java" scope="Request" methods="getListOfModels getPrice"> <isd:java class="samples.phonequote.MobilePhoneservice"/></isd:provider><isd:faultListener> org.apache.soap.server.DOMFaultListener</isd:faultListener></isd:service> |
Listing 21은 WSDL 파일용 완벽한 전개 디스크립터이다.
SOAP 클라이언트와 서버의 통신을 나타내는 샘플 애플리케이션이 있다. 세 개의 Listing을 보자: Startup.html (Listing 22), Operation.html (Listing 23), Execute.jsp (Listing 24).
StartUp.html (Listing 22)은 사용자에게 GUI를 나타내는 간단한 HTML 파일이고 호출하고 싶은 SOAP 메소드가 무엇인지를 묻는다. 사용자는 메소드를 선택한다.
Listing 22: 프론트엔드로서 작동하는 HTML 페이지
<HTML><BODY bgcolor="Teal"><br/><p align="center"> <font size="5" face="Arial" color="white"><b> SOAP method invocation demo </b></font></p><hr/><font face="Arial" color="whitesmoke" size="3"><br/><b> Click any of the method name to execute.<br/> 1. Get the List of all Models that we manufacture.... <a href="execute.jsp?index=1"> <font color="orange"> GetListOfModels </font></a> <br/> 2. Get the Price of any particular model...................... <a href="operation.html"> <font color="orange"> GetPrice </font></a></b></BODY></HTML> |
Operation.html (Listing 23)은 사용자에게 메소드 호출과 함께 할 매개변수를 제공할 것을 요청한다.
Listing 23: 사용자가 선택한 것을 기준으로 사용자에게 GUI 나타내기
<HTML><BODY bgcolor="Teal"><br/><p align="center"> <font size="5" face="Arial" color="white"><b> GetPrice Operation input Form </b></font></p><hr/><p align="center"> <form action="execute.jsp" method="POST"><input type="hidden" name="index" value="0"><table textColor="white"><tr><td><font color="whitesmoke"><b>Description :</b></font></td><td><font color="whitesmoke"> Method GetPrice is used to Get Price of given Model Number</font></td></tr><tr><td><font color="whitesmoke"><b>Parameter(s)</b></font></td><td></td></tr><tr><td><font color="whitesmoke">Model Number </td></font><td><font color="whitesmoke"> <input type="text" name="parameter" size="30"> (required) </font></td></tr><tr><td> </td><td><input type="Submit" value="Invoke"></td></tr></font></table></form></p></BODY></HTML> |
Execute.jsp (Listing 24)에는 재미있는 모든 코드가 포함되어있다. 이것은 어떤 메소드가 호출되었고 어떤 매개변수가 전달되었는지를 감시한다. 그런다음 원격 서버로 메소드 호출을 전송한다.
Listing 24: 메소드 감시와 원격 서버로 호출하기
<%@ page language="java" import="java.util.Vector" %><%@ page import="java.net.MalformedURLException, java.net.URL" %><%@ page import="java.util.Vector" %><%@ page import="org.apache.soap.SOAPException, org.apache.soap.Constants" %><%@ page import="org.apache.soap.rpc.Call, org.apache.soap.rpc.Response, org.apache.soap.rpc.Parameter" %><%@ page import="org.apache.soap.transport.http.SOAPHTTPConnection" %><%@ page import="org.apache.soap.Fault" %><HTML><BODY bgcolor="Teal"><br/><p align="center"><font color="whitesmoke"><% boolean isParameter = false ; SOAPHTTPConnection soapTransport = new SOAPHTTPConnection(); // Address of the remote server. // Normally this should be dynamically passed and detected. // We have hard coded it only for demonstration. URL url = new URL ("http://localhost:8080/soap/servlet/rpcrouter"); // Build the call. Call call = new Call (); call.setTargetObjectURI ("urn:MobilePhoneservice"); call.setSOAPTransport (soapTransport); call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); // We'll detect which method user selected // and give a call accordingly. // We'll pass parameters if present. if (request.getParameter("parameter")!=null) isParameter = true; if (request.getParameter("index").equals("0")) { call.setMethodName("getPrice"); Vector params = new Vector(); String message = new String (request.getParameter("parameter")); params.addElement (new Parameter("message", String.class, message , null)); call.setParams(params); } else call.setMethodName("getListOfModels"); Response resp = call.invoke ( url, /* actionURI */ "" ); out.println("<p align=left> <font size=\"4\" face=\"Arial\" color=\"white\"> Response of [ "+call.getMethodName()+" ] </font><hr/>"); // Check the response. if (resp.generatedFault ()) { Fault fault = resp.getFault (); out.println("<b>Fault is:</b>"+ fault.getFaultCode () +" ["+fault.getFaultString ()+"]"); } else { Parameter result = resp.getReturnValue (); out.println("<b>Response is: </b>"+ result.getValue ()+""); }%><font></p></BODY></HTML> |
이 애플리케이션을 실행하기 위해서, 두 개의 Apache SOAP 서버가 필요하다. 한 개의 서버는 사용자와 통신하고 Listings 22, 23, 24를 호스팅한다. 다른 서버는(원격 서버) WSDL 기반 서비스를 전개하는 장소가 된다("Deployment of WSDL-based services on a SOAP server" 참조). 원격 서버의 주소를 http://localhost:8080/soap/servlet/rpcrouter
로 Execute.jsp (Listing 24)에 어렵게 코딩하였다.
단순한 데이터 유형과 복잡한 데이터 유형의 차이를 설명하겠다. 그런다음 SOAP에서 이를 인코딩하는지를 설명하겠다.
단순한 유형은 string, float, integer, enumeration 등을 포함한다. 예를들어 모바일폰의 "이름"은 "string"
의 유형을 갖는다. 복잡한 유형은 단순 유형에서 형성되지만 하나의 엔터티를 나타낸다. 예를 들어, "Student"
유형은 기록은 다른 애트리뷰트를 갖고있다.
Listing 25에는 "Mobile"
이라고 하는 복잡한 데이터 유형이 포함된다. SOAP 요청 시 이 유형을 사용한다.
Listing 25: "Mobile" 유형의 구조를 정의하는 스키마.
1<? xml version="1.0" ?>2<xsd:schema xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" 3 xmlns:xsd="http://www.w3.org/1999/XMLSchema">4 targetNameSpace= "www.mobilephoneservice.com/phonequote">5 <xsd:element name ="Mobile">6 <xsd:complexType>7 <xsd:element name="modelNumber" type="xsd:int">8 <xsd:element name="modelName" type="xsd:string">9 <xsd:element name="modelWeight" type="xsd:int">10 <xsd:element name="modelSize" type="xsd:int">11 <xsd:element name="modelColor">12 <simpleType base="xsd:string">13 <enumeration value="white" />14 <enumeration value="blue" />15 <enumeration value="black" />16 <enumeration value="red" />17 <enumeration value="pink" />18 </simpleType>19 </xsd:element>20 </complexType>21 </xsd:element>22</xsd:schema> |
Line 5 in Listing 25 의 5 라인은 유형의 이름(Mobile)을 나타내는 반면 6 라인은 이것이 복잡한 데이터 유형라라는 것을 나타낸다. 알다시피 복잡한 데이터 유형은 애트리뷰트를 갖고 있다. 7 라인에서 12 라인 까지는 "Mobile"
데이터 유형의 애트리뷰트를 보여준다.
7 라인에서 선언된 엘리먼트는 "Mobile"
유형이 "modelNumber"
라는 애트리뷰트를 갖고 있다는 것을 보여준다; 그리고 이것의 유형은 "int"
이다. 이와 비슷하게, 9라인과 10 라인에서 선언된 엘리먼트는 같은 유형을 갖고 있지만 다른 애트리뷰트 이름을 갖고 있다. 8 라인에서 정의된 엘리먼트는 "modelName"
이라는 애트리뷰트 이름을 갖고 있고 "string"
유형이다.
11 라인의 엘리먼트는 약간의 이해력이 필요하다. 왜냐하면 12 라인에서 "simpleType"
이라고 하는 하위 엘리먼트를 갖고 있기 때문이다. 여기에서 Mobile 이라고 하는 복잡한 유형 속에 간단한 유형을 정의한다. simpleType의 이름은 "modelColor"
이고 이것은 "enumeration"
이다. 이것은 "base"
라는 애트리뷰트를 갖고 있고 "xsd:string"
값을 수행한다. 이 값은 단순한 유형인 "modelColor"
가 SOAP 스키마에서 정의된 "string"
유형의 기능을 갖고 있다는 것을 나타낸다. 각각의 <enumeration> 태그(13~17 라인)는 "value"
( "white"
, "blue"
, "black"
, "red"
, "pink"
) 애트리뷰트를 수행한다. 열거 유형은 많은 옵션들 중 하나를 선택할 수 있도록 한다.
Listing 26 은 SOAP 요청 시 복잡한 유형의 사용 예제이다. Body 엘리먼트에 요청을 수행하는 envelope을 보여준다. Listing 26 은 uses the data typethat was defined in Listing 25에서 정의된 데이터 유형인 "Mobile"
을 사용한다.
AddModel 메소드는 "Mobile"
유형의 인자를 취한다. Listing 26의 <SOAP-ENV:Envelope>
엘리먼트에서 "xmlns:msd"
선언을 참조하라. 다음은 SOAP 요청 시 데이터 유형을 정의한 사용자를 적용하는 예제이다.
Listing 26: Listing 25에 정의된 "Mobile" 구조 구현
1 <SoAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"2 xmlns:xsd="http://www.w3.org/1999/XMLSchema" 3 xmlns:msd="www.mobilephoneservice.com/phonequote">4 <SOAP-ENV:Body>5 <m:addModel xmlns:m="www.mobilephoneservice.com">6 <msd:Mobile>7 <modelNumber>1</modelNumber>8 <modelName>mlr97</modelName>9 <modelWeight>10</modelWeight>10 <modelSize>4</modelSize>11 <modelColor>white</modelColor>12 </msd:Mobile>13 </m:addModel>14 </SOAP-ENV:Body>15<SOAP-ENV:Envelope> |
다음에는 사용자 정의의 데이터 유형의 예제를 좀 더 다루겠다. SOAP 상호운용성에 대해서도 기대하라.
- developerWorks worldwide 사이트에서 이 기사에 관한 영어원문.
- Simple Object Access Protocol (SOAP) 1.1
- 본 시리지의 Part 1: Deploying Web services with WSDL.
- SOAP 기술자료: XML.Com.
- SOAP의 기초.
- Scribner, Kenn et all "Understanding SOAP" , Sams.
- Bequet, Henry "Professional Java SOAP" , Wrox.
- Apache SOAP toolkit 다운로드.
'웹서비스' 카테고리의 다른 글
SOAP 해더에서 클라이언트 IP조회 방법 (0) | 2010.07.07 |
---|---|
SOAP 통신에서 weblogic parsing error - jar 의 충돌 (0) | 2010.07.05 |
오래된 SOAP문서 (0) | 2010.07.05 |
[JSP] XML 통신 예제 (0) | 2010.06.30 |
[JSP] XML 읽기 (0) | 2010.06.30 |