SOAP2011. 4. 5. 15:29

Tip: SOAP attachments와 JAX-RPC

 

 


난이도 : 중급

Russell Butek, 소프트웨어 엔지니어, IBM

2004 년 2 월 27 일

JAX-RPC는 SOAP with attachments를 지원한다. JAX-RPC API를 사용하여 MIME attachments를 보내는 방법을 이 글에서 설명한다.

SOAP 메시징 프로토콜은 SOAP 메시지들을 통해 MIME attachments를 보낼 수 있도록 한다. WSDL은 이 attachment의 디스크립션을 제공한다. JAX-RPC는 attachment의 WSDL 디스크립션을 자바로 매핑한다. 이 글에서 JAX-RPC 매핑을 사용하여 SOAP 메시지에서 attachment를 보내는 방법을 설명한다.

WSDL

attachment의 WSDL 디스크립션은 그다지 단순하지가 않다. Listing 1의 WSDL을 보자.


Listing 1. WSDL with attachments
<?xml version="1.0" encoding="utf-8"?>
<definitions
    xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
    targetNamespace="urn:attachment.tip"
    xmlns:tns="urn:attachment.tip">
  <message name="empty"/>
  <message name="imageMsg">
    <part name="image" type="xsd:hexBinary"/>
  </message>
  <message name="octetMsg">
    <part name="octet" type="xsd:hexBinary"/>
  </message>

  <portType name="AttachmentTip">
    <operation name="sendImage">
      <input message="tns:imageMsg"/>
      <output message="tns:empty"/>
    </operation>
    <operation name="sendOctet">
      <input message="tns:octetMsg"/>
      <output message="tns:empty"/>
    </operation>
  </portType>

  <binding name="AttachmentBinding" type="tns:AttachmentTip">
    <soap:binding style="rpc"
                  transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="sendImage">
      <soap:operation soapAction=""/>
      <input>
        <mime:multipartRelated>
          <mime:part>
            <soap:body use="literal"/>
          </mime:part>
          <mime:part>
            <mime:content part="image" type="image/jpeg"/>
          </mime:part>
        </mime:multipartRelated>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
    <operation name="sendOctet">
      <soap:operation soapAction=""/>
      <input>
        <mime:multipartRelated>
          <mime:part>
            <soap:body use="literal"/>
          </mime:part>
          <mime:part>
            <mime:content part="octet" type="application/octet-stream"/>
          </mime:part>
        </mime:multipartRelated>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>

  <service name="AttachmentService">
    <port name="AttachmentTip" binding="tns:AttachmentBinding">
      <soap:address
          location="http://localhost:9080/attachment/services/AttachmentTip"/>
    </port>
  </service>

</definitions>

WS-I와 attachments


MIME 유형은 WSDL의 '인터페이스'로 정의될 수 없다. WS-I organization (참고자료)은 모든 MIME 유형을 위한 새로운 XML 유형을 도입하여 부분적이라도 이러한 단점을 보완을 시도하고 있다: wsi:swaRef. 이 글을 쓰는 당시에는 이 유형은 작업중에 있었으며 표준화된 자바 바인딩이 존재하지 않았음을 밝힌다.

우선 기억해야 할 것은 항상 바인딩에 대처하기 전까지는 어떤 MIME 정보도 없다는 것이다. 한 순간이라도 바인딩을 무시하고 WSDL의 '인터페이스'(portType과 메시지)만을 본다면 두 개의 오퍼레이션인 sendImagesendOctet를 보게 될 것이다. 이들 각각은 hexBinary 인풋을 갖고 있다. hexBinarybyte[]로 매핑한다. 단지 이 정보만을 이용하여 이 portType이 Java language Service Endpoint Interface (SEI)로 매핑되는 것을 짐직할 수 있다. 이것은 두 개의 메소드를 갖고 있는데 각각 하나의 byte[] 매개변수를 갖고있다. 이는 MIME 유형을 제외한 모든 것에 알맞은 생각이다. 하지만 MIME 유형의 경우 실제 매개변수 유형을 결정하려면 바인딩을 살펴보아야한다.

바인딩에서 오퍼레이션용 인풋이 실제로 MIME 콘텐트 유형인 image/jpegapplication/octet-stream이라는 것을 알 수 있다. hexBinary가 아니다. JAX-RPC는 이들을 java.awt.Imagejavax.activation.DataHandler에 매핑하도록 정의한다.




위로


Service Endpoint Interface

Listing 2에는 Listing 1의 WSDL에서 만들어진 Java language SEI가 포함되어 있다.


Listing 2. AttachmentTip SEI
package tip.attachment;

import java.awt.Image;
import java.rmi.Remote;
import java.rmi.RemoteException;
import javax.activation.DataHandler;

public interface AttachmentTip extends Remote {
    public void sendImage(Image image) throws RemoteException;
    public void sendOctet(DataHandler octet) throws RemoteException;
}

WSDL의 sendImage 오퍼페이션은 java.awt.Image 매개변수를 이용하여 자바 프로그램 메소드가 된다. 매우 단순하고 깔끔하다. 표 1은 MIME 유형을 자바 유형으로 매핑한 리스트이다.

표 1 - JAX-RPC 매핑

MIME Type Java Type
image/gif, image/jpeg java.awt.Image
text/plain java.lang.String
multipart/* javax.mail.internet.MimeMultipart
text/xml, application/xml javax.xml.transform.Source



위로


클라이언트 구현

JAX-RPC 구현을 사용하여 AttachmentTip WSDL에서 모든 클라이언트 쪽 매핑을 만든다고 가정한다. 클라이언트 구현은 이 매핑에 의존할 것이고 특히 Listing 2의 AttachmentTip SEI를 의존한다.

attachments의 클라이언트 구현은 우선 Service에서 SEI의 구현을 얻는 것으로 시작한다.(Listing 3).

sendImage 메소드 호출하기

SEI 구현을 갖게 되면 attachment로 이 메소드를 호출할 수 있다. sendImage의 경우, 이 attachment는 java.awt.Image 이다. 이 뿐이다. JAX-RPC 구현은 모든 이미지가 attachment로서 보내지는 것을 알고 있고 이에 따라 SOAP 메시지를 만든다. 클라이언트 프로그래머는 attachment가 개입되었는지를 알 필요가 없다. (Listing 3).


Listing 3. AttachmentTip 클라이언트 구현과 sendImage 호출
package tip.attachment;

import java.awt.Image;
import java.awt.Toolkit;

import java.net.URL;

import java.rmi.RemoteException;

import javax.xml.namespace.QName;

import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;

public class AttachmentTipClient {

    static AttachmentTip getTip() throws Exception {
        QName serviceName = new QName(
                "urn:attachment.tip",
                "AttachmentService");
        URL wsdlLocation = new URL(
                "http://localhost:9080/attachment/services/AttachmentTip?wsdl");
        ServiceFactory factory = ServiceFactory.newInstance();
        Service service = factory.createService(wsdlLocation, serviceName);
        QName portName = new QName("", "AttachmentTip");
        return (AttachmentTip) service.getPort(
                portName,
                AttachmentTip.class);
    }

    static void sendImage(AttachmentTip tip, String fileName)
            throws RemoteException {
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Image image = toolkit.createImage(fileName);
        tip.sendImage(image);
    }

    public static void main(String[] args) {
        try {
            AttachmentTip tip = getTip();
            sendImage(tip, args[0]);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

sendOctet 메소드 호출하기

비 지정 MIME 유형을 매핑할 때 유의할 점


JAX-RPC는 표 1에 나타나지 않은 MIME 유형을 지원하는 구현을 필요로하지 않는다. 구현은 비 지정 MIME 유형을 DataHandler로 매핑하지 않을 수도 있다. 예를 들어, WebSphere 웹 서비스는 Application Server 6.0 버전이 나오기 전까지는 이 매핑을 지원하지 않는다.

JAX-RPC가 매핑을 정의한 몇 가지 MIME 유형이 있다는 것은 다행이다. (표 1 참조). For those MIME types for which there is no explicit 뚜렷한 JAX-RPC 매핑이 없는 MIME 유형의 경우 javax.activation.DataHandler 객체와 함께 남아있다. 이 클래스는 Java Activation Framework (JAF -- 참고자료)의 일부이다. 따라서 JAF에 대해 알아야한다. 그다지 어렵지 않다. DataHandler에는 javax.activation.DataSource가 포함되어 있고 인풋과 아웃풋 스트림이 포함되어 있다. 대부분의 자바 프로그래밍 유형은 이 스트림에서 매우 쉽게 변환된다. 게다가 활성화 프레임웍도 도움이 된다. attachment 데이터가 파일에 있으면 활성화 프레이웍은 javax.activation.FileDataSource 클래스를 제공하고 따라서 스트림 단계를 우회할 수 있다.(Listing 4) .


Listing 4. 완전한 AttachmentTip 클라이언트 구현
package tip.attachment;

import java.awt.Image;
import java.awt.Toolkit;

import java.net.URL;

import java.rmi.RemoteException;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;

import javax.xml.namespace.QName;

import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;

public class AttachmentTipClient {

    static AttachmentTip getTip() throws Exception {
        QName serviceName = new QName(
                "urn:attachment.tip",
                "AttachmentService");
        URL wsdlLocation = new URL(
                "http://localhost:9080/attachment/services/AttachmentTip?wsdl");
        ServiceFactory factory = ServiceFactory.newInstance();
        Service service = factory.createService(wsdlLocation, serviceName);
        QName portName = new QName("", "AttachmentTip");
        return (AttachmentTip) service.getPort(
                portName,
                AttachmentTip.class);
    }

    static void sendImage(AttachmentTip tip, String fileName)
            throws RemoteException {
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Image image = toolkit.createImage(fileName);
        tip.sendImage(image);
    }

    static void sendOctet(AttachmentTip tip, String fileName)
            throws RemoteException {
        FileDataSource fds = new FileDataSource(fileName);
        DataHandler dh = new DataHandler(fds);
        tip.sendOctet(dh);
    }

    public static void main(String[] args) {
        try {
            AttachmentTip tip = getTip();
            sendImage(tip, args[0]);
            sendOctet(tip, args[0]);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

두 개의 attachment 작동에 대한 데이터로 같은 파일을 사용했지만 어디까지나 이것은 sendOctet에 한해서였다는 것을 기억하라. 이를 고려하지 않는다면 상상에 맡기겠다. application/octet-streamFileDataSource용 디폴트 콘텐트 유형이다. 이것이 바로 내가 이를 사용한 이유이다. 파일에 데이터를 갖고 있지 않다면 application/octet-stream 말고 다른 것으로 보내야한다. DataSource의 구현을 만들어야 하지만 이는 간단한 인터페이스이기 때문에 많은 노력이 필요하지는 않다.




위로


참고자료




위로


필자소개

Russell Butek: IBM WebSphere Web services engine 개발자. IBM JAX-RPC Java Specification Request (JSR) 전문가 그룹 대표.



- 출처 : http://www.ibm.com/developerworks/kr/webservices/library/ws-tip-soapjax.html#N100EA -

'SOAP' 카테고리의 다른 글

JAVA로 SOAP 구축하기(2)  (0) 2011.04.05
JAVA로 SOAP 구축하기(1)  (0) 2011.04.05
[SOAP강좌] Java 서버 - Delphi 클라이언트  (0) 2011.04.05
기본 XML Web Services - MSDN  (0) 2011.04.05
Soap이란?  (0) 2011.04.05
Posted by 아로나