이번시간에는 WS Communication Protocol 중 현재 가장 널리 사용되고 있는 SOAP에 대한 기본적인 구조에 대해서 알아보겠다.
SOAP 은 서로 다른 플랫폼의 XML 분산컴퓨팅을 위한 기반기술이다. 분산컴퓨팅이라는 말처럼 SOAP내에는 분산컴퓨팅을 가능하게 하기 위한 기반기술이 XML Document로 정의되어지고 SOAP Message는 SOAP처리기라는 SOAP엔진에 의해 처리된다. 일반적으로 많이 쓰이는 엔진이 Axis 이고 해당 엔진은 많은 Vendor들에 의해 어플리케이션 서버와 같은 제품에 탑재되어 있다. SOAP자체는 일반 application이나 비즈니스 로직의 개발자나 업무사용자를 위한 기술이 아니라, 저 수준의 분산시스템 개발자를 위한 것이다. SOAP을 이해할때 중요한 포인트는 단순히 WS의 통신 Protocol이라는 개념으로 이해하지 말고 분산컴퓨팅을 위한 통신 Protocol이라는 개념을 항상 주지해야 한다는 것이다.
DS process간의 통신(interprocess communication)은 DS의 핵심이다. DS는 수천 수만의 process들이 Network에 편재해 있고 이러한 process들을 어떠한 표준적인 방법으로 접근하지 않는다면 많은 어려움이 뒤따를 것이다. 그래서 나타난 것이 표준적인 Rule인 Protocol이 등장했고 다음이 가장 널리 사용되는 Protocol이다.
- Remote Procedure Call ( RPC)
- Remote Method Invocation (RMI)
- Message-Oriented Middleware (MOM)
- Stream
이에 대한 자세한 사항은 Distributed System이라는 Category에서 다루기로 하겠다.
여기서 잠깐, 우선 일반 서적에서 얘기하고 있는 SOAP의 기본적인 Framework부터 살펴보고 SOAP 자체가 어떠한 확장성을 가지는지는 다음시간에 다루겠다. 쉽게쉽게가자. 정리하느라 힘들당.
[ SOAP Envelope Framework ]
SOAP 에서 가장 중요한 부분은 Envelope Framework이다. 메시지에 무엇이 있는지와 이를 어떻게 처리하는지를 설명하는 Framwork을 정의하는 인벨롭(envelope), 애플리케이션 정의의(application-defined) 데이터 유형의 인스턴스를 표현하는 인코딩 규칙, 원격 프로시져 호출과 응답을 나타내는 규칙 등 세 부분으로 구성된 XML 기반의 프로토콜이다
Figure1. 기본 구조
SOAP은 크게 세부분, Envelope, Header, Body로 나뉜다.
- [ Envelope ] SOAP Message 의 root 로서 전체 Message에 대한 Encoding Style을 정의할 수 있다.
- [ Header ] Envelope 의 Child Element로서 optional하고 1회이상 쓰일 수 있다. Header는 Security, Transaction, Reliable Message, QoS 등과 같은 추가적인 기능을 포함할 수 있는 확장 메커니즘을 제공한다. 또한 SOAP Node간의 각종 Spec과 관련된 협약의 준수여부를 나타내는 mustUnderstande 속성을 제공한다.
- [ Body ] 실질적인 Data가 들어가는 곳이다. 다른말로 하면 Body Element내에는 최종수신자에게 보내져야 하는 정보가 들어가 있다. 어떤 서비스를 이용할 것인지, 요청과 응답 Data는 무엇인지 등등
그럼 Header와 Body에 대해서 좀더 자세히 알아보자.
[ Header ]
SOAP Spec은 message path에 서 처리되어야하는 rule을 정의할 수 있는데 처리되어야 하는 rule을 정의하는 곳이 바로 Header block이다. 여기서 message path는 SOAP message가 최초의 sender로 부터 최종 receiver까지 가는데 거쳐야 하는 경로를 말한다. message path상에 등록되어 있는 SOAP Node들을 Intermediaries라 하는데 spec에서는 어떠한 intermediary가 특정 header block을 처리할 것인지를 정의하고 있다. SOAP은 Network상의 SOAP application들 간의 message를 상호 교환하기 위한 protocol이다. 여기서 SOAP application이라 함은 SOAP message를 생성하거나 처리하기 위한 일종의 software이다. 예를 들어 여느 java application 혹은 J2EE component가 JAX-RPC를 사용한다면 일종의 SOAP application이라고 볼 수 있다. SOAP message는 message path를 경유하는데 모든 SOAP message는 최초의 message를 생성하는 initial sender로 부터 시작해서 최종 message를 처리하는 ultimate receiver로 끝이 난다.
Figure2. The SOAP Message Path
SOAP message가 message path를 경유할 때 SOAP header block은 지정된 SOAP node에 의해 intercept되서 해당 header block을 처리하게 되는데 SOAP Node들은 sender 와 receiver의 역할을 병행한다. 여기서 잠시 예를 들어보자.
Figure3. The Message Path of the Purchase-Order SOAP Message.
Figure3 은 Purchase Order라는 SOAP message가 Customer, Sales, Accounts, Inventory, Shipping SOAP nodes경유하는 message path이다. Intermediaries는 SOAP body block를 처리하거나 수정할 수 없고 단지 header block을 처리하는 역할을 한다. 실질적인 SOAP message를 살펴보도록 하자.
List1. The process-by Header block.
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:mi="http://www.Monson-Haefel.com/jwsbook/message-id"
xmlns:proc="http://www.Monson-Haefel.com/jwsbook/processed-by">
<soap:Header>
<mi:message-id>11d1def534ea:b1c5fa:f3bfb4dcd7:-8000</mi:message-id>
<proc:processed-by>
<node>
<time-in-millis>1013694680000</time-in-millis>
<identity>http://www.customer.com</identity>
</node>
<node>
<time-in-millis>1013694680010</time-in-millis>
<identity>http://www.Monson-Haefel.com/sales</identity>
</node>
<node>
<time-in-millis>1013694680020</time-in-millis>
<identity>http://www.Monson-Haefel.com/AR</identity>
</node>
<node>
<time-in-millis>1013694680030</time-in-millis>
<identity>http://www.Monson-Haefel.com/inventory</identity>
</node>
<node>
<time-in-millis>1013694680040</time-in-millis>
<identity>http://www.Monson-Haefel.com/shipping</identity>
</node>
</proc:processed-by>
</soap:Header>
<soap:Body>
<!-- Application-specific data goes here -->
</soap:Body>
</soap:Envelope>
List1에서 process-by 라는 Header Block은 SOAP Message를 처리한 SOAP node들에 대한 기록을 남긴 것이다. 이말은 Message Path에 있는 SOAP node들이 SOAP Message를 처리하면서 SOAP Message에 내용을 추가하거나 뺄 수도 있다는 얘기이다. 그럼 SOAP node들은 어떤 Header block을 처리해야 하는지 어떻게 알까? 이에 대해 SOAP Spec은 특정 Header Block을 처리하는 node를 식별하기 위한 actor 속성을 도입했다.
actor 속성은 역할에 대한 URI 형태의 식별자이다. 그래서 해당 SOAP Message가 Message Path를 경유할때 해당 actor의 역할을 하기로 되어 있는 SOAP node에서는 처리되어지고 다른 node에서는 무시된다.
List2. The actor Attribute.
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:mi="http://www.Monson-Haefel.com/jwsbook/message-id"
xmlns:proc="http://www.Monson-Haefel.com/jwsbook/processed-by">
<soap:Header>
<mi:message-id soap:actor="http://www.Monson-Haefel.com/logger" >
11d1def534ea:b1c5fa:f3bfb4dcd7:-8000
</mi:message-id>
<proc:processed-by>
<node>
<time-in-millis>1013694680000</time-in-millis>
<identity>http://www.customer.com</identity>
</node>
</proc:processed-by>
</soap:Header>
<soap:Body>
<!-- Application-specific data goes here -->
</soap:Body>
</soap:Envelope>
List2를 보면 soap:actor="http://www.Mansoa-Haefel.com/logger" 을 볼 수가 있는데 actor에 대한 식별자를 URI로 식별하고 있으며 해당 actor에 대한 처리 노드는 해당 처리절차를 진행한다.
일 반적인 관점으로 SOAP Header를 봤을때 SOAP Header는 meta-data를 처리하기 위한 뛰어난 확장성을 지닌다. Security, Transaction, QoS, Message Persistence, Routing 등 실제 Data와는 상관이 없는 meta-data를 처리하기 위한 기반을 제공하고 있다. 물론 범용적으로 사용되는 표준은 OASIS같은 단체에서 관장하고 있으며 Domain에 custom한 방식으로도 사용될 수 있다.
[ BODY ]
SOAP BODY에는 웹 서비스간 교환하려는 실질적인 Data, 어느 operation을 call할것인지, 넘겨줄 parameter는 무엇인지, return 값은 무엇인지, error발생시 fault 메세지 등, 상호운영상에 교환되는 Data가 들어간다. Header Element는 선택적으로 사용될 수 있지만 Body Element는 필수적인 요소이다. 또한 Message Path에서 Body Element를 처리할 수 있는 SOAP node는 Ultimate Node 뿐이다.
상호운영 시 error가 발생해 Body Element에 적용되는 fault message를 제외하고 SOAP은 Body의 Contents가 well-formed XML이라면 어떠한 XML message가 적용되더라도 상관하지 않는다. 물론 웹서비스간 상호운영성에 맞는 Rule를 적용해야 되겠지만서도.......
웹서비스는 상호운영하는데 있어 XML 기반의 Protocol을 사용한다. 즉. Text기반의 Message로 상호간의 원하는 일을 수행한다는 것이다. 그래서 SOAP에서는 4종류의 messaging mode를 지원한다.
- RPC/Literal
- Document/Literal
- RPC/Encoded
- Document/Encoded
messaging mode는 messaging style(RPC/Document)과 encoding style(Section 5/Literal)에 의해 정의되는데 여기서는 RPC/Literal과 Document/Literal에 대해서 알아보겠다.
Figure 4. Document Literal and RPC Literal
Document / Literal
SOAP Body Element내에 well-formed XML Document가 embed되어 있는것을 말한다. List3에서는 namespace가 http://www.Monson-Haefel.com/jwsbook/PO 인 XML Schema에 따르는 XML Message가 embed되어 있다.
List3. A Document Style SOAP Message.
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:mi="http://www.Monson-Haefel.com/jwsbook/message-id"
xmlns:proc="http://www.Monson-Haefel.com/jwsbook/processed-by">
<soap:Header>
<!-- Header blocks go here -->
</soap:Header>
<soap:Body>
<po:purchaseOrder orderDate="2003-09-22"
xmlns:po="http://www.Monson-Haefel.com/jwsbook/PO">
<po:accountName>Amazon.com</po:accountName>
<po:accountNumber>923</po:accountNumber>
...
<po:book>
<po:title>J2EE Web Services</po:title>
<po:quantity>300</po:quantity>
<po:wholesale-price>24.99</po:wholesale-price>
</po:book>
</po:purchaseOrder> </soap:Body>
</soap:Envelope>
RPC / Literal
주 로 기존의 Component를 web serivice화할때 사용하는 방식으로 RPC Request Message에는 method명과 input parameter명이 오고, RPC Response Message에는 return value와 output parameter or fault message가 온다. 기존의 component로는 servlet, stateless session bean, Java RMI object, CORBA object, DCOM component 등이 있다.
List4. An RPC/Literal SOAP Request Message
List4에서는 SOAP Request Method로 getBookPrice를 call 했고 input parameter로 isbn을 넘겨주었다.
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:mh="http://www.Monson-Haefel.com/jwsbook/BookQuote">
<soap:Body>
<mh:getBookPrice>
<isbn>0321146182</isbn>
</mh:getBookPrice> </soap:Body>
</soap:Envelope>
List5. An RPC/Literal SOAP Response Message
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:mh="http://www.Monson-Haefel.com/jwsbook/BookQuote" >
<soap:Body>
<mh:getBookPriceResponse>
<result>24.99</result>
</mh:getBookPriceResponse> </soap:Body>
</soap:Envelope>
List5에서는 List4에 대한 응답으로 return value인 result를 반환하였다.
[ SOAP Fault ]
Message Path에서 어떠한 한 노드에서 error가 발생했다면 해당 SOAP Fault message는 이전단계의 node로 전송된다. 물론 이러한 방식은 Request / Response Messaging mode에서 발생하며 One-Way mode에서는 fault message를 전송하지 않는다. 예를 들어 Message Path상에 있는 3번째 node에서 error발생했다면 이전단계의 node에게만 fault message가 전송되며 최초의 node에는 message가 전송되지 않는다. fault message를 받은 node는 해당 fault에 대한 적절한 action을 취한 후 최초의 node에게 다른 fault message를 전송한다. SOAP message는 Body Element에 Fault Element를 포함하고 있는데 List6는 이에 대한 예제이다.
List6. A SOAP Fault Message.
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:mh="http://www.Monson-Haefel.com/jwsbook/BookQuote" >
<soap:Body>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>
The ISBN value contains invalid characters
</faultstring>
<faultactor>http://www.xyzcorp.com</faultactor>
<detail>
<mh:InvalidIsbnFaultDetail>
<offending-value>19318224-D</offending-value>
<conformance-rules>
The first nine characters must be digits. The last
character may be a digit or the letter 'X'. Case is
not important.
</conformance-rules>
</mh:InvalidIsbnFaultDetail>
</detail>
</soap:Fault> </soap:Body>
</soap:Envelope>
List6에서 보는바와 같이 fault message가 생성되었을 때 SOAP message의 Body는 Fault Element만을 포함하고 최초 Requester가 기대했던 Response는 포함되지 않는다. Fault Element에는 faulcode, faultstring, faultactor, detail element를 child element로 갖는다.
- faultcode Element
- faultstring Element
- faultactor Element
- detail Element
faultcode는 standard code 리스트가 오는데 Client, Server, VersionMismatch, MustUnderstand 등이 있다.
faulstring은 code와는 달리 가독성이 좋은 fault message가 온다.
faultactor는 error가 발생하고 fault를 생성한 node가 온다.
detail은 faultstring보다 더 자세한 message가 온다.
- 출처 : http://ammoguy.springnote.com/pages/2289108 -