앞서 오픈소스를 통해서 소스 저장소에 등록되는 디렉토리 구조를 살펴보았습니다. 그리고 프로젝트 소스를 일괄처리하는 build.xml 도 살짝 들여다 보았습니다. 이클립스 툴을 쓰면 다 되는 작업을 왜 Ant 빌드스크립트를 만들어야하는지 질문을 종종 들어봤습니다. 지속적인 통합 빌드 같이 주기적으로 반복되는 작업이나 단계가 복잡한 작업들은 빌드스크립트가 효과적입니다. 클릭클릭하는 일도 지겨울 때가 있거든요. 이클립스 작업의 자동화가 빌드 스크립트라고 생각하시면 될 것입니다.

지난 번 소스 가져오기(import) 이후로 소스의 빌드 경로를 잡아보려고 합니다. 로컬pc에서 컴파일되나 안되나 확인하는 것이죠. 소스가 패키지에 맞게 제자리에 있어야 할 것이고, 참조하는 jar파일의 경로도 함께 지정해줘야 합니다.

일단 이클립스 자바 프로젝트에서 소스 폴더를 추가합니다. 자바소스가 있는 폴더를 소스폴더라고 합니다. *.java 파일과 *.properties 파일들이 위치합니다. httpunit-1.7 아래 src 폴더가 바로 소스폴더입니다. 그리고 httpunit-1.7 아래 test 라는 곳도 소스 폴더로 추가합니다. src 아래 있는 클래스들을 테스트하는 테스트케이스들의 소스 폴더입니다.

자동 빌드가 일어나면서 에러가 무진장 일어납니다. jar 파일 연결이 안되서 그렇습니다.

왼쪽 패키지 익스플로러에서 프로젝트를 선택하고 Properties 창을 엽니다. 컨텍스트 메뉴에서 제일 아래 Properties 메뉴를 선택하면 됩니다. 단축키는 alt+Enter
Java Build Path 항목을 선택하고 Libraries 탭을 클릭합니다.

우측의 Add JARs... 버튼을 클릭해서 httpunit-1.7/jars 폴더의 *.jar 파일들을 선택합니다.

오호, 에러가 줄기는 했는데, 하나 남았네요. fnfe를 클릭해서 해당 소스를 열어보겠습니다. 흠, 겁을 상실했군요. 에~ 뭐 꼭 고친다는 뜻은 아닙니다. ^^;

소스를 살짝 보니 캐릭터셋 문제로 Roger Lindsj 이름 옆에 이상한 문자가 생긴 것 같네요. 그것 때문에 아랫줄 if라인이 주석 줄로 따라 올라온 듯 합니다.

if 앞에서 엔터로 줄바꿔주니 고쳐졌습니다. ^^; 잠시 우쭐~

Problems 탭에 에러는 싹 사라졌군요. Warnings는 살짝 봐주기로 하죠. ^^;

소스 폴더가 추가된 모습입니다.

작업공간은 에러 없는 코드로 관리되는 것이 개발자 심리에 좋다고 생각을 합니다. ^^;

앞서 오픈소스인 httpunit을 통해서 프로젝트 소스 구성을 살펴봤습니다. 빌드스크립트인 build.xml를 통해서 프로젝트 소스를 가공하는 방법을 알 수 있습니다. 프로젝트의 작업 지시서와 같은 역할을 하는 것이죠.

이클립스의 아웃라인뷰에 나오는 타겟 목록입니다.
소스를 보면 <project ... default="jar"> 내용을 확인 할 수 있습니다. 기본 프로젝트 타겟은 jar 입니다.

그 외에도 수많은 작업그룹이 보입니다. 각각의 내용을 확인해 봐야 정확한 작업 내용을 알 수 있겠지만 여기서는 jar 를 중심으로 살펴보겠습니다.

<!--  ===================================================================  -->
<!--  Creates the jar archive                                              -->
<!--  ===================================================================  -->
<target name="jar" depends="compile" description="create the jar file">
    <mkdir dir="${lib.dir}" />
    <echo file="${build.dir}/info.txt">Manifest-Version: 1.0
Sealed: false
HttpUnit-Version: ${version}
Build-Date: ${TODAY}
Build-Time: ${TSTAMP}
</echo>
    <jar jarfile="${lib.dir}/${name}.jar" manifest="${build.dir}/info.txt">
        <fileset dir="${build.classes}" includes="com/**"/>
        <fileset dir="META-INF" includes="*.dtd"/>
    </jar>
</target>

주석의 모양도 참고 대상입니다.  타겟의 depends속성을 보면 compile 타겟이 먼저 수행되는 것을 알 수 있습니다. <jar> 태스크를 보면 JAR 파일명이 지정되어 있습니다. 컴파일된 클래스 디렉토리를 기준으로 com 패키지 아래 있는 것이 포함되고, META-INF 디렉토리에 있는 *.dtd 파일들도 jar 파일에 들어갑니다.

compile 타겟을 확인하면 소스의 위치는 확실히 알 수 있겠죠.

<!--  ===================================================================  -->
<!--  Compiles the source code                                             -->
<!--  ===================================================================  -->
<target name="compile-for-java2" depends="prepare,check_for_optional_packages" if="dom3.absent">
    <mkdir dir="${build.classes}" />
    <javac srcdir="src-1.4" destdir="${build.classes}"/>
</target>
<target name="compile" depends="prepare,check_for_optional_packages,compile-for-java2">
    <mkdir dir="${build.classes}" />
    <javac srcdir="${src.dir}" destdir="${build.classes}"
           debug="${debug}" deprecation="${deprecation}" optimize="${optimize}">
        <classpath refid="base.classpath" />
        <exclude name="**/JTidyHTMLParser.java" unless="jtidy.present" />
        <exclude name="**/ScriptFilter.java" unless="nekoHTML.present" />
        <exclude name="**/NekoHTMLParser.java" unless="nekoHTML.present" />
        <exclude name="**/NekoDOMParser.java" unless="nekoHTML.present" />
        <exclude name="**/servletunit/*" unless="jsdk.present" />
        <exclude name="**/JUnitServlet.java" unless="junit.present" />
        <exclude name="**/javascript/*" unless="rhino.present" />
    </javac>
</target>
 
클래스의 빌드 디렉토리를 만든 후에 파일들을 컴파일 합니다. 컴파일 시 관련 jar의 유무에 따라 컴파일에서 제외시키기도 합니다. 여러가지 jar파일들을 사용하는 것을 알 수 있습니다. jtidy, nekoHTML, jsdk, junit, rhino. 대부분 자바스크립트 파서나 실행에 관련된 것들이죠.

httpunit 한 프로젝트에서도 건질 것들이 굉장히 많은 듯 합니다.


오픈소스의 좋은 점 중 하나는 제품 개발과정을 볼 수 있다는 것입니다. 소스 프로젝트의 구성을 볼 수 있고, ant나 maven 등의 빌드 구성과 TestCase를 어떻게 만들었는지 확인이 가능합니다.

httpunit이라는 소스포지의 오픈소스를 통해서 그 구성을 살펴보겠습니다.
http://httpunit.sourceforge.net 에 접속합니다.

왼쪽 메뉴 중 Download를 클릭해서 다운로드 받습니다.

파일을 이클립스에서 import 해보겠습니다. httpunit 이라는 이름으로 자바프로젝트를 하나 만듭니다.

프로젝트를 선택하고 컨텍스트 메뉴에서 Import... 를 선택합니다.

ar 이라고 필터란에 입력하면 Archive File 메뉴가 보입니다.

앞서 다운로드 받은 httpunit-1.7.zip 파일을 선택합니다.

폴더 통째로 import를 해왔습니다.

디렉토리의 구성을 잘 살펴볼 필요가 있습니다.
doc : 아마도 html 이나 프로젝트 관련 문서들 원본 등이 있을 것입니다.
examples : httpunit을 이용하는 예제들 디렉토리
jars : 프로젝트 관련 jar 파일 디렉토리
lib : httpunit.jar 산출물 생성 디렉토리
META-INF : jar 압축시 기본 생성 디렉토리
src : java 소스 디렉토리
test : 테스트케이스 디렉토리
build.xml : 프로젝트 빌드를 위한 ant 빌드 스크립트


이러한 구성을 참고로 자신이 진행하는 프로젝트의 소스 및 파일들을 관리하는 것도 좋을 것입니다.


http://www.eclipse.org/users 페이지를 가보면 다음과 같은 화면을 볼 수 있습니다. Help Topic 페이지입니다.

우측 상단의 Switch View를 클릭하면 이클립스의 기둥들이라고 하는 주요한 프로젝트들에 대한 아이콘들이 나타납니다. 상단 메인 영역가 우측 하단의 내용이 스위치됩니다. 재밌게 만들어 놓았습니다.

많은 컨텐츠들을 효과적으로 배치해 놓았다는 느낌이 듭니다.

사용자는 생태계 피라미드에서 바닥을 깔아주는 넓고, 광범위한 영역입니다. 이들에게 필요한 것은 가이드, 매뉴얼, 튜토리얼 등 입문과 활용에 관한 문서들이죠. 그에 관한 접근을 쉽고 재밌게 만들어 놓은 노력은 높이 살만합니다.
 
http://www.eclipse.org/users


어제 스타킹 신청을 했었습니다. 오늘 오전에 전화를 받아보니 장기자랑이라는군요. 헉, 혼동했었습니다. 번개토크(Lightning Talk)를 대화의 시간으로 번역이 되어서 제가 스타킹과 혼동을 했었네요. 여차저차해서 findbugs로 준비한 내용으로 끼어 들어가긴 했습니다. 안 하려고 했던 스타킹도 하게 되고요.

첨부 파일은 그 때 발표한 자료입니다.

http://www.okjsp.pe.kr/seq/124888 
금일 okjsp세미나에서 발표하게 되는 내용입니다.
30분 정도의 짧은 시간에 발표하게 됩니다.

마인드맵은 http://freemind.sf.net 에서 구하실 수 있습니다.
ps. 에이콘 출판사에서 Great Code 1,2 두 세트를 후원해주셨습니다. 감사합니다.

findbugs-ant.jar 파일을 $ANT_HOME/lib 에 복사한 뒤에 findbugs task를 사용할 수 있습니다.
파일이 많아지면 timeout이나 memory 이슈가 생길 수 있습니다.

참고용으로 적어봅니다.


        <taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask" />
        <target name="findbugs" depends="compile">
                <findbugs home="${findbugs.home}" output="xml" outputFile="findbugs.xml"
                        jvmargs="-Xms512M -Xmx1024M " timeout="1800000">
                        <auxClasspath path="${findbugs.home}/lib/Regex.jar" />
                        <sourcePath path="WebContent/WEB-INF/src" />
                        <class location="WebContent/WEB-INF/classes" />
                </findbugs>
        </target>


조대협님 감사합니다. ^^


update site url 입니다. http://findbugs.cs.umd.edu/eclipse/
설치가 완료되면 다음과 같은 메뉴가 보입니다.

테스트용으로 에러를 발생시키는 소스를 만들어서 테스트 해봅니다.

package net.okjsp;

public class HelloWorld {

 /**
  * @param args
  */
 public static void main(String[] args) {
  String arg = null;
  System.out.println("Hello World! "+arg.equals("0"));

 }

}


문제가 되는 라인 앞에 버그가 표시됩니다. 더블클릭하면 하단에 findbugs 뷰가 생깁니다.


해당 버그의 내용과 수정 방법에 대해서 표시됩니다.

뷰 메뉴 중 findbugs 퍼스펙티브로 전환하는 아이콘도 있습니다.

클릭하면 다음과 같은 정보를 확인할 수 있습니다.

이제 쎄스코를 부르지 않아도 될 것 같습니다.

 

제일 처음 자바를 시작했을 때, 에러(Error와 Exception 나뉘지만 에러로 표기합니다)화면을 보고 깜짝 놀랬습니다.

2008-10-06 13:27:06 ApplicationDispatcher[/] Servlet.service() for servlet download threw exception
java.lang.IllegalStateException: getWriter() has already been called for this response
        at org.apache.coyote.tomcat5.CoyoteResponse.getOutputStream(CoyoteResponse.java:568)
        at org.apache.coyote.tomcat5.CoyoteResponseFacade.getOutputStream(CoyoteResponseFacade.java:148)
        at kr.pe.okjsp.DownloadServlet.doGet(Unknown Source)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
        at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:704)
        at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:474)
        at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:409)
        at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:312)
        at kr.pe.okjsp.ControllerServlet.doGet(Unknown Source)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
... 중략 ...
        at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:799)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:705)
        at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:577)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
        at java.lang.Thread.run(Thread.java:619)

저런 식으로 우수수 떨어지는 에러메시지는 초보에게는 공포감을 일으키기 충분합니다. "내가 그 정도로 잘못했는지 정말 몰랐어요"라는 감정이 생기죠. 사실 에러메시지의 상단 2~3줄만 봐도 문제의 원인을 파악할 수 있는데, 스택트레이스(Stack Trace)라 불리는 사정없는 에러메시지는 정말 "안 좋아"였습니다.

try{...} catch(Exception e) { System.out.println(e.getMessage()); }

저런 메시지 폭탄을 피하기 위해서 위 코드를 통해 핵심 메시지만 봅니다. 이 포스팅의 핵심은 저기서 나온 메시지들과 친해지라는 것입니다. 아마 자주 보일 것입니다.

가까이 하기 어려운 사실 하나는 "영어"로 된 메시지라는 것이겠죠. 영어는 못해도 자바는 좀 하신다면 공개된 소스나 디컴파일을 통해서 저 메시지 생성부분을 찾아볼 수 있습니다. 더구나 자바의 기본 라이브러리는 공개되어 있습니다. src.zip 파일이 그것이죠.

이클립스 툴이나 텍스트 에디터 등을 통해서 에러 메시지를 검색해보면 해당 부분의 소스를 볼 수 있을 것입니다.

또 다른 방법은 구글링을 통해서 소스를 검색해 볼 수도 있습니다. 위 메시지의 경우 검색어를 다음과 같이 넣습니다.


따옴표("")로 감싼 이유는 단어 구분해서 찾지 말고 문구 그대로 검색하라는 의미이고 filetype:java 는 확장자가 java인 파일만 검색하라는 뜻입니다.

이런 식으로 소스를 찾아서 에러원인을 볼 수 있다면, 아마 문제해결(Troubleshooting) 능력이 많이 좋아질 것입니다.

버그와 에러는 다르죠. 에러 메시지! 사라지지 말고 함께 해요.

ps. 공통 프레임워크 만드시는 분들 에러 씹지 말고 보내주세요. ^^;
http://www.eclipse.org 사이트의 메인이 확 바뀌었습니다.

Users > Ecosystems > Members > Committers 사이클의 의미가 새롭게 다가옵니다.

일반적인 서비스는 제공자(Provider)와 소비자(Consumer)로 나뉩니다. 하지만 다른 제품들은 생태계(Ecosystem)를 만들어냅니다. 블리자드의 스타크래프트를 떠올려 볼 수 있습니다. Map을 사용자가 직접 만들어서 배틀넷에서 플레이할 수 있습니다. 놀이터를 만들어서 자유롭게 게임을 즐길 수 있도록 한 것입니다. 시나리오 모드에 감격하고 끝나면 소비에서 마치게 되지만 배틀넷에서 Use Map Setting 모드의 게임들은 상상초월의 재미를 가져다 주게 됩니다. 물론 모든 사용자가 만든 맵들이 공평하게 대우받지는 못합니다. 재미 요소를 가진 맵들이 생존하고 주도권을 잡게 되는 것이죠.

이클립스 플랫폼이 추구하는 것도 같다고 봅니다. PDE(Plugin Development Environment)를 제공해서 스스로 진화할 수 있는 통로를 열어놓았습니다.

"너희는 주는대로 받아 먹어라"는 서비스와 "자 이제 같이 함께 놀아봅시다 당신의 생각은 어떤 것인가요"라고 판(플랫폼)을 펼쳐 놓는 것은 다릅니다.

+ Recent posts