달력

102018  이전 다음

  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  •  
  •  
  •  
 Enterprise Java Technologies Tech Tip에 오신 여러분을 환영합니다
Enterprise Java Technologies
테크팁
2005년 7월 26일자
 
Java 2 Platform, Enterprise Edition (J2EE)에 기반한 enterprise Java technologies 와 APIs의 사용에 관한 최신 정보를 얻어 가시기 바랍니다.

이번 호에서는,

» JAX-RPC를 사용하여 간단한 웹서비스 구현하기
» JAXB로 RELAX NG 사용하기

를 다루게 됩니다.


이 글에서는 Java 2 Java 2, Enterprise Edition, v 1.4 를 사용합니다.
다운로드

저자 Robert Eckstein

JAX-RPC를 사용하여 간단한 웹서비스 구현하기
 

이미 웹 서비스와 자바 기술 대해 작성된 문서들이 많이 있다. 이 중 심도깊은 내용을 다루는 문서도 있었지만, 사람들은 여전히 자바 기술을 사용하여 웹 서비스를 생성하도록 도와주는 간결하고 직접적인 문서를 원한다. 이번 테크팁은 이를 위한 것이다. 간단한 웹 서비스를 구축하는 과정과 XML기반의 RPC(JAX-RPC)를 위해 Java API를 사용하여 서비스에 접근하는 클라이언트를 구축하는 과정에 대해 단계적으로 다룬다. 이 단계는 J2EE 1.4 tutorial에 있는 Chapter 8: Building Web Services with JAX-RPC를 기반으로 한다. 이들은 웹 서비스와 웹서비스의 클라이언트를 생성하는 기본적인 단계들이다.
  1. 서비스를 위한 위한 SEI(service endpoing interface)와 SEI의 실행 클래스 코드를 작성한다.
  2. SEI와 실행클래스를 컴파일한다.
  3. WSDL과 매핑 파일들을 생성한다.
  4. 서비스를 패키지화하고 배치한다. 특별한 동일 클래스들(클라이언트와의 커뮤니케이션에 사용된)은 서비스가 배치되는 동안에 응용서버에 의해 생성된다.
  5. 클라이언트 클래스 소스를 작성한다.
  6. Stub 파일들을 생성한다.
  7. 클라이언트 클래스들을 컴파일한다.
  8. 클라이언트를 패키지화한다.
SEI와 실행 클래스 코드 작성

JAX-RPC 웹 서비스를 개발하는 데 있어서 시작 포인트는 SEI(service endpoint interface)이다. 이것은 단순히 클라이언트가 그 서비스에 호출할 수 있는 방법을 선언하는 자바 인터페이스이다.

JAX-RPC를 통하여 클라이언트들에게 사용 가능한 웹서비스를 만들어 주기 위해 2개의 자바 클래스를 생성할 필요가 있다. 하나는 SEI를 정의하는 것, 그리고 다른 하나는 SEI 구현하는 것이다. 이 두 클래스들의 소스 코드는 이번 테크팁의 샘플 코드인 ttmay2005-ws.jar를 사용한다. 다음은 웹 서비스를 위한 SEI를 정의하는 클래스이다.
   package helloservice;   import java.rmi.Remote;   import java.rmi.RemoteException;   public interface HelloIF extends Remote {       public String sayHello(String s) throws RemoteException;   } 
SEI는 다음의 규칙을 따라야 한다.
  • java.rmi.Remote 인터페이스를 확장한다.
  • public / final / static과 같은 일정한 선언을 가져서는 안된다.
  • 메소드들은 java.rmi.RemoteException이나 그것의 하위 클래스들 중의 하나를 throw해야한다. (메소드들은 또한 service-specific exception들을 throw할 수 있다.)
  • 메소드 매개변수들과 리턴 타입들은 반드시 JAX-RPC타입들에 의해 지원되어야한다. (JAX-RPC 타입 목록를 위해)
다음은 실행 클래스의 코드이다. 이 클래스는 문자열 매개변수를 수용하며, 그 매개변수를 약간 수정된 문자열을 리턴하기 위해 사용한다.
   package helloservice;   public class HelloImpl implements HelloIF {       public String message = "Hello there, ";       public String sayHello(String s) {           return message + s;       }   } 
SEI 클래스와 실행 클래스 컴파일하기

SEI 클래스와 실행 클래스를 생성한 후에는 그들을 컴파일해야한다. 이를 위한 쉬운 방법은 ant 설정 도구(http://ant.apache.org/)를 사용하는 것이다. 웹 서비스를 위한 구축 파일(build.xml)은 이 팁의 샘플 코드에 있다. 샘플을 위한 구축 파일과 같은 디렉토리에서 ant를 실행하여 구축할 수 있다. 현재의 디렉토리를 그 샘플 코드를 설치한 ws/helloservice 밑으로 변경한다. 그리고 다음의 명령을 입력한다.
   ant 
빌드하는데 가장 먼저 이뤄지는 것은 웹서비스를 위한 디렉토리를 생성하는 것이다. 그런 다음 파일들을 컴파일한다. 컴파일 단계는 다음의 javac 명령어들을 실행하는 것과 동일하다.
   src\helloservice>javac -d ..\..\build -cp ..\   ..\build HelloIF.java      src\helloservice>javac -d ..\..\build -cp ..\..\   build HelloImpl.java
(참고: 각각의 명령은 이 문서상에서는 두 줄로 나타내지만 실제로는 한 라인에 입력해야 한다.)

WSDL과 매핑 파일들의 생성

WSDL 파일은 웹서비스를 표현한다. 클라이언트에게 그 서비스에 대한 요구를 하는 데 있어서 어떤 포맷을 이용해야 하는 지를 말해주는 것이 바로 WSDL 파일이다. Wscompile는 JAX-RPC SEI와 WSDL 파일 사이에 매핑을 제공하는 J2EE 1.4 SDK에 패키지된 툴이다. SEI로부터 WSDL 파일을 생성시키거나 WSDL 파일로부터 SEI를 생성시키기 위해 wscompile툴을 구동할 수 있다. 이 만약 이 팁을 위한 구조를 설정하기 위해 ant 명령어를 사용하게 되면, 그것은 wscompile 도구를 구동하여 웹서비스를 위한 WSDL 파일을 생성한다. 그 구조는 또한 mapping.xml 파일을 생성하는데, 매핑 파일은 웹서비스의 WSDL 정의를 자바 인터페이스에 매핑한다.

만약 ant로 빌드하지 않는다면 디렉토리의 안에 다음의 명령을 구동하여 mapping.xml과 WSDL 파일을 새로 만들 수 있다.
   wscompile -define -mapping build\mapping.xml -d build    -nd build -classpath build config-interface.xml
(참고: 이 문서상에서는 두 줄로 나타내지만 실제로는 한 라인에 입력해야 한다.)

wscompile 명령에 있는 플래그는 각각 다음과 같은 의미이다.
-classpath. build 디렉토리에서 SEI를 읽도록 wscompile 툴을 지시한다. -define. WSDL을 생성하도록 wscompile을 지시한다.-mapping. 매핑 파일을 생성하도록 wscompile를 지시한다.  -d. Build 하위 디렉토리에 클래스 파일을 쓰도록 wscompile를 지시한다. -nd. Build 하위 디렉토리에 WSDL 파일을 쓰도록 wscompile를 지시한다. 
wscompile 툴을 구동할 때, 또한 SEI에 대한 정보를 명시하는 wscompile 구성 파일을 제공해야 한다. 구성 파일은 이 테크팁의 샘플 코드로 제공되는데, 그 구성파일은 config-interface.xml이라 하며 다음의 내용을 포함하고 있다.
   <?xml version="1.0" encoding="UTF-8"?>   <configuration      xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">     <service          name="MyHelloService"          targetNamespace="urn:Foo"          typeNamespace="urn:Foo"          packageName="helloservice">         <interface name="helloservice.HelloIF/>     </service>   </configuration>
이 구성 파일은 wscompile에게 MyHelloService.wsdl라는 이름의 WSDL 파일을 생성하도록 명령한다. 그 파일은 또한 다음의 정보와 명령을 제공된다.
  • 서비스명은 MyHelloService이다.
  • SEI는 helloservice.HelloIF이다.
  • helloservice 패키지에 그 서비스 클래스를 놓는다.
  • WSDL 대상과 타입 네임 스페이스는 urn:Foo이다. 네임 스페이스로 무엇을 이용할 것인지는 사용자가 선택할 수 있다. 네임 스페이스의 역할은 자바 패키지 이름의 사용과 비슷하다.즉, 그렇지 않으면 충돌할 수 있는 이름을 식별하는 것이다. 예를 들어, 어떤 회사는 회사의 모든 자바 코드가 com.wombat.* 패키지 안에 있도록 결정할 수 있다. 마찬가지로, 또한 네임스페이스 http://wombat.com을 사용하기로 결정할 수도 있다.
서비스의 패키지와 배치

그 다음으로 서비스를 패키지화하고 배치시킬 필요가 있다. 이를 위해서는 배치 기술어에 서비스에 대한 세부사항을 명시할 필요가 있다. 웹 서비스는 서블릿이나 비상태유지 세션빈(관련된 서비스를 하는데 상태정보를 유지하지 않은 bean;stateless session bean)으로써 구현될 수 있다. 웹 서비스는 서블릿들이 Web Archive (WAR) 파일에 패키지됨에 따라 구현된다. WAR 파일에 있는 WEB-INF 디렉토리는 웹 어플리케이션(web.xml, sun-web.xml)과 특별한 웹 서비스 배치 기술어 파일(webservices.xml)을 위한 두 개의 표준 배치 기술어 파일을 포함한다. 웹 서비스는 Bean이 EJB-JAR 파일에 비상태유지 세션 빈이 패키지됨에 따라 구현되며, 배치 기술어 파일은 META-INF 디렉토리에 있다.

이번 테크팁을 빌드를 하기 위해 ant 명령을 사용한다면, 사용자를 위해 서비스를 패키지한다. 특히 이 빌드는,
  • WAR 내용을 모으기 위해 임시 디렉토리를 생성한다.
  • 임시 디렉토리에서 두 하위디렉토리(WEB-INF와 build)를 생성한다.
  • WEB-IN디렉토리에서 두 하위 디렉토리(클래스들과 wsdl)를 생성한다.
  • HelloIF.class와 HelloImpl.class를 WEB-INF/classes 디렉토리로 복사한다.
  • MyHelloService.wsdl을 WEB-INF/wsdl 디렉토리로 복사한다.
  • mapping.xml 파일을 그 구축 디렉토리로 복사한다.
  • 임시 디렉토리로부터 WAR 파일을 새로 만든다. WAR파일은 WEB-INF 디렉토리에서 web.xmlsun-web.xml 배치 기술어, webservices.xml 파일을 둔다.
다른 대안으로, J2EE 1.4 Application Server의 배치 툴 유틸리티을 사용하는 웹서비스를 패키지 할 수 있다.

WAR 파일이 새로 만들어진 후에는, 이를 deploytool이나 다른 어플리케이션을 사용하여 배치시킬 수 있다. 배치가 성공적이면, 웹브라우저에 URL http://localhost:8080/ttmay2005/hello?WSDL를 입력하여 배치된 서비스의 WSDL 파일을 보게될 것이다.. (Application Server가 port 8080에 배치되었다고 가정). 그 다음 세션(“데스크탑 클라이언트”)에 있는 wscompile 명령이 성공하기 위해 서버로부터 이 XML파일을 다운로드 하는 것에 의존하기 때문에 이를 실행할 수 있음을 주의하기 바란다.

클라이언트 클래스 생성

그 웹서비스를 배치시킨 후에는, 클라이언트 프로그램으로부터 웹서비스에 접근할 수 있다. HelloClient는 이 테크팁의 샘플 코드로 제공된 데스크탑 클라이언트 프로그램이다. 이는 MyHelloService의 sayHello 메소드를 호출한다. 원격 서비스를 위한 프록시(proxy) 를 사용하는 지역 객체인 stub을 통해 이 호출을 하게 된다. stub이 개발 시간(실행시간과 대조적)에 생성되기 때문에, 그것은 보통 정적stub(static stub)이라고 불린다. 다음은HelloClient (정적 stub을 위한 코드)에 대한 원시 코드이다.

   package staticstub;   import javax.xml.rpc.*;   public class HelloClient {       private static String endpointAddress =           "http://localhost:8080/ttmay2005/hello";       public static void main(String[] args) {           System.out.println("Endpoint address = "             + endpointAddress);           try {              Stub stub = createProxy();              stub._setProperty                (Stub.ENDPOINT_ADDRESS_PROPERTY,                 endpointAddress);               HelloIF hello = (HelloIF)stub;              System.out.println(hello.sayHello("Duke!"));           } catch (Exception ex) {              ex.printStackTrace();           }       }           private static Stub createProxy() {           return                (Stub) (new MyHelloService_Impl().                   getHelloIFPort());       }   }  
Stub 파일들 생성

이전에 언급한 대로, 클라이언트는 서비스에 접근하기 위해 stub로 불리는 로컬 프록시를 사용한다. 따라서 그 서비스에 접근하는 클라이언트를 사용할 수 있기 전에, 그 stub 파일들을 생성해야한다. 이를 실행하는 방법은 wscompile와 같은 툴을 사용하는 것이다. 좀전에 한 것처럼, wscompile툴을 호출하기 위해 ant 명령어를 구동할 수 있다. 현재 디렉토리를 그 샘플 코드를 설치한 곳 밑에 있는 ttMay2005/helloclient 디렉토리로 바꾸기 바란다. 그리고 나서, 다음의 명령을 입력한다.
   ant stubs
Stub 태스크는 다음의 독립 변수를 가진 wscompile 툴을 구동한다.
   wscompile -gen:client -d build -classpath build     config-wsdl.xml 
이 독립 변수는 wscompile이 이전에 생성된 MyHelloService.wsdl 파일을 읽도록 한다. 이 툴은 또한 WSDL 파일과 명령어 줄(command-line) 플래그에 대한 정보에 기반하는 파일들을 생성한다. 특히, “-gen” 클라이언트 플래그는 serializers와 value type과 같은 런타임 파일과 stub들을 생성하도록 wscompile에 지시한다. "-d" 플래그는 툴이 생성된 결과물을 build/staticstub 하위 디렉토리에 쓰도록 명령한다.

wscompile 툴을 구동할 때, 목표 WSDL 파일의 위치를 명시하는 구성파일도 제공해야한다. 구성파일(config-interface.xml)은 이 팁의 샘플 코드로 나와있다. 다음은 config-interface.xml 파일의 내용이다.
   <configuration      xmlns="http//java.sun.com/xml/ns/jax-rpc/ri/config">     <wsdl location="http://localhost:8080/ttmay2005/hello?WSDL"      packageName="staticstub"/>   </configuration>
packageName 속성은 그 생성된 stub에 대해 자바 패키지를 명시한다. WSDL 파일의 위치가 URL으로서 명시된다는 것을 알아두기 바란다. 이는 웹서비스에서 WSDL 파일을 요청하는 wscompile 명령을 야기한다. 이 때문에, 웹서비스는 반드시 올바르게 배치되고 성공을 위한 명령을 위해 구동되고 있어야한다. 웹서비스가 실행되지 않고 있거나 서비스가 배치된 포트가 구성 파일의 포트와 다르다면, 그 명령은 실패할 것이다.

클라이언트 클래스 컴파일하기

다음 단계는 클라이언트 클래스를 컴파일하는 것이다. 이번 테크팁의 예제를 컴파일하려면, 다음 명령을 입력한다.
   ant compile
ant 컴파일 태스크는 src/HelloClient.java를 컴파일하고, 그 구축 하위 디렉토리에 클래스 파일을 작성한다. 다음의 명령을 구동하는 것과 동일하다.
   javac -sourcepath src -d build staticstub.HelloClient.java
클라이언트 패키지화

클라이언트를 생성하는 과거 단계는 이전에 생성된 파일들을 jar 파일 안으로 패키지하는 것이다. 다음 명령을 입력한다.
   ant jar
ant jar 태스크는 ttmay2005.jar이란 이름의 파일을 생성한다. HelloClient.class를 제외하고, ttmay2005jar 안의 모든 파일들은 wscompile에 의해 생성되었음을 알아두기 바란다. 또한, wscompile가 그것이 응용 서버로부터 다운로드 한 MyHelloService.wsdl 화일로부터 읽은 정보에 기반한 HelloIF.class를 생성시켰다는 것도 알아두자.

클라이언트 구동

클라이언트를 실행하기 전에 해당하는 JAR 라이브러리(Java Web Services Developer Pack 1.5 download 참고)클래스 패스를 설정하기 바란다.
   jaxrpc/lib/jaxrpc-api.jar   jaxrpc/lib/jaxrpc-spi.jar   jaxrpc/lib/jaxrpc-impl.jar   jwsdp-shared/lib/activation.jar   jwsdp-shared/lib/mail.jar   jwsdp-shared/lib/jax-qname.jar   saaj/lib/saaj-api.jar   saaj/lib/saaj-impl.jar   jaxp/lib/endorsed/dom.jar   jaxp/lib/endorsed/sax.jar   jaxp/lib/endorsed/xalan.jar   jaxp/lib/endorsed/xercesImpl.jar
다른 방법으로는, 다음과 같이 클라이언트를 실행 시킬 때 클래스패스를 추가 시킬 수도 있다.
   ant run
이 경우 커맨드 라인 창에 다음과 같은 내용이 보인다.
   [java] Endpoint address = http://localhost:8080/ttmay2005/hello   [java] Hello Duke!
추가 정보

JAX-RPC에 대한 추가 정보는, J2EE 1.4 Tutorial의 Chapter 8: Building Web Services with JAX-RPC를 참고하기 바란다.

Back to Top

JAXB로 RELAX NG 사용하기
 

Java WSDP(Java Web Services Developer Pack) 1.5의 JAXB 라이브러리는 기본적으로 RELAX NG을 포함하고 있다. RELAX NG는 XML 문서에 대한 용어를 제공하며, 이는 DTD나 XML 스키마를 대안으로 널리 알려져있다. RELAX NG 스펙은 OASIS(The Organization for the Advancement of Structured Information Standards) 내의 RELAX NG 기술 위원회에 의해 개발되어왔다. 현재 JAXB에서의 RELAX NG 지원은 실험적일 뿐이며 공식적으로 지원되지 않는다. 그러나 만약 RELAX NG를 이용하기 원한다면, 좀 더 실험적으로 JAXB와 함께 사용할 수 있다. 이번 테크팁에서는 JAXB에서 RELAX NG를 사용하는 방법에 대해 설명한다.

RELAX NG를 사용하여 속도 높이기

만약 과거에 DTD를 사용했다면, 이 문서들의 syntax가 종종 상당히 빠르게 암호화(cryptic)한다는 것을 알 것이다. RELAX NG 표준은 XML 문서 유효화를 위해 DTD를 사용하는 것에 대해 XML 기반의 대안을 제공한다. RELAX NG는 정의되지 않은 XML 스키마대신 좀 더 더 기능적인 것을 제공하도록 노력한다. 예를 들어, 다음은 DTD이다.
   <!DOCTYPE addressBook [   <!ELEMENT addressBook (card*)>   <!ELEMENT card (name, email)>   <!ELEMENT name (#PCDATA)>   <!ELEMENT email (#PCDATA)>   ]>
다음은 이와 동등한 RELAX NG이다.
   <element name="addressBook"      xmlns="http://relaxng.org/ns/structure/1.0">     <zeroOrMore>       <element name="card">         <element name="name">           <text/>         </element>         <element name="email">           <text/>         </element>       </element>     </zeroOrMore>   </element>
두 문법 중 RELAX NG syntax가 사용하기 더 쉽다고 말할 수 있다.. 이제 sysbtax를 구축해야하는 다음의 XML 문서를 보자.
   <?xml version="1.0" encoding="UTF-8"?>   <book isbn="0345391802">    <title>  The Hitchhiker's Guide to the Galaxy    </title>    <author>Douglas Adams</author>    <character>     <name>Arthur Dent</name>     <friend-of>Ford Prefect</friend-of>    </character>    <character>     <name>Ford Prefect</name>    </character>   </book>
이 XML 문서에서, 책(book)은 명백히 ISBN 숫자, 제목(title), 저자(author), 하나 이상의 문자(character)를 포함하고 있음을 알 수 있다. 그러나 각 문자는 하나 이상의 개별적인 특성을 나타낼 수도 있다. 즉, 각 문서는 그 문서와 연계된 문법을 갖는다. 이는 다음과 같다.
  A Book must have an ISBN number, a title, an author, and it   must have one or more characters.
다음은 XML 문서를 위한 어휘들을 제공하는 RELAX NG 문법에 대한 예제이다.
   <?xml version="1.0" encoding="UTF-8"?>   <grammar xmlns="http://relaxng.org/ns/structure/1.0">     <start>       <element name="book">         <attribute name="isbn">           <text/>         </attribute>       <element name="title">         <text/>       </element>       <element name="author">         <text/>       </element>       <zeroOrMore>         <element name="character">           <element name="name">             <text/>           </element>           <optional>             <element name="friend-of">               <text/>             </element>           </optional>         </element>       </zeroOrMore>     </start>   </grammar>
이는 다음 사항을 나타내고 있다.
  • 문법은 반드시 book이라는 이름의 요소로 구성된다.
  • <book> 요소는 반드시 이와 연계된 <book isbn="0345391802">같은 ISBN 속성을 갖는다.
  • book 요소에는 반드시 <title><author> 요소가 있어야한다.
  • <title><author> 요소 안과 ISBN 속성 내에는 일반 텍스트가 있어야한다.
  • There can be zero or more <character> elements.
  • 0개 이상의 <character>요소가 있을 수 있다.
  • <character>요소는 <name>요소와, 선택적으로 <friend-of>, <since>, <qualification>요소를 가진다. 이 네 요소는 모두 텍스트로만 구성된다.
만약 XML에 대해 알고 있다면 RELAX NG은 쉬울 것이다. 사실, RELAX NG를 XML에서 재형성된 DTD로 생각해도 된다.

RELAX NG 명세

RELAX NG 문법에 대해 좀 더 자세하게 알아보자.

<start> 요소는 RELAX NG 문법이 시작되는 곳을 명시한다. 이름 속성을 가지는 곳인 <define> 요소가 하나 이상 있을 수 있다. 이 정의된 요소들은 같은 이름을 명시하는 <ref> 요소로 참조될 수 있다. 따라서, 예제는 다음과 같다.
   <grammar>     <start>       <ref name="AddressBook"/>     </start>     <define name="AddressBook">       <element name="addressBook">         <zeroOrMore>           <ref name="Card"/>         </zeroOrMore>       </element>     </define>     <define name="Card">       <element name="card">         <ref name="Name"/>         <ref name="Email"/>       </element>     </define>     <define name="Name">       <element name="name">         <text/>       </element>     </define>     <define name="Email">       <element name="email">         <text/>       </element>     </define>   </grammar>
RELAX NG는 DTDs와 다른 많은 언어들과 비슷한 숫자 패턴 정량화(numerical pattern quantification)를 사용한다. 이는 다음과 같다.

<oneOrMore>. 적어도 하나 이상으로 구성된다.

<zeroOrMore>. 하나 이상으로 구성되거나 생략될 수 있다.

<optional>. 하나의 인스턴스로 구성되거나 생략될 수 있다.

In addition, if you want to specify a sequence of patterns at the same level, there are three different elements that you can use: <choice>, <group>, or <interleave>. 이에 덧붙여, 같은 레벨에서 패턴의 시퀀스를 명시하기 원한다면 사용할 수 있는 세 개의 다른 요소, <choice>, <group>, <interleave>가 있다.

<choice>.는 하나를 가리키며, 내부의 여러 개의 요소 중 하나만이 명시될 수 있다. 예를 들면,
     <choice>       <element name='femaleName'>           <text/>       </element>       <element name='maleName'>           <text/>       </element>   </choice>
<group>.은 내부의 요소들을 그룹화한다. 전체 그룹은 외부 수식어로 작용할 수 있다. 예를 들면,
      <oneOrMore>        <group>            <element name='areaCode'>                <text/>            </element>            <element name='phoneNumber'>                <text/>            </element>        </group>   </oneOrMore>
<interleave>. 그 안에 지정된 다른 시맨틱을 준수하는 한, 차일드(child) 요소를 다른 명령에도 나타날 수 있게 한다.

<list> 요소는 토큰(token)의 시퀀스가 반드시 매치되는 패턴을 포함한다. 예를 들어 공백에 의해 나누어지는 두 개의 부동소수점 숫자를 포함하는 벡터(vector)를 갖고자 한다면, 다음과 같이 리스트를 사용할 수 있다.
   <element name="vector">     <list>       <data type="float"/>       <data type="float"/>     </list>   </element>
merging inline pattern등 다른 흥미로운 RELAX NG 문법 부분은 RELAX NG tutorial에서 좀 더 자세히 알아보기 바란다.

Birthday 예제 다시 해보기

다음 예제는 RELAX NG를 이용한 XML Binding(JAXB)를 위한 Java API를 사용하여 설명하고 있다. 이 예제의 소스 코드는 이번 테크팁의 샘플 코드인 ttmay2005-rng.jar에서 제공하고 있다. 여기에서는 지난 2005년 2월 JAXB 테크팁에서 XML 스키마를 사용한 것을 RELAX NG로 변경하였다.

다음은 예제에서 사용된 XML 파일(birthdate.xml)이다.
<?xml version="1.0"?><birthdate>    <birthdayMonth>January</birthdayMonth>    <birthdayDay>21</birthdayDay>    <birthdayYear>1983</birthdayYear></birthdate>
다음은 XML 파일을 위한 규칙을 명시하는 RELAX NG 문법이다 . 문법은 birthdate.rng 파일에 있다. 이 파일은 우선 원시 RELAX NG 형식으로 나타나고, JAXB 요소는 없다. 따라서 위의 XML 파일이 어떻게 유효화되는지 알 수 있다.
<?xml version="1.0"?><grammar xmlns="http://relaxng.org/ns/structure/1.0"         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">           <start>     <element name="birthdate">        <element name="birthdayMonth">            <data type="string"/>         </element>                    <element name="birthdayDay">            <data type="integer"/>         </element>                   <element name="birthdayYear">            <data type="integer"/>          </element>     </element>  </start> </grammar>
이 버전은 JAXB 바인딩을 추가하여 RELAX NG 문법 내의 각각의 요소가 “xjc” 툴이 적절한 소스 코드를 생성하면 어떻게 자바 오브젝트에 바인딩되는지를 가리킨다.
<?xml version="1.0"?><grammar xmlns="http://relaxng.org/ns/structure/1.0"         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"         xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"         xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"         jaxb:extensionBindingPrefixes="xjc"         jaxb:version="1.0">    <jaxb:schemaBindings>    <jaxb:package name="birthdate"/>  </jaxb:schemaBindings>    <start>     <element name="birthdate">        <jaxb:class name="Birthdate" />                       <element name="birthdayMonth">                <jaxb:property name="Month" />                <data type="string">                    <jaxb:javaType name="java.lang.String"                     parseMethod="new" printMethod="toString" />                  </data>            </element>                        <element name="birthdayDay">                <jaxb:property name="Day" />                <data type="integer">                    <jaxb:javaType name="java.lang.Integer"                     parseMethod="new" printMethod="toString" />                  </data>            </element>                       <element name="birthdayYear">                <jaxb:property name="Year" />                <data type="integer">                    <jaxb:javaType name="java.lang.Integer"                     parseMethod="new" printMethod="toString" />                  </data>            </element>     </element>  </start> </grammar>
이 버전은 먼저<jaxb:schemaBindings> 내의 <jaxb:package> 요소를 이용하여 정의된 모든 클래스가 "birthdate" 패키지에 있도록 명시한다. 덧붙여서,는 "Birthdate" 클래스에 매핑된다. <birthdayMonth> 요소는 RELAX NG string 데이타 타입을 확인하고 "Month."라는 이름으로 java.lang.String의 read/write 속성에 매핑될 것이다.같은 형태로, <birthdayDay><birthdayYear> 요소는 java.lang.Integer 오브젝트를 사용하는 비슷한 구조에 매핑될 것이다.

다음은 데이터를 JAXB 생성 인스턴스에서 XML 파일로 마샬Marchal)하거나, 또는 XML 파일에서 JAXB 생성 인스턴스로 언마샬(unmarshal)하기 위해 JAXB를 사용하는 Java 코드 (RELAXNGExample.java 파일 내)이다.
  import java.io.File;  import javax.xml.bind.JAXBContext;  public class RELAXNGExample {    public static void main(String[] args) throws Exception {        test(args[0]);           }        private static void test( String fileName ) throws       Exception {                        JAXBContext context = JAXBContext.newInstance("birthdate");                Object o = context.createUnmarshaller().            unmarshal(new File(fileName));         context.createValidator().validate(o);        context.createMarshaller().marshal(o,System.out);    }  }
예제를 구동하기 위해서는, 먼저 XJC 컴파일러를 사용하여 RelaxNG를 컴파일해야한다. XJC가 -relaxng 옵션으로 RELAX NG 사용하도록 요청할 수 있다. 다음의 XJC 명령을 구동하자.
   xjc -relaxng birthdate.rng -d gen-src
RelaxNG 파일 내의 옵션은 birthdate 패키지(코멘트 없이 Birthdate 인터페이스 포함)을 중심으로 하는 소스 코드를 생성할 수 있다.
package birthdate;public interface Birthdate {    java.lang.Integer getDay();    void setDay(java.lang.Integer value);    java.lang.Integer getYear();    void setYear(java.lang.Integer value);    java.lang.String getMonth();    void setMonth(java.lang.String value);}
다음으로, RELAXNGExample 클래스를 컴파일한다. gen-src 디렉토리에 클래스들이 방금 생성되었다. 그 후 컴파일된 클래스들을 구동한다. 컴파일과 구동을 쉽게 하기 위새서는 ant build tool을 이용한다. 구축 파일(build.xml)은 이 테크팁을 위한 샘플 코드에 제공되어 있다. 예제의 구축 파일이 있는 같은 디렉토리에 ant를 구동하여 구조를 설정할 수 있다. 사용자의 현재 디렉토리를 사용자가 샘플 코드를 설치한 릴렉싱 디렉토리로 변경한다. 그리고 다음 명령어를 입력한다.
   ant
다음 화면이 보여질 것이다.
   Buildfile: build.xml   compile:        [echo] Compiling the schema...        ...        [echo] Compiling the java source files...        ...      run:        [echo] Running the sample application...        [java] <?xml version="1.0" encoding="UTF-8"         standalone="yes"?>        [java] <birthdate><birthdayMonth>January</birthdayMonth>        <birthdayDay>21</birthdayDay><birthdayYear>1983        </birthdayYear></birthdate>         BUILD SUCCESSFULTotal time: 4 seconds
Additional Resources

For more information about JAXB, see Chapter 2: Using JAXB.

For more information about RELAX NG, see the RELAX NG tutorial.

For more information on the JAXB RI project.

For more information on the JAXB extensions for RELAX NG.

Back to Top
Posted by Tornado tornado