날짜별 글 목록: 2010년 6월 22일

eclipse에서 apache ivy로 binary 의존성 확인

Apache Ant 프로젝트의 서브 프로젝트로 Ivy 프로젝트(http://ant.apache.org/ivy/)가 있습니다.

 Ivy is a tool for managing (recording, tracking, resolving and
reporting) project dependencies.

아래의 IvyTest 클래스, ivy.xml을 만들고 build.xml파일에서 resolve target을 실행하게 아래와 같은 결과를 얻을 수 있습니다.

IvyTest.java

package dev;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.lang.WordUtils;

import static java.lang.System.out;

public class IvyTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {
            Option msg = OptionBuilder.withArgName(“msg”).hasArg().withDescription(“the message to capitalize”).create(“message”);
           
            Options options = new Options();
            options.addOption(msg);
   
            CommandLineParser parser = new GnuParser();
            CommandLine line = parser.parse(options, args);
   
            String  message = line.getOptionValue(“message”, “default message”);
            out.println(“standard message : ” + message);
            out.println(“capitalized by ” + WordUtils.class.getName() + ” : ” + WordUtils.capitalizeFully(message));
           
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

build.xml

<?xml version=”1.0″?>
<project name=”ivy-test” default=”resolve” basedir=”.” xmlns:ivy=”antlib:org.apache.ivy.ant”>
    <property name=”project.name” value=”ivy-test” />
     <property name=”project.version” value=”1.0.0″ />
     <property name=”project.owner” value=”mcsong@gmail.com” />
   
    <!– src –>
    <property name=”src.dir” value=”src” />
    <property name=”src.main.dir” value=”src/main” />
    <property name=”src.test.dir” value=”src/test” />
   
    <!– build –>
    <property name=”build.dir” value=”build” />
    <property name=”build.main.classes” value=”${build.dir}/classes/main” />
    <property name=”build.test.classes” value=”${build.dir}/classes/test” />
   
    <!– lib –>
    <property name=”lib.dir” value=”lib” />
    <property name=”lib.ext.dir” value=”lib-ext” />
   
    <!– dist –>
    <property name=”dist.dir” value=”dist” />
   
    <!– doc –>
    <property name=”doc.dir” value=”doc” />
   
    <!– ivy –>
    <property name=”ivy.install.version” value=”2.1.0″ />
    <property name=”ivy.dir” value=”ivy” />
    <property name=”ivy.jar.file” value=”${lib.dir}/ivy-2.1.0.jar” />
   
    <!– test –>
    <property name=”test.dir” value=”test” />
   
    <tstamp>
        <format property=”time” pattern=”yyyyMMdd” />
    </tstamp>
   
    <!– setting class path –>
    <path id=”class.path”>
        <pathelement location=”${build.main.classes}”/>
        <pathelement location=”${build.test.classes}”/>
        <pathelement location=”${dist.dir}”/>
        <pathelement location=”${lib.dir}”/>
 
        <pathelement location=”${lib.dir}/junit.jar”/>
        <pathelement location=”${lib.dir}/commons-cli-1.2.jar”/>
        <pathelement location=”${lib.dir}/commons-lang-2.5.jar”/>
        <pathelement location=”${lib.dir}/ivy-2.1.0.jar”/>
        <pathelement location=”${ant.home}/lib”/>
    </path>   
   
    <!– initialize –>
    <target name=”init” description=”–> create directories”>
        <echo>init target started</echo>
        <mkdir dir=”${doc.dir}”/>
        <mkdir dir=”${build.dir}”/>
        <mkdir dir=”${build.main.classes}”/>
        <mkdir dir=”${build.test.classes}”/>
        <mkdir dir=”${test.dir}”/>
        <!–mkdir dir=”${test.result.dir}”/>
        <mkdir dir=”${test.report.dir}”/–>
        <mkdir dir=”${dist.dir}”/>
        <echo>init target completed</echo>
    </target>       
   
    <!– clean –>
    <target name=”clean” description=”–> clean created directories”>
        <echo>clean target started</echo>       
        <delete dir=”${doc.dir}” />
        <delete dir=”${build.dir}”/>
        <delete dir=”${build.main.classes}”/>
        <delete dir=”${build.test.classes}”/>
        <delete dir=”${test.dir}”/>
        <!–delete dir=”${test.result.dir}”/>
        <delete dir=”${test.report.dir}”/–>
        <delete dir=”${dist.dir}”/>
        <echo>clean target completed</echo>
    </target>       
   
    <macrodef name=”compile_”>
        <attribute name=”srcdir” />
        <attribute name=”destdir” />
        <sequential>
            <javac srcdir=”@{srcdir}” destdir=”@{destdir}”>
                <classpath refid=”class.path” />
            </javac>
        </sequential>
    </macrodef>   

       <!– compile source –>
    <target name=”compile” depends=”clean, init” description=”compile this project”>
        <echo>compile target started</echo>
        <compile_ srcdir=”${src.main.dir}” destdir=”${build.main.classes}” />
        <compile_ srcdir=”${src.test.dir}” destdir=”${build.test.classes}” />
        <echo>compile target completed</echo>
    </target>   

    <!– run –>
    <target name=”run” depends=”compile” description=”run the project”>
        <echo>run target started</echo>
        <property name=”arg.01″ value=”ivy testing !”/>
        <java classpathref=”class.path” classname=”dev.IvyTest”>
            <arg value=”-message”/>
            <arg value=”${arg.01}”/>
        </java>
        <echo>run target completed</echo>
    </target>
   
   
    <target name=”resolve” depends=”init” description=”retreive dependencies with ivy”>
        <ivy:retrieve />
    </target>       
   
    <target name=”report” depends=”resolve” description=”generates a report of dependencies”>
        <ivy:report todir=”${build.dir}”/>
    </target>
  
    <target name=”clean-cache” description=”clean the ivy cache”>
        <ivy:cleancache />
    </target>
       
</project>

ivy.xml

<ivy-module version=”2.0″>
    <info organisation=”org.apache” module=”hello-ivy”/>
    <dependencies>
        <dependency org=”commons-lang” name=”commons-lang” rev=”2.5″/>
        <dependency org=”commons-cli” name=”commons-cli” rev=”1.2″/>
    </dependencies>
</ivy-module>

결과

Buildfile: C:\dev\works\ivy_test\build.xml
init:
     [echo] init target started
     [echo] init target completed
resolve:
[ivy:retrieve] :: Ivy 2.1.0 – 20090925235825 :: http://ant.apache.org/ivy/ ::
[ivy:retrieve] :: loading settings :: url = jar:file:/C:/Program%20Files/eclipse/plugins/org.apache.ant_1.7.1.v20090120-1145/lib/ivy-2.1.0.jar!/org/apache/ivy/core/settings/ivysettings.xml
[ivy:retrieve] :: resolving dependencies :: org.apache#hello-ivy;working@LENOVO-FAD74E43
[ivy:retrieve]     confs: [default]
[ivy:retrieve]     found commons-lang#commons-lang;2.5 in public
[ivy:retrieve]     found commons-cli#commons-cli;1.2 in public
[ivy:retrieve] downloading http://repo1.maven.org/maven2/commons-lang/commons-lang/2.5/commons-lang-2.5-javadoc.jar …
[ivy:retrieve] ……
[ivy:retrieve] …….
[ivy:retrieve] …..
[ivy:retrieve] ……..
[ivy:retrieve] ……..
[ivy:retrieve] ……….
[ivy:retrieve] ………
[ivy:retrieve] ….
[ivy:retrieve] …
[ivy:retrieve] ….
[ivy:retrieve] ……
[ivy:retrieve] …. (1557kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]     [SUCCESSFUL ] commons-lang#commons-lang;2.5!commons-lang.jar(javadoc) (24578ms)
[ivy:retrieve] downloading http://repo1.maven.org/maven2/commons-lang/commons-lang/2.5/commons-lang-2.5-sources.jar …
[ivy:retrieve] ……
[ivy:retrieve] …… (357kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]     [SUCCESSFUL ] commons-lang#commons-lang;2.5!commons-lang.jar(source) (4109ms)
[ivy:retrieve] downloading http://repo1.maven.org/maven2/commons-lang/commons-lang/2.5/commons-lang-2.5.jar …
[ivy:retrieve] ……..
[ivy:retrieve] ….. (272kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]     [SUCCESSFUL ] commons-lang#commons-lang;2.5!commons-lang.jar (5313ms)
[ivy:retrieve] downloading http://repo1.maven.org/maven2/commons-cli/commons-cli/1.2/commons-cli-1.2-sources.jar …
[ivy:retrieve] … (47kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]     [SUCCESSFUL ] commons-cli#commons-cli;1.2!commons-cli.jar(source) (2203ms)
[ivy:retrieve] downloading http://repo1.maven.org/maven2/commons-cli/commons-cli/1.2/commons-cli-1.2.jar …
[ivy:retrieve] … (40kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]     [SUCCESSFUL ] commons-cli#commons-cli;1.2!commons-cli.jar (1610ms)
[ivy:retrieve] downloading http://repo1.maven.org/maven2/commons-cli/commons-cli/1.2/commons-cli-1.2-javadoc.jar …
[ivy:retrieve] …..
[ivy:retrieve] .. (209kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]     [SUCCESSFUL ] commons-cli#commons-cli;1.2!commons-cli.jar(javadoc) (3734ms)
[ivy:retrieve] :: resolution report :: resolve 12688ms :: artifacts dl 41562ms
    ———————————————————————
    |                  |            modules            ||   artifacts   |
    |       conf       | number| search|dwnlded|evicted|| number|dwnlded|
    ———————————————————————
    |      default     |   2   |   2   |   2   |   0   ||   6   |   6   |
    ———————————————————————
[ivy:retrieve] :: retrieving :: org.apache#hello-ivy
[ivy:retrieve]     confs: [default]
[ivy:retrieve]     4 artifacts copied, 2 already retrieved (2171kB/47ms)
BUILD SUCCESSFUL

위의 내용을 통해서, 프로젝트의 의존성 있는 바이너리들을 쉽게 관리(?) 할 수 있을듯 합니다.
개발팀에서 적용하기에는 좀 귀찮은 작업일듯 하나, 개발팀의 모임인 개발실 급의 규모에서는 적용할 만한 기술인거 같네요..

참고로, Ivy 프로젝트의 설치는 아래와 같습니다.
1. 다운로드
2. ivy-2.1.0.jar를 ${ant.home}/lib에 카피를 합니다.
3. eclipse에서 window –> preference –> ant –> runtime –> classpath의 ant home entries에서 add external jars 버튼을 통해서 ivy-2.1.0.jar를 잡아주면 됩니다. 

위 데이타에 대한 리포팅 결과는 아래의 첨부파일을 참고하세요..
cfile7.uf.156C4F1C4C207A16183D8B.mht
* 참고자료
 – 사람을 위한 자동화: Ivy로 의존성 관리하기

외부 API를 JDK에서 내포한 경우, 최신의 외부 API 사용하기..

외부 API들이 JDK에 많이 포함이 되어 있습니다.
http://java.sun.com/javase/6/docs/api/ 문서의 package들을 보시면, javax나 org로 시작하는 외부(?) API들을 보실 수가 있는데요.. JDK에서는 rt.jar에 포함되어 잇지만, 아래의 내용처럼, http://aploit.egloos.com/4806304 님의 블로그에 포스팅된 내용을 보시면, 최신의 외부 API를 사용하기 위해서 java.endorsed.dirs 옵션을 사용해서 해결하는 내용을 보실 수가 있습니다.

java로 작업을 하다보면 가끔씩 endorsed라는 디렉토리 명이 보였다. 사전을 찾아보면 배서하다, 추천하다, 양도하다 정도의
뜻이고, 사전적 의미가 아닌 java쪽에서는 어떤 의미로 사용되는지 몰랐다.

그냥 몰라도 별 문제는 없었고 해서
그냥 넘어갔었다.

그런데 의미를 확실히 알게 되었다. 

jdk1.4에는 JAXP1.2의 라이브러리들이
포함되어 있다. 대표적으로 org.w3c.dom의 패키지와 javax.xml의 패키지가 그것이다.

그런데
JAXP1.3, 1.4가 나왔고, jdk1.4의 환경에서 이들을 사용하고자 할 경우에 문제가 된다.
(참고로 JAXP1.3은
JDK5.0에 JAXP1.4는 JDK6.0에 포함되었다. 따라서 JDK5.0에서는 JAXP1.3 라이브러리를 따로 설치할 필요가
없다.) jdk는 1.4이고 어플리케이션에서 JAXP1.3을 설치했다고 하면(구체적인 jar 파일은 jaxp-api.jar와
jaxp-ri.jar이다) 같은 패키지 이름까지 같은 클래스가 2개 존재하게된다. 예를 들면
org.w3c.dom.Document이다. 하나는 rt.jar에 있는 것이고(버전은 JAXP1.2) 하나는
jaxp-api.jar에 있는 것이다(요 버전은 JAXP1.3). 원했던 것은 rt.jar의 것이 아닌 jaxp-api.jar의
것이 로딩되는것이였는데, 그렇게 동작하지 않는다. 설치한 라이브러리들 간의 로딩 순서는 classpath에 설정한 순서로 조절할 수
있지만, rt.jar는 설정 순서로 조절할 수 없다.

JDK 자체에 포함된 것이 아닌 설치한 라이브러리의 것을
로딩할때 사용하는 매커니즘이 바로 endorsed이다. “java.endorsed.dirs”라는 시스템 파라매터를 설정하면 된다.
다음과 같이 java를 실행할 때 jaxp-api.jar가 있는 디렉토리를 설정해 주면 된다.
java
-Djava.endorsed.dirs=/path/where/jar/is ……
여기서 /path/where/jar/is
디렉토리는 jaxp-api.jar가 있는 곳이다.

TOMCAT의 경우 endorsed 매카니즘을 사용하고 있다.
tomcat 4.1.39의 bin/setclasspath.bat에서 set
JAVA_ENDORSED_DIRS=%BASEDIR%\common\endorsed 으로 endorsed 디렉토리를 설정하고
catalina.bat에서 다음과 같이 java 실행 시에 시스템 파라매터로 설정해 주고 있다.
%_EXECJAVA% …
-Djava.endorsed.dirs=”%JAVA_ENDORSED_DIRS%”

TOMCAT_HOME/common
/endorsed에 가보면 xercesImpl.jar, xml-apis.jar가 있는데 이들은 JAXP 1.3의 것이다.


고로 클래스로딩의 매카니즘에서 “java.” 로 시작하는 패키지의 클래스는 endorsed가 적용되지 않는다.

JAXP
에 대한 기타.
JAXP1.4가 설치되어 있다면 apache xalan의 다음과 같은 라이브러리들을 따로
설치할 필요 없다. JAXP안에 포함되어 있기 때문이다. 설치할 필요가 없는 것 보다는 쫑나는 상황을 피하기 위하여 설치해서는
안된다.
  serializer.jar
  xalan.jar
  xercesImpl.jar
  xml-apis.jar
  xsltc.jar

jaxp
는 sun의 glassfish 프로젝트에서 관리하고 있다.