Aegis Databinding

Aegis는 JAXB와 다르게 표준(Spec.)이 아니며, Apache CXF에서만 제공되는 기능으로 JAXB와 역할이 동일하다. 즉, XML Schema로부터 클래스 데이터를 바인딩하여 XML로부터 객체를 Unmarshalling 하거나, 반대로 객체를 XML로 저장하는 Marshalling을 수행할 수 있도록 해 준다. Xfire 프로젝트의 일부로 시작되었으나 Celtix와 Xfire의 합체로 현재 Apache CXF에 포함되어 발전되고 있다.

Aegis의 특징 을 살펴보면 다음과 같다.
  • Apache CXF 사용 시 디폴트 Databinding 방식이 JAXB이므로, Aegis를 사용하기 위해서는 추가 설정이 필요하다.
  • JavaBeans 코드에 Annotation 설정 없이 Aegis를 사용할 수 있다.
  • List 형태의 타입 뿐 아니라 Map 형태의 타입에 대해서 추가 작성해야 하는 클래스 필요없이 기본적으로 Databinding을 지원한다.
  • Java 객체를 XML Schema에 의해 작성되는 XML 문서로 매핑해주는 일을 수행하는데 객체 제어 및 확장을 개발자가 최소한의 작업을 통해 가능하게 해준다.
  • Aegis를 사용하는 대부분의 개발자들은 Simple Frontend를 사용한다.
Aegis에서 지원하는 데이터 타입 은 다음과 같다.
구분
데이터 타입
Basic types int, double, float, long, byte[], short, String, BigDecimal, BigInteger, Character, Double, Float 등 *주의)char는 지원되지 않음
Collections Arrays, Maps
Dates java.util.Date, java.util.Calendar, java.sql.Timestamp, java.sql.Date, java.sql.Time
XML org.w3c.dom.Docmument, org.jdom.Element, XMLStreamReader, Source
Complex types 위 데이터 타입의 조합으로 새로 작성한 User Defined Types

다음은 Aegis 기능을 Server와 Client 단에서 어떻게 사용해야 하는지에 대한 사용법이다.

Server Configuration

Movie Service를 Simple Frontend를 사용하여 Web Services로 노출시킬 때 인터페이스 메소드의 파라인터 인자와 리턴 값의 타입을 다양한 타입으로 선언하여 테스트해보도록 한다.

Samples

다음은 Movie Service의 인터페이스 클래스 예제이다. Map 타입 사용을 위해서 부가적인 작업이 필요없다. 서버 구동을 위해서 Anyframe에서 제공하는 SimpleServer 클래스를 이용하고 있다.
  • Interface Class
  • 다음은 Movie Service의 인터페이스 클래스를 작성한 MovieService.java 의 일부이다.
    public interface MovieService {  
    
        public List<Movie> findMovieListAll() throws Exception;
    
        public Map<String, Movie> findMovieMapAll() throws Exception;
    
        public Movie findMovie(String movieId) throws Exception;
    
        public void createMovie(Movie movie) throws Exception;
    
        public void updateMovie(Movie movie) throws Exception;
    
        public void removeMovie(Movie movie) throws Exception;
    
        // ================= method for Type tests
        public int testMovieIntVal(int val);
    
        public long testMovieLongVal(long val);
    
        public short testMovieShortVal(short val);
    
        public float testMovieFloatVal(float val);
    
        public double testMovieDoubleVal(double val);
    
        public BigDecimal testMovieBigDecimalVal(BigDecimal val);
    
        public boolean testMovieBooleanVal(boolean val);
    
        public Character testMovieCharacterVal(Character val);
            중략...
    
  • Test case
  • 다음은 서버 사이드의 서비스를 Web Services로 노출시키는 서버를 구동하는 코드를 작성한 SimpleAegisTest.java 의 일부이다. setUp() 메소드 내에서 SimpleServer 를 생성시킨 후, 서버의 정보로 인터페이스 클래스, 구현 클래스의 인스턴스, Web Services 주소를 설정해준다.
    상위 테스트케이스 클래스인 RemotingTestCase 의 setUp() 메소드에서 Server 의 start() 메소드가 호출되면서 실제로 구동된다.
    여기서 ServerInfo 클래스 생성 시 생성자 메소드의 네번째 파라미터(boolean useAegisBinding)값을 true로 설정하고 있음에 주의하도록 한다. Aegis Databinding 기능을 사용하고자 한다면 true로 반드시 설정해야 한다.
    public class SimpleAegisTest extends RemotingTestCase {
    
        // ==============================================================
        // ====== TestCase 수행에 필요한 사전 작업 정의 ====================
        // ==============================================================
        
        public void setUp() throws Exception {
            this.setServer(new SimpleServer());
            this.getServer().setServerInfo(
                new ServerInfo(MovieService.class, new MovieServiceImpl(),
                    "http://localhost:9002/Movie", true)));
            super.setUp();
        }
           중략...
    ServerInfo 클래스의 useAegisBinding 값을 true로 설정하게 되면, 내부적으로 ServerFactoryBean 클래스의 API를 호출하여 Aegis Databinding 사용을 가능하게 해준다. 다음은 SimpleServer.java 의 일부 코드 부분이다. 참고하도록 한다.
    public class SimpleServer implements Server {
    
        ServerFactoryBean svrFactory = null;
    
        public SimpleServer() {
            svrFactory = new ServerFactoryBean();
        }
    
        public void setServerInfo(ServerInfo serverInfo) {
            svrFactory.setServiceClass(serverInfo.getInterfaceClass());
            svrFactory.setAddress(serverInfo.getAddress());
            svrFactory.setServiceBean(serverInfo.getImpleClass());
            if (serverInfo.isUseAegisBinding())
                svrFactory.getServiceFactory().setDataBinding(
                    new AegisDatabinding());
        }
    
        public void start() throws Exception {
            svrFactory.create();
            Server.LOGGER.info("Server ready...");
        }
    
        public void stop() throws Exception {
            svrFactory.getBus().shutdown(true);
        }
            중략...
    [Optional] Spring Configuration XML Server 설정 이용
    SimpleAegisTest 에서는 Simple Frontend API 코드를 사용하고 있으나, Spring Configuration XML 설정을 통해 Aegis Databinding 사용을 정의할 수 있다.
    <!-- Simple Frontend to expose MovieService with Aegis Databinding -->	
    <simple:server id="movieService" serviceBean="#anyframe.sample.movie.MovieService" 
           serviceClass="anyframe.sample.movie.MovieService" address="/Movie">
           <simple:dataBinding>
          		<bean class="org.apache.cxf.aegis.databinding.AegisDatabinding" />
       	</simple:dataBinding>
    </simple:server>
    중략...

Client Configuration

Web Services에 접근하기 위한 클라이언트 작성 방식 중 Anyframe에서 제공하는 API인 SimpleClient 를 사용하면 더욱 간편하고 편리하게 사용할 수 있다.(SimpleClient 내부적으로 Simple Frontend API 코드를 호출하고 있다.)

Samples

다음은 Anyframe에서 제공하는 SimpleClient를 이용하여 Web Services로 노출된 Movie Service에 접근하는 예제이다.
  • Test Case
  • 다음은 Anyframe에서 제공하는 SimpleClient 클래스를 사용하여 Web Services로 노출된 Movie Service에 접근하는 클라이언트 코드를 작성한 SimpleAegisTest.java 의 일부이다. testXXX() 메소드 내에서 SimpleClient 를 생성시킨 후, 클라이언트의 정보로 인터페이스 클래스와 접근하고자 하는 Web Services 주소를 이용하여 Movie Service를 얻어낸다. Movie Service를 얻은 후에는 Movie Service에서 Web Service 메소드로 노출된 메소드를 호출하여 동작이 올바른지 테스트해본다.

    즉, 다양한 데이터 타입에 대해서 Databinding이 올바로 동작하여 파라미터 값과 리턴 값이 의도된 대로 동작하는지 테스트한다.
    여기서 ClientInfo 클래스 생성 시 생성자 메소드의 세번째 파라미터(boolean useAegisBinding)값을 true로 설정하고 있음에 주의하도록 한다. Aegis Databinding 기능을 사용하고자 한다면 true로 반드시 설정해야 한다.
    public class SimpleAegisTest extends RemotingTestCase {
        // ==============================================================
        // ====== TestCase methods ======================================
        // ==============================================================
        /**
         * [Flow #-1] Positive Case : List 형태로 전체 목록을 조회한다.
         * @throws Exception
         *         throws exception which is from service
         */      
        public void testFindMovieListAll() throws Exception {
            Client client = new SimpleClient();
            MovieService movieService =
                (MovieService) client.getClient(new ClientInfo(MovieService.class,
                    "http://localhost:9002/Movie", true));
    
            // 1. find movie list all
            List<Movie> movieList = movieService.findMovieListAll();
    
            // 2. check the movie list count
            assertEquals(2, movieList.size());
        }
    
        /**
         * [Flow #-2] Positive Case : Map 형태로 전체 목록을 조회한다.
         * @throws Exception
         *         throws exception which is from service
         */    
        public void testFindMovieMapAll() throws Exception {
            Client client = new SimpleClient();
            MovieService movieService =
                (MovieService) client.getClient(new ClientInfo(MovieService.class,
                    "http://localhost:9002/Movie", true));
    
            // 1. find movie map all
            Map<String, Movie> movieMap = movieService.findMovieMapAll();
    
            // 2. check the movie map count
            assertEquals(2, movieMap.size());
        }
    
        /**
         * [Flow #-3] Positive Case : Movie Id가 "001"인 Movie를 조회한다.
         * @throws Exception
         *         throws exception which is from service
         */     
        public void testFindMovie() throws Exception {
            Client client = new SimpleClient();
            MovieService movieService =
                (MovieService) client.getClient(new ClientInfo(MovieService.class,
                    "http://localhost:9002/Movie", true));
    
            // 1. find movie
            Movie movie = movieService.findMovie("001");
    
            // 2. check the movie information
            assertEquals("The Sound Of Music", movie.getTitle());
            assertEquals("Robert Wise", movie.getDirector());
        }
            중략...
        /**
         * [Flow #-7] Positive Case : Type Test - input, output parameter로 int value를 
         *                            사용하여 호출한다.
         */    
        public void testMovieIntVal() {
            Client client = new SimpleClient();
            MovieService movieService =
                (MovieService) client.getClient(new ClientInfo(MovieService.class,
                    "http://localhost:9002/Movie", true));
    
            assertEquals(1, movieService.testMovieIntVal(1));
        }
    
        /**
         * [Flow #-8] Positive Case : Type Test - input, output parameter로 long value를
         *                            사용하여 호출한다.     
         */     
        public void testMovieLongVal() {
            Client client = new SimpleClient();
            MovieService movieService =
                (MovieService) client.getClient(new ClientInfo(MovieService.class,
                    "http://localhost:9002/Movie", true));
    
            assertEquals(1, movieService.testMovieLongVal(1));
        }
            중략...
    
    ClientInfo 클래스의 useAegisBinding 값을 true로 설정하게 되면, 내부적으로 ClientProxyFactoryBean 클래스의 API를 호출하여 Aegis Databinding 사용을 가능하게 해준다. 다음은 SimpleClient.java 의 일부 코드 부분이다. 참고하도록 한다.
    public class SimpleClient implements Client {
    
        ClientProxyFactoryBean factory = null;
    
        public SimpleClient() {
            factory = new ClientProxyFactoryBean();
        }
    
        public Object getClient(ClientInfo clientInfo) {
            factory.setServiceClass(clientInfo.getInterfaceClass());
            factory.setAddress(clientInfo.getAddress());
            if (clientInfo.isUseAegisBinding())
                factory.getServiceFactory().setDataBinding(new AegisDatabinding());
            return factory.create();
        }
            중략...
    [Optional] Spring Configuration XML Client 설정 이용
    SimpleAegisTest 에서는 Simple Frontend API 코드를 사용하고 있으나, Spring Configuration XML 설정을 통해 Aegis Databinding 사용을 정의할 수 있다.
    <!-- Simple Frontend to access MovieService with Aegis Databinding -->
    <simple:client id="movieService" serviceClass="anyframe.sample.movie.MovieService" 
        address="http://localhost:9002/Movie">
    	<simple:dataBinding>
    		<bean class="org.apache.cxf.aegis.databinding.AegisDatabinding" />
    	</simple:dataBinding>
    </simple:client>	
    중략...

Resources

  • 다운로드
  • 샘플 테스트 코드를 포함하고 있는 anyframe-remotingtest-src.zip 파일을 다운받은 후, 테스트 환경 설정 을 참조하여 위에서 제시한 예제 코드를 실행해 볼 수 있다. 이때 해당 프로젝트 내의 src/test/java 소스폴더 하위의 anyframe.core.remoting.webservices.databinding.aegis.SimpleAegisTest 클래스를 JUnit Test Framework을 이용하여 수행시키도록 한다.
    Name
    Download
    anyframe-remotingtest-src.zip
    Download

  • 참고자료