JAX-RPC 웹 서비스 설정 파일 작성

본 장에서는 JAX-RPC 웹 서비스의 표준 웹 서비스 DD 파일 작성 방법과 JAX-RPC 매핑 파일 작성 방법에 대해 설명한다.

JAX-RPC 웹 서비스 DD 파일 작성

Jakarta EE JAX-RPC 웹 서비스는 webservices.xml이라는 이름을 가진 웹 서비스 서술자를 Java 클래스 Endpoint나 EJB Endpoint를 포함하는 압축 파일(WAR나 JAR)에 포함할 것을 요구한다.

webservices.xml을 EJB Endpoint의 경우에는 EJB JAR 파일의 META-INF 디렉터리에 저장하고, 서블릿 Endpoint의 경우에는 WAR 파일의 WEB-INF 디렉터리에 위치시킨다.

다음은 FileAttachmentService라는 웹 서비스의 webservices.xml 파일이다.

JAX-RPC 웹 서비스 : <webservices.xml>
<?xml version="1.0"?>
<webservices version="1.1" xmlns="http://java.sun.com/xml/ns/j2ee">
    <webservice-description>
        <webservice-description-name>
            FileAttachmentService
        </webservice-description-name>
        <wsdl-file>
            WEB-INF/wsdl/FileAttachmentService.wsdl
        </wsdl-file>
        <jaxrpc-mapping-file>
            WEB-INF/FileAttachmentService-mapping.xml
        </jaxrpc-mapping-file>
        <port-component>
            <port-component-name>FileAttPort</port-component-name>
            <wsdl-port xmlns:ns2="urn:FileAttachmentService">
                ns2:FileTransferIFPort
            </wsdl-port>
            <service-endpoint-interface>
                filetransfer.FileTransferIF
            </service-endpoint-interface>
            <service-impl-bean>
                <servlet-link>FileAttachmentServlet</servlet-link>
            </service-impl-bean>
            <handler>
                <handler-name>ServerAttachmentHandler</handler-name>
                <handler-class>
                    filetransfer.ServerAttachmentHandler
                </handler-class>
                <init-param>
                    <param-name>directory</param-name>
                    <param-value>/temp</param-value>
                </init-param>
            </handler>
        </port-component>
    </webservice-description>
</webservices>

webservices.xml 파일의 root element는 <webservices>이고, <webservice-description>을 하나 또는 그 이상을 필수 요소로 가진다.

<webservice-description>은 동일한 WSDL을 사용하는 Java 클래스나 EJB Endpoint의 집합을 서술한다. 즉, 패키징 내의 다른 WSDL 각각의 파일 들에 대해서 <webservice-description>이 하나씩 존재해야 한다. 예를 들면 2개의 다른 Java 클래스 Endpoint가 각각 WSDL을 별도로 가지고 하나의 WAR 파일 안에 존재한다면 각각의 JSE를 서술하기 위해서 <webservice-description>은 2개가 존재해야 한다.

<webservice-description>는 Jakarta EE Endpoint를 WSDL 포트 정의, DD 구현, JAX-RPC 매핑 파일 그리고 Endpoint 인터페이스로 바인딩시켜주는 역할을 하며, 본 장에서는 이들의 관계와 필요성에 대해서 설명한다.

  • <wsdl-file>

    <wsdl-file>는 WSDL 문서의 WAR나 EJB JAR 파일 내에서의 상대적인 위치를 나타내며, webservices.xml 파일은 WSDL 파일과 같은 WAR나 JAR 파일 내에 위치해야 한다.

  • <jaxrpc-mapping-file>

    <jaxrpc-mapping-file>는 JAX-RPC 매핑 파일의 위치를 지정한다. JAX-RPC 매핑 파일은 WSDL 파일과 Jakarta EE Endpoint 간의 매핑을 정의한다. JAX-RPC 매핑 파일에 관한 더 자세한 설명은 웹 서비스의 매핑 파일 작성을 참고한다.

  • <port-component>

    <port-component>는 특정한 Java 클래스나 EJB Endpoint를 WSDL 문서 내의 특정한 port element로 매핑하는 역할을 한다. Java 클래스의 경우에 WSDL port 정의와 바인딩 정의는 웹 서비스를 호스트하기 위해 필요한 서블릿을 생성하는 데 사용된다.

    EJB Endpoint의 경우에는 port와 바인딩 정의는 EJB 컨테이너가 SOAP 메시지를 무상태 Bean 객체에 보내기 위해 마셜링하는 데 사용된다.

    • <port-component-name>

      <port-component-name>는 특정한 Java 클래스나 EJB Endpoint를 지정하기 위한 이름을 제공한다. 이 이름은 webservices.xml 파일 내에서 유일해야 한다.

    • <service-endpoint-interface>

      Java 클래스를 Back-end로 가지는 웹 서비스의 경우, SEI의 이름을 지정하는 element이다.

      EJB Endpoint 웹 서비스의 경우에도 마찬가지로 이 element에서 정의하며, 추가적으로 ejb-jar.xml의 <service-endpoint>에서도 같은 이름으로 정의해야 한다.

    • <service-impl-bean>

      <service-impl-bean>는 서비스 배치가 수행되는 시점에 어떤 서비스의 로직 구현 정의가 Jakarta EE Endpoint가 될 것인지를 정의한다. Java 클래스의 경우에는 web.xml의 서블릿 정의를 가리키고, EJB Endpoint의 경우에는 ejb-jar.xml의 session 정의를 가리킨다.

      JSE의 경우에는 <servlet-link>에 정의되며 예는 다음과 같다.

      DocLitEchoService : <webservices.xml>
      <?xml version="1.0"?>
      <webservices …>
          <webservice-description>
              <webservice-description-name>
                  DocLitEchoService
              </webservice-description-name>
              <wsdl-file>WEB-INF/wsdl/DocLitEchoService.wsdl</wsdl-file>
              <jaxrpc-mapping-file>
                  WEB-INF/DocLitEchoService-mapping.xml
              </jaxrpc-mapping-file>
              <port-component>
                  <port-component-name>EchoPort</port-component-name>
                  <wsdl-port xmlns:ns2="urn:DocLitService">
                      ns2:EchoPort
                  </wsdl-port>
                  <service-endpoint-interface>
                      jeustest.webservices.java2wsdl.doclit.Echo
                  </service-endpoint-interface>
                  <service-impl-bean>
                      <servlet-link>EchoServlet</servlet-link>
                  </service-impl-bean>
              </port-component>
          </webservice-description>
      </webservices>

      <serlvet-link>의 값은 web.xml 내의 <servlet-name>의 값과 일치해야 한다.

      DocLitEchoService : <web.xml>
      <?xml version="1.0"?>
      <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee">
          <servlet>
              <servlet-name>EchoServlet</servlet-name>
              <servlet-class>
                  jeustest.webservices.java2wsdl.doclit.EchoImpl
              </servlet-class>
              . . .
          </servlet>
      </web-app>

      위와 마찬가지로 EJB Endpoint 웹 서비스의 경우 <ejb-link>를 사용하여 정의한다.

      AddressBookService : <webservices.xml>
      <?xml version="1.0"?>
      <webservices …>
          <webservice-description>
              <webservice-description-name>
                  AddressBookService
              </webservice-description-name>
              <wsdl-file>META-INF/wsdl/AddressBookService.wsdl</wsdl-file>
              <jaxrpc-mapping-file>
                  META-INF/AddressBookService-mapping.xml
              </jaxrpc-mapping-file>
              <port-component>
                  <port-component-name>
                      AddressBookIFPort
                  </port-component-name>
                  <wsdl-port xmlns:ns2="urn:AddressBookService">
                      ns2:AddressBookIFPort
                  </wsdl-port>
                  <service-endpoint-interface>
                      address.AddressBookIF
                  </service-endpoint-interface>
                  <service-impl-bean>
                      <ejb-link>AddressEJB</ejb-link>
                  </service-impl-bean>
              </port-component>
          </webservice-description>
      </webservices>

      <ejb-link>의 값은 ejb-jar.xml 파일 내의 <ejb-name>의 값과 일치해야 한다.

      AddressBookService : <web.xml>
      <?xml version="1.0" encoding="UTF-8"?>
      <ejb-jar …>
          <display-name>AddressEJB</display-name>
          <enterprise-beans>
              <session>
                  <display-name>AddressEJB</display-name>
                  <ejb-name>AddressEJB</ejb-name>
                  <service-endpoint>
                      address.AddressBookIF</service-endpoint>
                  <ejb-class>address.AddressBookEJB</ejb-class>
                  . . .
              </session>
          </enterprise-beans>
      </ejb-jar>

      한 가지 유의해야 할 사항은 <servlet-link>나 <ejb-link>를 통해 연결될 대상들은 webservices.xml를 포함하는 압축 파일 안에 존재해야 한다는 것이다.

    • <handler>

      메시지 핸들러는 Jakarta EE Endpoint가 보내고 받는 메시지를 걸러서 가공하는 역할을 한다.

      webservices.xml 파일 안에서 이 메시지 핸들러들을 설정하고, 처리 순서를 지정할 수 있다. 메시지 핸들러에 대한 더 자세한 설명은 JAX-RPC 웹 서비스 SOAP 메시지 핸들러 생성을 참고한다.

      다음은 핸들러를 설정한 webservices.xml의 작성 예이다.

      FileAttachmentService : <webservices.xml>
      <?xml version="1.0"?>
      <webservices version="1.1" xmlns="http://java.sun.com/xml/ns/j2ee">
          <webservice-description>
              . . .
              <port-component>
                  <port-component-name>FileAttPort</port-component-name>
                  . . .
                  <handler>
                      <handler-name>ServerAttachmentHandler</handler-name>
                      <handler-class>
                          filetransfer.ServerAttachmentHandler
                      </handler-class>
                      <init-param>
                          <param-name>directory</param-name>
                          <param-value>/temp</param-value>
                      </init-param>
                  </handler>
              </port-component>
          </webservice-description>
      </webservices>

      다음은 <handler>의 하위 항목에 대한 설명이다.

      항목 설명

      <handler-name>

      정의되는 값은 webservices.xml 파일 안에서 유일한 값이 되어야 하며, 설정한 핸들러에 대한 식별자 역할을 한다.

      <handler-class>

      핸들러를 구현한 클래스를 정의한다.

      정의되는 핸들러 클래스는 javax.xml.rpc.handler.Handler 인터페이스를 직접 또는 간접적으로 구현해야 한다.

      <init-param>

      필수 사항은 아니며 메시지 핸들러의 생성 주기의 시작 단계에서 핸들러를 초기화하기 위해 전달될 파라미터를 정의한다. 런타임에 HandlerInfo.getHandlerConfig() 메소드를 실행해서 얻어지는 java.util.Map 객체로부터 파라미터들을 가져 올 수 있다.

      <soap-header>

      핸들러가 처리해야 하는 SOAP Header 블록의 큐 네임(Q Name : Qualified Name)을 정의하며, <handler>는 하나 이상의 <soap-header>를 포함할 수 있다.

      <soap-role>

      Header 블록을 처리할 때 핸들러가 정하는 역할을 정의한다.

      <soap-role> 값이 <soap-header>와 짝을 이루어서 정의될 때에만 어떤 Header 블록을 핸들러가 처리하는지 정확하게 알 수 있다.

      SOAP 메시지는 각각의 Header 블록을 처리하기 위한 역할을 명시적으로 지정할 수 있다. actor 속성이 정의되어 있으면 지정된 역할을 수행하는 노드만이 Header 블록을 처리하고, actor 속성이 정의 되지 않은 경우에는 최종적인 메시지 수신자가 header 블록을 처리한다.

웹 서비스의 매핑 파일 작성

JAX-RPC 매핑 파일은 JEUS 웹 서비스에 내장된 JAX-RPC 컴파일러가 WSDL 문서와 웹 서비스 Endpoint를 나타내는 Java 인터페이스의 관계를 이해하는 것을 도와준다. 많은 경우에 WSDL과 Java의 매핑은 매핑 파일이 없어도 큰 문제가 없지만 명시적인 정의가 필요할 때가 있으며, 그러한 필요에 의해서 JAX-RPC 매핑 파일이 도입되었다.

JAX-RPC 매핑 파일은 Jakarta EE 웹 서비스 Endpoint나 Jakarta EE 웹 서비스 클라이언트를 사용할 때마다 필요하며, WSDL 문서와 JAX-RPC 매핑 파일은 1대 1로 대응한다. 즉, 각각의 WSDL 파일에는 하나씩의 JAX-RPC 매핑 파일이 존재한다.

JAX-RPC 매핑 파일 내용

JAX-RPC 매핑 파일은 다음과 같은 관계에 있는 요소들의 매핑을 정의한다.

  • XML 복합 타입(Complex Type)과 Java Bean

  • Fault 메시지와 예외 클래스

  • WSDL의 portType 정의와 SEI(Service Endpoint Interface)

  • WSDL의 서비스 정의와 서비스 인터페이스

JAX-RPC 매핑 파일에 정의되지 않은 것들은 WSDL과 XML의 Java로의 표준 매핑 법칙을 따라서 매핑된다. 그리고 매핑 파일에서 정의 되는 것들은 항상 표준 매핑 법칙에 우선한다.

JAX-RPC 매핑 파일 작성

매핑 파일은 상당히 내용이 복잡해 보이고, 크기에 있어서도 단일 설정 파일 중에 큰 편이다.

전체적인 설정 파일의 구성은 다음과 같다.

JAX-RPC 매핑 파일의 구조
<java-wsdl-mapping>
    <package-mapping/>
    <java-xml-type-mapping/>
    <exception-mapping/>
    <service-interface-mapping/>
    <service-endpoint-interface-mapping>
        <service-endpoint-method-mapping/>
        <service-endpoint-method-mapping/>
        . . .
    </service-endpoint-interface-mapping>
    <service-interface-mapping/>
    <service-endpoint-interface-mapping>
        <service-endpoint-method-mapping/>
        <service-endpoint-method-mapping/>
        . . .
    </service-endpoint-interface-mapping>
</java-wsdl-mapping>
  • <java-wsdl-mapping>

    JAX-RPC 매핑 파일의 최상위 element이며, 다른 매핑 element들을 포함하고 있다.

  • <package-mapping>

    JAX-RPC 컴파일러가 WSDL에 정의된 여러 가지 타입에 대해 Java 클래스와 인터페이스 정의를 생성하려고 할 경우 사용된하는 항목으로 반드시 설정되어야 한다.

    <package-type>의 값은 Java 패키지의 이름이며, <namespaceURI>의 값은 지정된 Java 패키지로 매핑되어야 하는 XML 이름 공간이다.

    <java-wsdl-mapping version="1.1"
        xmlns="http://java.sun.com/xml/ns/j2ee">
        <package-mapping>
            <package-type>address</package-type>
            <namespaceURI>urn:AddressBookService</namespaceURI>
        </package-mapping>
        . . .
    </java-wsdl-mapping>
  • <java-xml-type-mapping>

    XML Schema 복합 타입(Complex Type)이나 단순 타입(Simple Type)을 사용할 때 필요하며, XML Schema와 Java 타입 간의 관계를 정의한다. XML Schema에 정의된 built-in 타입이 Java로 표준적인 매핑이 된다면 이 element를 사용하지 않아도 된다.

    <java-wsdl-mapping version="1.1"
        xmlns="http://java.sun.com/xml/ns/j2ee">
        . . .
        <java-xml-type-mapping>
            <java-type>address.Address</java-type>
            <ns1:root-type-qname
                xmlns:ns1=”http://java.sun.com/xml/ns/j2ee”
                xmlns="urn:AddressBookService">
                Address
            </ns1:root-type-qname>
            <qname-scope>complexType</qname-scope>
            <variable-mapping>
                <java-variable-name>addr</java-variable-name>
                <xml-element-name>addr</xml-element-name>
            </variable-mapping>
            <variable-mapping>
                <java-variable-name>street</java-variable-name>
                <xml-element-name>street</xml-element-name>
            </variable-mapping>
            <variable-mapping>
                <java-variable-name>zipcode</java-variable-name>
                <xml-element-name>zipcode</xml-element-name>
            </variable-mapping>
        </java-xml-type-mapping>
        . . .
    </java-wsdl-mapping>
  • <exception-mapping>

    WSDL 결함(fault) 메시지를 Java 예외 클래스로 매핑한다.

    <java-xml-mapping>
        . . .
        <exception-mapping>
            <exception-type>CLASS_NAME</exception-type>
            <wsdl-message>WSDL_MESSAGE_NAME</wsdl-message>
        </exception-mapping>
        . . .
    </java-xml-mapping>
  • <service-interface-mapping>

    WSDL의 서비스 정의를 JAX-RPC 서비스 인터페이스 타입으로 매핑한다.

    <service-interface>는 WSDL의 서비스 정의를 나타내는 Java 인터페이스의 클래스 이름을 정의하고, 서비스 인터페이스의 패키지 이름은 <package-mapping>에 정의된 패키지 이름과 일치해야 한다.

    <port-mapping>는 서비스 인터페이스의 getPortName() 메소드의 포트 이름을 WSDL의 <port>와 대응하게 정의한다.

    <java-xml-mapping…>
        . . .
        <service-interface-mapping>
            <service-interface>
                address.AddressBookService
            </service-interface>
            <ns3:wsdl-service-name
                xmlns:ns3="http://java.sun.com/xml/ns/j2ee"
                xmlns="urn:AddressBookService">
                AddressBookService
            </ns3:wsdl-service-name>
            <port-mapping>
                <port-name>AddressBookIFPort</port-name>
                <java-port-name>AddressBookIFPort</java-port-name>
            </port-mapping>
        </service-interface-mapping>
        . . .
    </java-xml-mapping>

    위와 같이 정의될 경우 생성되는 Java 서비스 인터페이스 정의는 다음과 같다.

    Java 서비스 인터페이스 정의 : <AddressBookService.java>
    package address;
    
    public interface AddressBookService extends javax.xml.rpc.Service {
    public java.lang.String getAddressBookIFPortAddress();
    public address.AddressBookIF getAddressBookIFPort()
        throws javax.xml.rpc.ServiceException;
    public address.AddressBookIF getAddressBookIFPort(java.net.URL portAddress)
        throws javax.xml.rpc.ServiceException;
    }
  • <service-endpoint-interface-mapping>

    SEI를 WSDL의 portType과 바인딩 정의로 매핑한다. 이 element는 JAX-RPC 컴파일러가 적절한 Endpoint Stub과 Endpoint 인터페이스를 생성할 때 필요한 정보를 제공한다. 또한 WSDL의 operation과 message part 정의가 어떻게 Java Endpoint 메소드의 정의로 매핑될 것인지에 대한 상세 정보를 제공한다.

    다음은 AddressBookService의 매핑 파일에 정의된 예이다.

    <java-wsdl-mapping…>
        . . .
        <service-endpoint-interface-mapping>
            <service-endpoint-interface>
                address.AddressBookIF
            </service-endpoint-interface>
            <ns4:wsdl-port-type
                xmlns:ns4="http://java.sun.com/xml/ns/j2ee"
                xmlns="urn:AddressBookService">
                AddressBookIF
            </ns4:wsdl-port-type>
            <ns5:wsdl-binding
                xmlns:ns5="http://java.sun.com/xml/ns/j2ee"
                xmlns="urn:AddressBookService">
                AddressBookIFSoapBinding
            </ns5:wsdl-binding>
            <service-endpoint-method-mapping>
                <java-method-name>add</java-method-name>
                <wsdl-operation>add</wsdl-operation>
                <wrapped-element/>
                <method-param-parts-mapping>
                    <param-position>0</param-position>
                    <param-type>address.PersonInfo</param-type>
                    <wsdl-message-mapping>
                        <ns6:wsdl-message
                            xmlns:ns6="http://java.sun.com/xml/ns/j2ee"
                            xmlns="urn:AddressBookService">
                            addRequest
                        </ns6:wsdl-message>
                        <wsdl-message-part-name>
                            parameters
                        </wsdl-message-part-name>
                        <parameter-mode>IN</parameter-mode>
                    </wsdl-message-mapping>
                </method-param-parts-mapping>
                <wsdl-return-value-mapping>
                    <method-return-value>
                        address.PersonInfo[]
                    </method-return-value>
                    <ns7:wsdl-message
                        xmlns:ns7=”http://java.sun.com/xml/ns/j2ee“
                        xmlns="urn:AddressBookService">
                        addResponse
                    </ns7:wsdl-message>
                    <wsdl-message-part-name>
                        parameters
                    </wsdl-message-part-name>
                </wsdl-return-value-mapping>
            </service-endpoint-method-mapping>
            . . .
        </service-endpoint-interface-mapping>
        . . .
    </java-wsdl-mapping>