나 자신을 다스리는 자가 세상을 다스린다.

1. Extended VS Presentation
license : EPL
homepage : http://andrei.gmxhome.de/skins/index.html
url update manager : http://andrei.gmxhome.de/eclipse/
※ 마우스 wheel click 으로 창닫기 기능이 편리하여 잘 사용하고 있음.

2. AnyEdit tools
license : BSD License
homepage : http://andrei.gmxhome.de/anyedit/index.html
url update manager : http://andrei.gmxhome.de/eclipse/

3. Eclipse Web Tools Platform
license:   CPL1.0
homepage:   http://www.eclipse.org/webtools/index.html
url update manager:  http://download.eclipse.org/webtools/updates  (그냥 callisto 사용 또는 all in one 버전 다운로드)

4. myEclipse Enterprise Workbench (상용)
license:       Commercial/Free trial
homepage:   http://www.myeclipseide.com
※ 상용이어서 Web Tools 를 사용하고 있지만 J2EE 쓰기에는 myEclipse 가 제일 나은 듯(개인적인 생각)

5. BEA Workshop JSP Editor
license:   Free
homepage:   http://www.m7.com/epiinfo.do
※ 주의사항 : Workshop 설치 전에 WTP 의 server 를 이미 설정 했을 경우 충돌. server 지우고 다시 생성하면 문제는 없는 듯

6. Log4E (상용)
license:       Free and commercial versions
homepage:       http://log4e.jayefem.de
url update manager:   http://log4e.jayefem.de/update

7. Properties Editor
license : GPL
homepage : http://propedit.sourceforge.jp/index_en.html
url update manager : http://propedit.sourceforge.jp/eclipse/updates/

8. implementors
license : CPL1.0
homepage : http://eclipse-tools.sourceforge.net/implementors
url update manager : http://eclipse-tools.sourceforge.net/updates/
※ interface 를 많이 사용 할 경우에 굉장히 유용한 plug-in. implementation class 로의 jump 가 가능하게 해주는 plug-in

9. QuantumDB
license : Common Public License
homepage : http://quantum.sourceforge.net/index.html
url update manager : http://quantum.sourceforge.net/update-site

10. PDT (PHP Development Tools)
license : Eclipse Public License
homepage : http://www.eclipse.org/pdt/index.php
url update manager : http://download.eclipse.org/tools/pdt/updates/

11. Eclipse Status Monitor
license : Creative Commons Attribution v3.0
homepage : http://www.kyrsoft.com
url update manager : http://www.kyrsoft.com/updates

신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by trypsr Trackback 0 Comment 0
맨날 까먹는다..
이제 잊지말자.

프로젝트의 properties > Info > New text file line delimiter 에서 Unix 로 설정
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by trypsr Trackback 0 Comment 0
그 동안 iBATIS 를 Oracle 과 mySQL 에서만 사용해 오다가 JDBC를 사용하며 RDBMS이면 거의 다 지원한다고 하는 iBATIS를 믿고 Altibase 와 연동을 해보았다.

connection pool 로는 DBCP 를 사용하였다.

그런데 이 Altibase 라는 놈이 기존 DB 들과는 다르게 Encoding 을 connection 맺을 때 properties 로 받고 있었다.

30 분 정도 실랑이 후 지인의 도움으로 해결 방법을 겨우 찾았다.


드라이버에 종속적인 properties 를 사용하기 위해서는 기존의 접두사 방식의 설정을 사용해서는 안된다.

bean 스타일의 셋팅을 사용해야 한다.
드라이버에 종속적인 properties 를 명시하기 위해서는 Driver 라는 새로운 접두사를 사용해서 하면 된다.

Driver.properitiesName = propertiesValue

그러나 기존의 접두사 방식과 Driver 접두사 를 같이 사용하면 적용이 안된다는 사실...(이건 내부적으로 어떻게 그리고 왜 구분 하는지? 소스 한번 봐? 귀찮다. -.-;)
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by trypsr Trackback 0 Comment 0
테스트 없이 눈으로만 코딩할 때 가장 틀리기 쉬운 부분이 call by value 와 call by refence 를 정확히 이해하지 못할 때 생기는 오류가 아닐까 싶다.

기본형과 객체가 있는데
기본형은 call by value 이고 객체는 call by refence 라는 것은 대부분의 java 개발자들이 알고 있을꺼라 생각한다.

그 예로 swap 함수를 가장 많이 설명하는데..

예제 1)

class Test {
    private static void swap(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
    }

    public static void main(String args[]) {
        int a = 1;
        int b = 2;

        System.out.println("a => " + a);
        System.out.println("b => " + b);

        swap(a, b);

        System.out.println("------- swap 후 -------");

        System.out.println("a => " + a);
        System.out.println("b => " + b);
    }
}

예제 1 의 경우 원하던 결과가 아닌 것을 바로 알아 낼 수 있을 것이다.
swap 메소드에 넘기는 것은 reference 가 아닌 value 이기 때문에...
쉽다. 넘어가자.

다음 예제 2 를 보자
예제 2)

class Test {
    private static void swap(Integer a, Integer b) {
        Integer temp = a;
        a = b;
        b = temp;
    }

    public static void main(String args[]) {
        Integer a = new Integer(1);
        Integer b = new Integer(2);

        System.out.println("a => " + a.intValue());
        System.out.println("b => " + b.intValue());

        swap(a, b);

        System.out.println("------- swap 후 -------");

        System.out.println("a => " + a.intValue());
        System.out.println("b => " + b.intValue());
    }
}

예제 2 의 경우 Integer 는 Object 이다. Object 는 call by reference 다.
따라서 위의 예제는 원하는 결과를 가져올 것이다.
그러나 실행을 하면 예제 1과 전혀 다르지 않다는 것을 알 수 있다.

왜? 객체는 call by reference 라며 사기친거야?

결론부터 말하면 객체는 call by reference 맞다

그러나 해당 객체를 보는 새로운 reference 를 참조해서 넘기는 것이다.

따라서 동일한 객체를 가르키고 있지만
main 에서의 reference 값과 swap 함수에서의 reference 값은 다르다.

따라서 위의 예제의 경우 원하는 결과가 나오지 않는다.

그렇다면 어떻게 해야 해?

예제 3 을 보자.

예제 3)

class Test {
    int value;

    Test(int value) {
        this.value = value;
    }

    private static void swap(Test a, Test b) {
        int temp = a.value;
        a.value = b.value;
        b.value = temp;
    }

    public static void main(String args[]) {
        Test a = new Test(1);
        Test b = new Test(2);

        System.out.println("a => " + a.value);
        System.out.println("b => " + b.value);

        swap(a, b);

        System.out.println("------- swap 후 -------");

        System.out.println("a => " + a.value);
        System.out.println("b => " + b.value);
    }
}

예제 2와 같이 객체의 reference 를 넘긴다.
reference 를 직접 변경하는 게 아니라.
reference 가 참조하는 객체의 value 를 변경하고 있다.
따라서 같은 객체를 보고 있는 main 에서도 값이 바뀌는 것을 알 수 있다.

call by reference

해당 객체의 주소값을 직접 넘기는 게 아닌 객체를 보는 또 다른 주소값을 만들어서 넘기다는 사실을 잊지 말자~
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
TAGjava
Posted by trypsr Trackback 0 Comment 2
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import org.apache.commons.lang.StringUtils;

public class ZipUtils {

    private static final int COMPRESSION_LEVEL = 8;

    private static final int BUFFER_SIZE = 1024 * 2;

    /**
     * 지정된 폴더를 Zip 파일로 압축한다.
     * @param sourcePath - 압축 대상 디렉토리
     * @param output - 저장 zip 파일 이름
     * @throws Exception
     */
    public static void zip(String sourcePath, String output) throws Exception {

        // 압축 대상(sourcePath)이 디렉토리나 파일이 아니면 리턴한다.
        File sourceFile = new File(sourcePath);
        if (!sourceFile.isFile() && !sourceFile.isDirectory()) {
            throw new Exception("압축 대상의 파일을 찾을 수가 없습니다.");
        }

        // output 의 확장자가 zip이 아니면 리턴한다.
        if (!(StringUtils.substringAfterLast(output, ".")).equalsIgnoreCase("zip")) {
            throw new Exception("압축 후 저장 파일명의 확장자를 확인하세요");
        }

        FileOutputStream fos = null;
        BufferedOutputStream bos = null;
        ZipOutputStream zos = null;

        try {
            fos = new FileOutputStream(output); // FileOutputStream
            bos = new BufferedOutputStream(fos); // BufferedStream
            zos = new ZipOutputStream(bos); // ZipOutputStream
            zos.setLevel(COMPRESSION_LEVEL); // 압축 레벨 - 최대 압축률은 9, 디폴트 8
            zipEntry(sourceFile, sourcePath, zos); // Zip 파일 생성
            zos.finish(); // ZipOutputStream finish
        } finally {
            if (zos != null) {
                zos.close();
            }
            if (bos != null) {
                bos.close();
            }
            if (fos != null) {
                fos.close();
            }
        }
    }

    /**
     * 압축
     * @param sourceFile
     * @param sourcePath
     * @param zos
     * @throws Exception
     */
    private static void zipEntry(File sourceFile, String sourcePath, ZipOutputStream zos) throws Exception {
        // sourceFile 이 디렉토리인 경우 하위 파일 리스트 가져와 재귀호출
        if (sourceFile.isDirectory()) {
            if (sourceFile.getName().equalsIgnoreCase(".metadata")) { // .metadata 디렉토리 return
                return;
            }
            File[] fileArray = sourceFile.listFiles(); // sourceFile 의 하위 파일 리스트
            for (int i = 0; i < fileArray.length; i++) {
                zipEntry(fileArray[i], sourcePath, zos); // 재귀 호출
            }
        } else { // sourcehFile 이 디렉토리가 아닌 경우
            BufferedInputStream bis = null;
            try {
                String sFilePath = sourceFile.getPath();
                String zipEntryName = sFilePath.substring(sourcePath.length() + 1, sFilePath.length());

                bis = new BufferedInputStream(new FileInputStream(sourceFile));
                ZipEntry zentry = new ZipEntry(zipEntryName);
                zentry.setTime(sourceFile.lastModified());
                zos.putNextEntry(zentry);

                byte[] buffer = new byte[BUFFER_SIZE];
                int cnt = 0;
                while ((cnt = bis.read(buffer, 0, BUFFER_SIZE)) != -1) {
                    zos.write(buffer, 0, cnt);
                }
                zos.closeEntry();
            } finally {
                if (bis != null) {
                    bis.close();
                }
            }
        }
    }

    /**
     * Zip 파일의 압축을 푼다.
     *
     * @param zipFile - 압축 풀 Zip 파일
     * @param targetDir - 압축 푼 파일이 들어간 디렉토리
     * @param fileNameToLowerCase - 파일명을 소문자로 바꿀지 여부
     * @throws Exception
     */
    public static void unzip(File zipFile, File targetDir, boolean fileNameToLowerCase) throws Exception {
        FileInputStream fis = null;
        ZipInputStream zis = null;
        ZipEntry zentry = null;

        try {
            fis = new FileInputStream(zipFile); // FileInputStream
            zis = new ZipInputStream(fis); // ZipInputStream

            while ((zentry = zis.getNextEntry()) != null) {
                String fileNameToUnzip = zentry.getName();
                if (fileNameToLowerCase) { // fileName toLowerCase
                    fileNameToUnzip = fileNameToUnzip.toLowerCase();
                }

                File targetFile = new File(targetDir, fileNameToUnzip);

                if (zentry.isDirectory()) {// Directory 인 경우
                    FileUtils.makeDir(targetFile.getAbsolutePath()); // 디렉토리 생성
                } else { // File 인 경우
                    // parent Directory 생성
                    FileUtils.makeDir(targetFile.getParent());
                    unzipEntry(zis, targetFile);
                }
            }
        } finally {
            if (zis != null) {
                zis.close();
            }
            if (fis != null) {
                fis.close();
            }
        }
    }

    /**
     * Zip 파일의 한 개 엔트리의 압축을 푼다.
     *
     * @param zis - Zip Input Stream
     * @param filePath - 압축 풀린 파일의 경로
     * @return
     * @throws Exception
     */
    protected static File unzipEntry(ZipInputStream zis, File targetFile) throws Exception {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(targetFile);

            byte[] buffer = new byte[BUFFER_SIZE];
            int len = 0;
            while ((len = zis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
        } finally {
            if (fos != null) {
                fos.close();
            }
        }
        return targetFile;
    }
}

위의 소스는 문제점이 있다.
사실 소스문제라기 보다는 java.util.zip 문제이다.
zip 파일안의 파일명의 인코딩을 UTF-8 로 하기 때문에 압축 대상 파일명에 한글이 있을경우 문제가 생긴다.
만약 압축 대상 파일명에 한글이 포함되어 있다면 jazzlib 를 사용하기 바란다.

jazzlib 는 java.util.zip 과 구조 및 사용법이 똑같으므로 위의 소스에서 ZipEntry, ZipOutputStream 의 import 문만 변경하여 주면 된다.

import net.sf.jazzlib.ZipEntry;
import net.sf.jazzlib.ZipInputStream;
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
TAGjava
Posted by trypsr Trackback 0 Comment 1

우리나라에서 자바 개발자 컨퍼런스가 벌써 8회째..
6회때부터 신청만 해놓고 가지 못했던 자바 개발자 컨퍼런스..
이번엔 다른 일 다 제쳐두고 참석해보았다.

정말 많은 참석인원..
우리나라에 개발자가 이렇게 많을 줄이야~
그런데 사람 뽑을려면 왜 이렇게 없는지~
다들 좋은 곳으로 몰려 다니나?

컨퍼런스 내용을 보면 세션 준비 하신 분들이 너무나들 쟁쟁하신 분들..
3, 4번째 세션엔 너무 좋은 세션이 몰려있어서 세션 시간 전까지도 고민을 많이 했다.

추후에 세션 내용 동영상으로 제공 안되려나? 다른 세션들도 놓치기 아까웠는데.
사실 스폰서들의 경품에 현혹되어 세션 시작 시간을 놓치기도 했지만..^^
컨퍼런스 하루 참석으로 인하여 내 실력이 갑자기 뛰어나졌다고 할 수 없지만
앞으로 계속될 나의 개발 인생에 도움이 많이 된 컨퍼런스 였다.

한가지 아쉬운 점은.. 쇼케이스 부스가 부족했었던 것 같다.
스폰서 부스들이 있기는 했지만 뭔가 보여주기에는 너무나도 부족했었다.
내년엔 더욱 더 멋진 자바 개발자 컨퍼런스가 되길...
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by trypsr Trackback 0 Comment 0
* form 의 input 의 type 으로 image 를 주고 거기에 onclick 속성을 적용하면 안됨.
   - submit 이 2번 일어남...

* jakarta commons dbcp 사용시
   - pool.jocl 파일에 주석이라도 한글이 들어가면 아래와 같은 에러발생
ERROR ({http-8080-Processor24} ConvertorProcess.java[process]:41) [2007-02-16 13:42:30,792] - 에러 발생 :
org.apache.commons.dbcp.SQLNestedException: Could not load configuration file

....
....

Caused by: java.io.UTFDataFormatException: Invalid byte 2 of 2-byte UTF-8 sequence.
    at org.apache.xerces.impl.io.UTF8Reader.invalidByte(Unknown Source)
  - Could not load configuration file  메세지만 보고 헛짓 하지 말기...ㅠ.ㅠ
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by trypsr Trackback 0 Comment 1
jdk1.5.0_08 와 jakarta-tomcat-5.0.28 에서 내포하고 있는 w3c dom 의 버전 차이로 인하여 문제가 발생한다.

Node 의 getTextContent() 메소드를 사용하는데

컴파일시에는 jdk1.5.0_08 의 w3c dom 을 사용 하므로 아무이상없이 실행된다.

그러나 Tomcat 으로 실행을 하게 되면 아래와 같이 메소드를 찾지 못한다.
   
java.lang.NoSuchMethodError: org.w3c.dom.Node.getTextContent()Ljava/lang/String;

Tomcat 설치 디렉토리/common/endorsed 디렉토리를 보면 xml-apis.jar 파일이 있는데

Tomcat 실행시에는 xml-apis.jar 의 w3c dom 을 먼저 읽게 되므로 메소드를 못 찾는 현상..

그래서 과감히 xml-apis.jar 를 이동시키면 임시적으로 문제 해결...

더 좋은 해결 방법은 뭐가 없을까??

관련 링크 : http://forum.java.sun.com/thread.jspa?threadID=699041&messageID=4057479
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
TAGjava, XML
Posted by trypsr Trackback 0 Comment 0
선수의 수와 그 선수가 싫어하는 선수의 정보를 입력받아
두 개의 팀으로 구성하여라.

예)
1번째 선수의 정보를 입력하세요(싫어하는 선수의 번호, ...)
3
2번째 선수의 정보를 입력하세요(싫어하는 선수의 번호, ...)
1
3번째 선수의 정보를 입력하세요(싫어하는 선수의 번호, ...)
----------------
A Team : 1
B Team : 2 3

싫어하는 선수가 여러명일 경우 1,2 ... 와 같이 , 로 구분하여 입력받는다.


=================================================================================

나는 아래와 같이 작성하였다.

알고리즘을 생각하는데 많은 시간이 걸렸다..

처음에는 단순하게 for 문 돌리면서 넣었다 뺐다 하면 되겠지 생각했는데...

생각보다 쉽지가 않았다.

코드 작성 초기에는 TDD 도 익힐 겸 JUnit 제대로 적용하고 Exception 처리도 말끔히 해볼까 했는데...

회사에서 눈치보면서 한 것이라 막 코딩이 되어버렸다. ㅠ.ㅠ

그래도 재미있는 문제였다.


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Test{

    private final int POSSIBLE = 1; // 위치한 자리

    private final int IMPOSSIBLE = -1; // 불가 자리

    private final int HOLD = 0; // 빈 자리

    int[] aTeam; // A Team

    int[] bTeam; // B Team

    int[] otherTeam; // Other

    String[][] playerInfo = null; // 싫어하는 선수 정보

    private void doProcess(InputStream is) {
        while (true) {
            System.out.println("선수의 수를 입력하십시요 : ");
            int totalNum = readTotal(is);

            if (totalNum > 0) {

                playerInfo = new String[totalNum][];
                aTeam = new int[totalNum];
                bTeam = new int[totalNum];
                otherTeam = new int[totalNum];
                // 선수 정보 입력
                for (int i = 1; i < totalNum + 1; i++) {
                    System.out.println(i + "번째 선수의 정보를 입력하세요(싫어하는 선수의 번호, ...)\n싫어하는 선수가 없을 시에는 Enter");
                    playerInfo[i - 1] = readPlayerInfo(is);
                }

                makeTeam();
                System.out.println("결과는 다음과 같습니다.");
                System.out.println("A Team : " + printTeam(aTeam));
                System.out.println("B Team : " + printTeam(bTeam));
                System.out.println("Not Team : " + printTeam(otherTeam));
                System.exit(0); // 종료
            } else {
                System.out.println("잘못된 입력입니다.\n 다시 입력하여 주십시요.");
            }
        }
    }

    /**
     * 전체 선수의 수 읽어오기
     * @param is
     * @return
     */
    private int readTotal(InputStream is) {
        String total = null;
        int totalNum = 0;
        try {
            total = readLine(is);
            if ("exit".equalsIgnoreCase(total)) {
                System.out.println("프로그램을 종료합니다.");
                System.exit(0);
            }
            totalNum = Integer.parseInt(total); // 전체 player
        } catch (NumberFormatException nfe) {
            // nothing doto
        }
        return totalNum;
    }

    /**
     * player 정보 입력
     * @param is
     * @return
     */
    private String[] readPlayerInfo(InputStream is) {
        String info = readLine(is);
        return ("".equals(info.trim())) ? null : info.trim().split(",");
    }

    /**
     * make Team
     *
     */
    private void makeTeam() {
        for (int i = 0; i < playerInfo.length; i++) {
            boolean conBoolean = true;

            // aTeam check
            conBoolean = checkTeam(playerInfo[i], aTeam, i);

            if (conBoolean) // aTeam 자격 안되면 bTeam 체크
                conBoolean = checkTeam(playerInfo[i], bTeam, i);

            if (conBoolean) // aTeam, bTeam 둘다 자격 안되면 otherTeam
                otherTeam[i] = POSSIBLE;
        }
    }

    /**
     * Team check
     *
     * @param pInfos
     * @param team
     * @param i
     * @return
     */
    private boolean checkTeam(String[] pInfos, int[] team, int i) {
        boolean retVal = true;
        if (team[i] == HOLD) { // 해당 자리 있을 경우에만
            if (pInfos == null) { // 싫어하는 선수 없으면 현재 team 소속
                team[i] = POSSIBLE;
                retVal = false; // 다음 team 작업 중지
            } else { // 싫어하는 선수 리스트 있으면...
                if (checkHate(team, pInfos)) { // 싫어하는 선수 중에 이미 자리잡은 경우가 있는지 체크, 없을 경우 아래 작업 진행
                    for (int j = 0; j < pInfos.length; j++) {
                        int hateNum = Integer.parseInt(pInfos[j]) - 1;
                        team[hateNum] = IMPOSSIBLE; // 싫어하는 선수의 자리 불가로 표시..
                        team[i] = POSSIBLE; // 현재 team 소속
                        retVal = false; // 다음 team 작업 중지
                    }
                }

            }
        }
        return retVal;
    }

    /**
     * team 에 싫어하는 선수가 자리 잡고 있는지 체크
     *
     * @param team
     * @param infos
     * @return 해당 팀에 들어갈 수 있는지 여부 return
     */
    private boolean checkHate(int[] team, String[] infos) {
        for (int i = 0; i < infos.length; i++) {
            if (team[i] == POSSIBLE) { // 현재 team 에 싫어하는 사람 있는 경우
                return false; // 해당 팀에 들어갈 수 없음
            }
        }
        return true;
    }

    /**
     * InputStream 으로 부터 read Line
     * @param is
     * @return
     */
    private String readLine(InputStream is) {
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);

        String retVal = null;
        try {
            retVal = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("프로그램에 오류가 발생하였습니다.");
            System.exit(1);
        }
        return retVal;
    }

    /**
     * team print
     *
     * @param team
     * @return
     */
    private String printTeam(int[] team) {
        StringBuffer retVal = new StringBuffer();
        for (int i = 0; i < team.length; i++) {
            if (team[i] == POSSIBLE)
                retVal.append(i + 1).append(" ");
        }
        return retVal.toString();
    }

    public static void main(String[] args) {
        System.out.println("프로그램을 시작합니다.");
        Test t = new Test();
        t.doProcess(System.in);
    }
}
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
TAGjava
Posted by trypsr Trackback 0 Comment 0
그동안 귀찬니즘으로 인하여 test 를 멀리했었다.

하지만 이제는 tdd 를 습관화 해봐야지ㅣ

그런데.. 전에 junit 이 4.x 버전 부터 완전히 바꼈다... ㅠ.ㅠ


더 편해졌다고들 하는데.. 전에 봤던 것과 너무 많이 바껴서...ㅠ.ㅠ

그래도 열심히 해봐야지..

testNG 가 junit 보다 더 낫다고 하던데... 나는 그냥 이클립스 기본 플러그인인 junit 4 로 습관화 하기로 했다.
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

'작업공간 > 프로그래밍' 카테고리의 다른 글

모 회사 기출문제 3  (0) 2007.02.08
tdd 를 생활화 하기에 앞서..  (0) 2007.02.05
나 자신을 또 한번 생각하게 만드는...  (0) 2007.02.02
모 회사 기출문제 2  (0) 2007.02.01
Posted by trypsr Trackback 0 Comment 0

무단 복제라...

갑자기 나를 돌아보게 된다.

위 경우와는 좀 다르지만..

솔직히 나는 개발을 하면서 이전 회사에서 개발했었던 소스들을 상당히 많이 참조를 한다.

비슷한 요구 사항이라면 난 항상 내가 이전에 했던 것들에서 힌트를 찾았었는데..

이것도 안되는 걸까?

어디까지 허용되고 어디까지가 불법일까?

프로그래머라는 직업, 참 어려운 것 같다.
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

'작업공간 > 프로그래밍' 카테고리의 다른 글

tdd 를 생활화 하기에 앞서..  (0) 2007.02.05
나 자신을 또 한번 생각하게 만드는...  (0) 2007.02.02
모 회사 기출문제 2  (0) 2007.02.01
모 회사 기출문제  (0) 2007.02.01
Posted by trypsr Trackback 2 Comment 0
2번째 기출문제..

입력받은 알파벳의 합을 구하라.
- A = 1 ~ Z= 26

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

class Test{

    public int calculate(String inputString) {
        int sum = 0;
        for (int i = 0; i < inputString.length(); i++) {
            int charNum = Character.getNumericValue(inputString.charAt(i)) - 9;

            if (charNum > 0 && charNum < 27) {
                sum += charNum;
            }
        }
        return sum;
    }

    public static void main(String[] args) {
        System.out.println("프로그램을 시작합니다.");
        System.out.print(">>");

        while (true) {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            Test t = new Test();

            String inputString = null;
            try {
                inputString = br.readLine();

                if (!"exit".equals(inputString)) {
                    System.out.println("SUM : " + t.calculate(inputString));
                    System.out.println(">>");
                } else {
                    System.out.println("프로그램을 종료합니다.");
                    System.exit(0);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
TAGjava
Posted by trypsr Trackback 0 Comment 0
내가 가고 싶은 회사 중에 하나인 곳의 기출문제 라는데..

나도 한 번 풀어보았다.

나의 풀이가 원하는 정답이 아닐 수 있지만..
나의 코드 스타일이 어떤지 되집어 보고는 싶었다.
뭐 많이 고민하고 구현한건 아니라지만... 역시 맘에 안든다...ㅠ.ㅠ
이런 간단한 것도 맘에 안들어 하는데... 그동안 돈 받고 팔아먹었던 것들은?
후회없는 프로그래밍은 과연 가능할까?



특정 문자열 계산
- 문장을 입력받아 문자열중 bab은 1점, baby는 -2점으로 계산
- 기본점수는 50점
- babbab 과 같이 한 단어에 bab 중복일 경우 한 번만 계산
- babbaby일 경우 bab 과 baby 가 같이 있을 경우 baby만  계산

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

class Test {

    public int calculate(String inputString) {
        int retVal = 0;
        retVal = getWordCount(inputString, "A") * 1 + getWordCount(inputString, "B") * -2;
        return retVal;
    }

    private int getWordCount(String inputString, String gubun) {
        int count = 0;

        String[] inputWord = inputString.split(" ");

        for (int i = 0; i < inputWord.length; i++) {
            if (gubun.equals("A")) {
                if (containsIgnoreCase(inputWord[i], "bab") && !containsIgnoreCase(inputWord[i], "baby"))
                    count++;
            } else if (gubun.equals("B")) {
                if (containsIgnoreCase(inputWord[i], "baby"))
                    count++;
            }
        }
        return count;
    }

    private boolean containsIgnoreCase(String str, String searchStr) {
        if (str == null || searchStr == null) {
            return false;
        }
        str = str.toUpperCase();
        searchStr = searchStr.toUpperCase();
        return str.indexOf(searchStr) >= 0;
    }

    public static void main(String args[]) {

        System.out.println("프로그램을 시작합니다.");
        System.out.print(">>");

        while (true) {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            int point = 50;

            Test t = new Test();

            String inputString = null;
            try {
                inputString = br.readLine();

                if (!"exit".equals(inputString)) {

                    point += t.calculate(inputString);

                    System.out.println("point : " + point);
                    System.out.println(">>");
                } else {
                    System.out.println("프로그램을 종료합니다.");
                    System.exit(0);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
TAGjava
Posted by trypsr Trackback 0 Comment 0
How to be a Programmer: A Short, Comprehensive, and Personal Summary : Robert L. Read 저, 강창기 역

어떻게 공부할까? 프로그래머를 위한 공부론 : 김창준
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by trypsr Trackback 0 Comment 0
* Subversive(SVN 을 위한 Eclipse plugin) 설치
Subversive : http://www.polarion.org/index.php?page=overview&project=subversive

- 설치환경
Eclipse : 3.2.1
Subversive : 1.1.0 RC4

사용자 삽입 이미지
1. Eclipse Top 메뉴에서 Help > Software Updates > Find and Install 선택

사용자 삽입 이미지
2. Install/Update 창에서 Search for new features to install 선택 후 Next

사용자 삽입 이미지
3. Install 창에서 New Remote Site 선택

사용자 삽입 이미지
4. New Update Site 창에 Name과 URL 입력 후 OK
  Name : 해당 사이트에대한 설명
  URL : http://www.polarion.org/projects/subversive/download/1.1/update-site/

사용자 삽입 이미지
5. Install 창에 입력한 Name 생성 확인, 선택 후 Finish

사용자 삽입 이미지
6. 탐색중인 창이 나오고 잠시후 Updates 창이 나옴. Search Result 에서  Subversive 와 Subversive client 선택 후 Next

사용자 삽입 이미지
7. 라이센스 동의를 하고 Next

사용자 삽입 이미지
8. 설치내역 확인후 Next

사용자 삽입 이미지
9. Downloading

사용자 삽입 이미지
10. Install All

사용자 삽입 이미지
11. Installing

사용자 삽입 이미지
12. Eclipse restart

* Repository 추가

사용자 삽입 이미지
1. Window > Open Perspective > Other 선택

사용자 삽입 이미지
2. Open Perspective 리스트에서 SVN Repository Exploring 선택 후 OK

사용자 삽입 이미지
3. SVN Repositories 에서 right click > New > Repository Location

사용자 삽입 이미지
4. New Repository Location 창에서 ROOT URL, User, Password 입력 후 Finish

사용자 삽입 이미지
5. Repository 가 생성 되었음을 알 수 있다.

* Project 공유

사용자 삽입 이미지
1. Project Name 에서 right click > Team > Share Project

사용자 삽입 이미지
2. SVN 선택 후 Next

사용자 삽입 이미지
3. repository location 선택 후 Next

사용자 삽입 이미지
4. Next

사용자 삽입 이미지
5. Finish.

사용자 삽입 이미지
6. List 확인, Comment 작성 후 OK 하면 Project 가 SVN 서버로 Commit 된다.

※ 최초 설치시 SVN Client 는 Subversive Default 인 JavaSVN 방식으로 되어 있다.
그런데 어떤 경우 (정확한 원인은 아직 잘 모르겠음. ㅠ.ㅠ) Malformed Netword Data 라는 오류가 나면서 Commit 이 되지 않는 경우가 있다.
그럴 경우 Native JavaHL 방식으로 변경하면 아무런 문제 없이 되기도 한다.
(그 두방식에 대해서는 잘 모르겠음. 추후 파악 되면 다시 업데이트 할 예정임 ㅠ.ㅠ)
사용자 삽입 이미지

신고
크리에이티브 커먼즈 라이선스
Creative Commons License

'작업공간 > 연장' 카테고리의 다른 글

Subversive(SVN 을 위한 Eclipse plugin) 설치  (0) 2007.01.26
Windows 용 SVN 설치  (2) 2007.01.26
Posted by trypsr Trackback 0 Comment 0
* 설치 환경
 - windows 2003 Server
 - subversion 1.4.2

* Subverion (http://subversion.tigris.org/)  설치

1. Subversion 다운로드 받기
 http://subversion.tigris.org/files/documents/15/35379/svn-1.4.2-setup.exe
    
2. 설치 파일 실행

사용자 삽입 이미지
3. Next

사용자 삽입 이미지
4. accept > Next

사용자 삽입 이미지
5. Next

사용자 삽입 이미지
6. 설치 디렉토리 지정 후 Next

사용자 삽입 이미지
7. 시작 메뉴 생성 여부 확인, Next

사용자 삽입 이미지
8. icon 생성 확인, Next

사용자 삽입 이미지
9. install 정보 확인, Next

사용자 삽입 이미지
10. installing

사용자 삽입 이미지
11. windows Me, 또는 98 의 경우 환경 변수를 추가 해야한다는 안내문. 2000, XP, 2003 의 경우 자동으로 환경변수 선언되므로 Next

사용자 삽입 이미지
12. Finish

13. 환경 변수를 확인하여 보면 APR_ICONV_PATH 라는 변수가 생성되어 있음을 알 수 있다
사용자 삽입 이미지


* Subversion 환경 설정

1. Subversion Data 디렉토리 생성
  자신이 원하는 위치에 SVN 데이터들을 저장할 Directory 를 만들어준다.
  D:\SVN>mkdir Data

2. svn 저장소 생성
  D:\SVN>cd Data
  D:\SVN\Data>svnadmin create --fs-type fsfs test

3. 저장소 생성 확인   (SVN SERVE 를 실행시키지 않아도 file 시스템 접근을 통하여 확인 가능)
  D:\SVN\Data>svn checkout file:///D:/SVN/Data/test
  체크아웃된 리비전 0.
  ※ 저장소가 비어 있으므로 리버전 0 

4. 권한 설정
  D:\SVN\Data\test\conf 밑에  passwd, svnserve.conf 파일 수정

  1) svnserve.conf 수정
   권한 인증 안된 사람들의 권한 (none, read, write 중에 하나 선택)
   anon-access = none
 
   계정 DB 파일 설정
   password-db = passwd

   저장소의 보여줄 이름 설정
   realm = my svn
   ※ 하나의 ID 사용되므로 다른 저장소끼리 같은 이름을 적지 않는 게 좋다.

  2) passwd 수정
   [users] 밑으로 id = password 의 형식으로 사용자를 추가 하면 된다.
   test = test

  ※ 그룹별 관리를 하려면 authz 를 설정하여 주면 된다.

5. svn server start
  D:\SVN\Data>svnserve -d -r D:\SVN\Data
  (-d 옵션은 Deamon, -r 옵션은 Root Directory 지정)
  ※ ROOT Directory 지정시 생성한 저장소의 디렉토리가 아닌 저장소 디렉토리가 있는 Data 디렉토리를 지정해야 함

6. svn server 체크
  D:\>svn checkout svn://localhost/test
  ※ svn 접근은 svn://서버ip/저장소 로 접근한다.

  처음에 시스템의 암호를 묻는 게 나온다. (이유는 잘 ....)
  그다음은 사용자 계정과 암호를 묻는다.

   인증 영역(realm): <svn://localhost:3690> Test
   'Administrator'의 암호:*
   인증 영역(realm): <svn://localhost:3690> Test
   사용자명:test
   'test'의 암호:****
   체크아웃된 리비전 0.

  ※ 현재 저장소가 비어 있으므로 리비전 0 으로 나오면 정상이다.


다음은 svn server 실행을 자동으로 부팅시 작동으로 실행 할 수 있도록 해주는 SVNSERVE manager 에 대한 설명이다.
우리나라 분이 만든 것 같은 데 이런 분들이 있기에 좀 더 편리하게 어플리케이션을 사용 할 수 있지 않나 싶어 너무 감사드립니다.

* SVNSERVE manager(http://www.pyrasis.com/main/SVNSERVEManager) 설치

1. SVNSERVE manager 다운로드
http://www.pyrasis.com/main/SVNSERVEManager?action=download&value=SVNManager-1.1.0-Setup.msi

2. 설치 파일 실행

사용자 삽입 이미지
3. Next

사용자 삽입 이미지
4. SubVersion 설치 디렉토리 밑의 bin 디렉토리 지정 후 Next

사용자 삽입 이미지
5. Next

사용자 삽입 이미지
6. Close

7. Windows 하단에 SVNSERVE Manager 작업 트레이 아이콘 클릭

사용자 삽입 이미지
8. SVN Data 디렉토리 지정후 Start  - 기본 Port 는 3690
  ※ Run Mode 를 Service 로 하게 되면 서비스로 등록되어 서버 부팅시 로그인을 하지 않아도 실행.
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

'작업공간 > 연장' 카테고리의 다른 글

Subversive(SVN 을 위한 Eclipse plugin) 설치  (0) 2007.01.26
Windows 용 SVN 설치  (2) 2007.01.26
Posted by trypsr Trackback 0 Comment 2
간단한 <table><tr><td> 만으로 엑셀만들기...

<@ page contentType="application/vnd.ms-excel; name='My_Excel'">
<%
    response.setHeader("Content-Disposition", "inline; filename=myfile.xls");
    response.setHeader("Content-Description", "JSP Generated Data");
%>

<contentType=text/html>
<contentType=application/vnd.ms-excel>

이 파일 이름이 xxx.jsp라고 하면
링크걸때 /를 붙이고 다운로드하고픈 파일명을 적으면..
<a target='_balnk' href="xxx.jsp/myfile.xls">
라고 하면
myfile.xls라는 이름으로 다운로드가 됩니다.
==============================================================================

<%@ page contentType = "application/vnd.ms-excel; charset=EUC-KR" %>
<%
   String filename;

   filename = new String("한글파일명".getBytes(),"ISO8859_1");
   filename = "report.xls";

   response.setHeader("Content-Disposition","attachment;filename=" + filename +";");
   response.setHeader("Content-Description", "JSP Generated Data");
%>
==============================================================================

# 브라우저에서 엑셀을 띄울때 숫자셀을 텍스트로 나타내기
<td style='mso-number-format:"\@";'>01112344567</td>

# 세자리마다 콤마를 찍고 싶다면
<td style='mso-number-format:"\#\,\#\#0_'>123456789</td>

신고
크리에이티브 커먼즈 라이선스
Creative Commons License
TAGJSP
Posted by trypsr Trackback 0 Comment 0
이 내용도 2년전에 정리했던 것이므로 다를수도 있음.

1. FCKeditor 다운로드
2. FCKeditor.java 다운로드
3. FCKeditor.jar 와 commons-fileupload.jar 추가
4. textarea 를 대신하여 jsp 에 맞게 fckeditor 생성
5. fckconfig.js 수정
6. filemanager 부분 수정
7. web.xml 수정
8. 한글 이미지 파일의 경우 frmupload.html 를 수정하여 한글 이미지 파일을 못 올리도록 한다.
   -> 한글 이름의 파일은 encoding 으로 인하여 에러발생
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by trypsr Trackback 0 Comment 0
2005년에 정리해 놓은 내용 (lucene-1.2 기준)

지금은 lucene.2.0.0 까지 release 된 상태여서 어떻게 변했는지..

귀차니즘으로 인하여 추후 사용할 일 있을 때 수정하겠습니다.


Analyzer 선택

 한글의 경우 가장 많이 사용하는 Analyzer :
org.apache.lucene.analysis.cjk.CJKAnalyzer()
=====================================================================

IndexWriter 생성
IndexWriter(String dir, Analyzer analyzer, boolean create);

create - 인덱싱 정보를 새로 생성할 것인지의 여부. 초기화할때만 true, 그외에는 false 로..

 예제)
 IndexWriter writer = new IndexWriter("C:\\indexDB\test", new org.apache.lucene.analysis.cjk.CJKAnalyzer(), false);
=====================================================================

Document 의 생성 및 저장

Document 는 하나의 행으로 생각
Field 는 한 행의 하나의 필드로 생각

Field 에는 Text, Keyword, UnIndexed, UnStored 의 4가지 타입.

                토큰처리  인덱싱처리    텍스트값저장
Text              O             O                    O
Keyword        X             O                    O
UnIndexed     X             X                    O
UnStored       O             O                    X

Text  - 가장 기본, 기사제목이나 요약정보
Keyword  - URL, 회원ID, 이름등의 고정값 갖고 크기가 작은 텍스트 정보
UnIndexed - 검색결과와 함께 보여줘야하는 정보
UnStored - 게시판의 텍스트, 기사의 본문내용 등 크기가 큰 텍스트 데이터

  ex)
  org.apache.lucene.document.Document doc = new org.apache.lucene.document.Document();
  doc.add(org.apache.lucene.document.Field.Keyword("name", name));
  doc.add(org.apache.lucene.document.Field.UnIndexed("part", "title"));
  doc.add(org.apache.lucene.document.Field.Text("contents", name));

  writer.addDocument(doc); //IndexWriter 에 Document add
=====================================================================

인덱싱 파일 존재 여부

org.apache.lucene.store.Directory fsDir = null;
fsDir = org.apache.lucene.store.FSDirectory.getDirectory(String path, boolean create);
boolean indexing = fsDir.fileExists("segments"); // segments 파일의 존재여부로 indexing 여부 확인
=====================================================================

검색하기

1. IndexSearcher 생성
 org.apache.lucene.search.IndexSearcher is = new org.apache.lucene.search.IndexSearcher(String path);
  => path 는 index 의 위치

2. Analyzer 객체 생성
Analyzer analyzer = new org.apache.lucene.analysis.cjk.CJKAnalyzer();

3. Query 객체 생성
 org.apache.lucene.search.Query qr = org.apache.lucene.queryParser.QueryParser.parse(String query, String field, Analyzer analyzer);

 첫번째 인자 query - 검색어 ex) 검색, 검색*, 검색?, 검색 or 결과 등등
 두번째 인자 field - 검색할 때 사용할 필드명

4. Query 객체를 IndexSearcher 에 전달하여 검색
 org.apache.lucene.search.Hits hits = is.search(Query query);

 ※ Hits 클래스가 제공하는 메소드
 length() - int  - 검색된 문서의 개수
 doc(int n) - Document - 결과 목록에서 위치가 n 인 문서
 id(int n) - int  - 결과 목록에서 위치가 n 인 문서의 ID를 구한다.
 score(int n) - float  - 결과 목록에서 위치가 n 인 문서의 스코어를 구한다.(문서와 검색어 사이의 관련도를 계산)

 ※ Sort 의 경우
 hits = is.search(Query query, new org.apache.lucene.search.Sort("Sort field명"));

 ※ 여러번의 Query 가 필요한 경우
 Query query1 = QueryParser.parse(String query, String field, Analyzer analyzer);  // query1 을 QueryFilter 에 담는다.

 org.apache.lucene.search.QueryFilter queryFilter1 = new org.apache.lucene.search.QueryFilter(query1);

 Query query2 = QueryParser.parse(String query, String field, Analyzer analyzer); 

 // filteredQuery 에 queryFilter1 와 query2를 담는다.
 org.apache.lucene.search.FilteredQuery filteredQuery = new org.apache.lucene.search.FilteredQuery(query2, queryFilter1);

 // filteredQuery 를 QueryFilter 에 담는다.
 QueryFilter queryFilter2 = new QueryFilter(filteredQuery);   

 Query query3 = QueryParser.parse(String query, String field, Analyzer analyzer);

 // 여러 개의 쿼리 적용을 위하여   BooleanQuery 사용
 BooleanQuery booleanQuery = new BooleanQuery();
 // query 를 BooleanQuery 에  ADD
 booleanQuery.add(query3, true, true);
 // queryFilter2 를 BooleanQuery 에  ADD
 booleanQuery.add(queryFilter2 , true, false);   

 Hits hits = searcher.search(booleanQuery, new org.apache.lucene.search.Sort("필드명"));
=====================================================================

인덱스 정보의 삭제 및 변경

1. org.apache.lucene.index.IndexReader 생성
 org.apache.lucene.index.IndexReader reader = org.apache.lucene.index.IndexReader.open(String path);

 IndexReader 는 인덱스 정보를 읽어올때 사용하는 클래스, 사용후 close 해줘야함.
 path 은 lucene 인덱스 정보 패스

2. 삭제하고자 하는 인덱스에 해당하는 Term 객체를 생성
 org.apache.lucene.index.Term term = new org.apache.lucene.index.Term(String filedName, String value)
 첫번째 인자 fileName - 문서의 필드명
 두번째 인자 value - 해당 필드의 값

3. 해당 문서 삭제
 reader.delete(term);
 
인덱스 정보를 변경해 주는 기능은 제공하지 않는다. 삭제후 정보를 추가하는 방식으로..
=====================================================================

쿼리 문자열

String query = "title:jakarta OR tomcat";
org.apache.lucene.search.Query qr = org.apache.lucene.queryParser.QueryParser.parse(query, String field, Analyzer analyzer);
=> query 에 컬럼명: 으로 구별하여 여러개의 컬럼에 대한 검색 가능

와일드카드(*) 는 Analyzer 에 따라 다른 결과가 나올수 있음.
=====================================================================

Analyzer 커스터마이징

- org.apache.lucene.Analyzer 객체와 org.apache.lucene.TokenStream 상속받아 객체 알맞게 구현
- org.apache.lucene.Token 객체 이용
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

'작업공간 > 프로그래밍' 카테고리의 다른 글

FCKeditor(WEB HTML Editor) - JAVA 사용법  (0) 2007.01.09
텍스트 검색엔진 Lucene  (0) 2007.01.09
Ant 주요 사용법  (0) 2007.01.09
Log4J 사용하기  (0) 2006.12.27
Posted by trypsr Trackback 0 Comment 0
아래 내용은
고수로 가는 지름길! Jakarta Project
이클립스 기반 프로젝트 필수 유틸리티: CVS, Ant, JUnit
두 책의 ant 부분을 보고 정리하였습니다.

# build.xml 파일의 기본구조
<?xml version="1.0" encoding="euc-kr"?>
<project name="projectName" default="defaultTargetName" basedir=".">
 <property name="" location=""/>
 <target name="">...</target>
 <target name="" depends="">...</target>
 <target name="" depends="">...</target>  
 <target name="" depends="" if="">...</target>
 <target name="" depends="" unless="">...</target>  
</project>

# project 태그
 1) name : 프로젝트의 이름
 2) default : Ant를 실행할때 target을 지정하지 않은 경우 기본적으로 사용할 target (필수)
 3) basedir : 경로 계산할때의 기준 디렉토리. 지정하지 않은 경우 현재 디렉토리가 basedir로 사용된다. basedir 프로퍼티의 값으로도 사용된다.

# target 태그
 1) name : 타켓의 이름 (필수)
 2) depends : 이 타겟이 의존하고 있는 타겟의 목록. 각 타켓의 이름은 ,(콤마) 로 구분한다.
 3) if : 지정한 프로퍼티가 설정되어 있는 경우 이 타겟을 수행한다.
 4) unless : 지정한 프로퍼티가 설정되어 있지 않은 경우 이 타겟을 수행한다.
 5) description : 타겟이 수행하는 기능에 대한 설명
 
# ant 경로 규칙
 1) * : 0개 또는 그이상의 글자가 매칭
 2) ? : 한글자와 매칭
 3) ** : 다계층을 나타냄  예) dir/**/A => dir/dir1/A, dir/dir2/A, dir/dir1/dirA/A 다 포함.
 4) / 또는 \ 으로 끝날 경우  : /** 또는 \** 과 동일
 
# includes 속성 : 포함시킬 파일의 목록 (include 태그, includesfile 속성으로 사용 가능)

# excludes 속성 : 제외시킬 파일의 목록 (exclude 태그, excludesfile 속성으로 사용 가능)

# excludes 속성 명시 여부에 상관없이 제외 되는 것들 : 제외 시키고 싶지 않을 경우 defaulteexcludes = "no" 설정
 - **/*~, **/#*#, **/.#*, **/%*%, **/._*
 - **/CVS, **/CVS/**, **/.cvsignore
 - **/SCCS, **/SCCS/**
 - **/vssver.scc
 - **/.svn, **/.svn/**
 - **/.DS_Store

# fileset 태그 : 파일 집합
 1) dir : 파일 집합을 표시할 때의 루트 디렉토리 (dir 또는 file 중 한개 반드시 명시)
 2) file : 한 개의 파일을 명시할 때 사용하는 속성  (dir 또는 file 중 한개 반드시 명시)
 3) casesensitive : 대소분자 구분 여부 (true/false) 기본값 true
 4) followsymlinks : 심볼릭 링크를 따라갈지의 여부 (true/false) 기본값 true)
  사용 예)
 <fileset dir="${basedir}/src" defaultexcludes="no">
  <include name="**/*.java"/>
  <include name="**/*.properties"/>
  <exclude name="**/*.bak"/>
 </fileset>

# dir 태그 : 디렉토리 집합
 1) dir : 디렉토리 집합을 표시할 때의 루트 디렉토리 (필수)
 2) casesensitive : 대소분자 구분 여부 (true/false) 기본값 true
 3) followsymlinks : 심볼릭 링크를 따라갈지의 여부 (true/false) 기본값 true)
  사용 예)
 <dirset dir="" includes="" excludes=""/>
 
# patternset 태그 : 재사용 가능한 파일 집합
 사용 예)
 <patternset id="commonJar">
  <include name="servlet.jar"/>
  <include name="mail.jar"/>
  <include name="activation.jar"/>    
 </patternset>
 
 <fileset dir="j2eelib">
  <patternset refid="commonJar"/>
 </fileset>
 
# path 태그 : 재사용 가능한 경로 목록의 집합
 사용 예)
 <path id="project.class.path">
  <pathelement location="fileupload/WEB-INF/classes"/>
  <pathelement path="lib/servlet.jar;lib/commons-fileupload-1.0.jar"/>
 </path>
 
 <classpath refid="project.class.path"/>
 
 - location : 하나의 파일 또는 디렉토리 지정
 - path : 여러 경로를 지정 (; 또는 : 으로 구분)


# 아래의 build.xml 파일에서 ant makeZip 을 할경우 complie 은 두번이 아닌 한번만 실행되게 된다.
 <project name="build" default="makeZip" basedir=".">
  <target name="compile"/>
   <target name="srcCopy" depends="compile"/>
   <target name="classCopy" depends="compile"/>
   <target name="makeZip" depends="srcCopy, classCopy"/>
 </project>

# property 태그 : property 지정
 1) name : 프로퍼티의 이름
 2) value : 프로퍼티의 값을 지정 (name 속성 지정시 value 또는 location 둘중 하나 반드시 사용)
 3) location : 지정한 경로명의 절대 경로명을 값으로 지정 (name 속성 지정시 value 또는 location 둘중 하나 반드시 사용)
 4) resource : 프로퍼티 파일을 읽어 올 때 사용할 자원명을 지정 (name 속성 사용않는 경우 resource, file, environment 중 하나 반드시 사용)
 5) file : 지정한 파일로부터 프로퍼티 목록을 읽어 온다 (name 속성 사용않는 경우 resource, file, environment 중 하나 반드시 사용)
 6) environment : 환경 변수를 읽어 올때 사용할 접두어를 지정 (name 속성 사용않는 경우 resource, file, environment 중 하나 반드시 사용)
 7) classpath : 자원으로부터 프로퍼티 파일을 읽어 올 때 사용할 클래스 패스
 8) classpathref : 클래스패스로 사용할 경로를 path 태그 로 부터 가져온다.
 9) prefix : resource 또는 file 속성을 사용하여 읽어 온 프로퍼티를 참조할 때 사용할 접두어를 지정한다. 만약 접두어 맨뒤에 "." 가 포함되어 있지 않을 경우, 자동으로 "."이 접두어 뒤에 붙는다.
 사용 예)
 <property file="${basedir}/buildprop/global.properties"/>
 
 <property environment="env"/>
 <echo message="JAVA_HOME ${env.JAVA_HOME}"/>

# 기본 프로퍼티 : property 태그 사용하지 않아도 사용 가능한 프로퍼티
 - 모든 자바의 시스템 프로퍼티
 - basedir : 프로젝트의 기본 디렉토리의 절대 경로. project 태그의 basedir 속성에 명시된 값
 - ant.file : 빌드 파일의 절대 경로
 - ant.version : Ant 버전
 - ant.project.name : 현재 실행주인 프로젝트의 이름. project 태그의 name 속성에 명시된 값
 - ant.java.version : Ant 가 발견한 자바 버전.
 
# javac
 1) srcdir : 소스가 위치한 디렉토리 (src 태그로 지정가능. 둘 중 하나 필수)
 2) descdir : 생성된 클래스가 위치할 디렉토리를 지정. javac -d 옵션과 동일
 3) classpath : 컴파일할 때 사용할 클래스패스 (class 태그로 지정 가능)
 4) classapathref : path 태그로 지정한 경로를 클래스패스로 참조
 5) encoding : 소스파일의 인코딩을 지정. javac -encoding 옵션과 동일
 6) nowarn : 컴파일시 -nowarn 옵션 추가 (on) 기본값은 off
 7) deprection : 컴파일시 -deprecation 옵션 추가 (on) 기본값은 off
 사용 예)
 <javac srcdir="" descdir="">
  <classpath>
   <fileset>
    <patternset refid=""/>
   </fileset>
  </classpath>
 </javac>
 
# jar
 1) destfile : 생성할 jar 파일 지정
 2) basedir : jar 파일로 압축할 기본 디렉토리 지정

 사용 예)
  <jar destfile="${disc}/lib/app.jar" basedir="${build}/classes"/>
 
  <jar destfile="${disc}/lib/app.jar">
   <fileset dir="${build}/classes" exclude="**/test*.class"/>
   <fileset dir="${src}/resources"/>
  </jar>

# zip
 - 기본적으로 jar 사용법와 같이 사용 가능.
 - zipfileset 태그를 사용하여 압축되는 파일의 경로명을 변경할 수 있음.
 - zipfileset 의 속성
  1) prefix : ZIP 파일에 압축될 때 변경되어 들어갈 경로명
  2) fullpath : 특정 파일의 변경될 경로를 지정
  3) filemode : 유닉스 기반의 시스템에서 압축되는 파일의 모드를 지정. 기본값은 644
  4) dirmode : 유닉스 기반의 시스템에서 압축되는 디렉토리의 모드를 지정. 기본값은 775
 사용 예)
 <zip destfile="${dist}/example.zip">
  <zipfileset dir="build/api" prefix="docs/api"/>
  <zipfileset dir="${basedir}" includes="chang.log.20031227" fullpath="docs/chagelog.txt"/>
  <zipfileset dir="build/classes" prefix="classes"/>
  <zipfileset dir="build/src" prefix="src"/>
 </zip>

# war
  사용 예)
  <war destfile="main.war" webxml="src/metadata/web.xml">
   <fileset dir="src/mainapp/html"/>
   <fileset dir="src/mainapp/jsp"/>
   <lib dir="lib">
    <exclude name="logging2.jar"/>
   </lib>
   <classes dir="build/main/classes"/>
   <zipfileset dir="src/imagefile/images" prefix="images"/>
  </war>

# tar
 - 기본 사용 법 : <tar destfile="" basedir=""/>
 - tarfileset 태그
 - targileset 의 속성
  1) mode : 3자리 8진수값. 775 등의 값을 갖는다.
  2) username : 파일에 대한 사용자 이름을 지정한다. UID와는 다르다.
  3) group : 파일에 대한 그룹 이름을 지정한다. GID와는 다르다.
  4) prifix : tar 파일에 압축될 때 변경되어 들어갈 경로명
  5) fullpath : 특정 파일의 변경될 경로를 지정
  6) preserveLeadingSlashes : 맨 앞의 '/'를 유지할지의 여부를 지정. 기본값 : false
 사용 예)
 <tar destfile="${dist}/example.tar">
  <tarfileset dir="build/api" prefix="docs/api"/>
  <tarfileset dir="${basedir}" includes="chage.log.20031227" fullpath="docs/chagelog.txt"/>
  <tarfileset dir="build/classes" prefix="classes"/>
  <tarfileset dir="build/src" prefix="src"/>
 </tar>
 <gzip zipfile="${dist}/example.tar.gz" src="${dist}/example.tar"/>
 
 <tar destfile="${dist}/example.tar.gz" basedir="${build}" compression="gzip"/>

# javadoc
 1) sourcepath : 소스 파일의 경로 지정. 하위 디렉토리까지 모두 처리 (sourcepath, sourcepathref, sourcefiles 중 하나는 필수)
 2) sourcepathref : path 에서 지정한 경로를 소스 파일의 경로로 사용 (sourcepath, sourcepathref, sourcefiles 중 하나는 필수)
 3) sourcefiles : 소스 파일의 목록을 지정. 각 파일은 콤마(,)로 구분 (sourcepath, sourcepathref, sourcefiles 중 하나는 필수)
 4) destdir : 결과 파일이 생성될 디렉토리
 5) packagenames : 콤마로 구분된 패키지 파일의 목록. 패키지명이 *로 끝날 경우 그 하위 패키지까지 모두 처리한다.
 6) excludepackagenames : 문서를 생성하지 않을 패키지의 목록을 지정. 각 패키지는 콤마(,)로 구분. 패키지명이 *으로 끝날 경우 그 하위 패키지까지 모두 제외
 7) access : 접근 모드를 지정. public, protected, package, private 중 한 가지 값. 기본값 : protected
 8) public : 생성되는 API 문서에 public 클래스와 멤버만 보여준다.
 9) protected : 생성되는 API 문서에 protected/public 클래스와 멤버만 보여준다.
 10) package : 생성되는 API 문서에 package/protected/public 클래스와 멤버만 보여준다.
 11) private : 생성되는 API 문서에 private/package/protected/public 클래스와 멤버만 보여준다.
 12) encoding : 소스 파일의 인코딩을 명시.
 13) locale : ko_KR과 같이 사용할 로케일을 지정.
 14) charset : 생성된 문서를 보여줄 때 사용할 케릭터셋을 지정.
 15) version : @version 주석을 포함.
 16) author : @author 주석을 포함.
 17) nodeprecated : deprecated 정보를 포함하지 않는다.
 18) nodeprecatedlist : deprecated 목록을 생성하지 않는다.
 19) windowtitle : 문서를 위한 제목을 텍스트로 입력.
 20) overview : HTML 문서로부터 개략 문서를 읽어 온다.
 21) helpfile : 도움말로 사용할 HTML 파일을 지정.
 22) stylesheetfile : 스타일 시트로 사용할 파일을 지정.
 23) header : 생성될 HTML 파일의 헤더로 사용될 HTML 코드를 명시
 24) footer : 생성될 HTML 파일의 풋터로 사용될 HTML 코드를 명시
 
 사용 예)
 <javadoc destdir="{build}/api"
  sourcepath="src"
  packagenames="javacan.main.*"
  excludepackagenames="javacna.main.test.*"
  windowtitle="Main 웹 어플리케이션"
  encoding="euc-kr" />
 
 <javadoc destdir="{build}/api"
  windowtitle="Main 웹 어플리케이션"
  encoding="euc-kr">
  <packageset dir="src" defaultexcludes="yes">
   <include name="javacan/main/**"/>
   <exclude name="javacan/main/test/**"/>   
  </packageset>
 </javadoc>
 
# copy
 1) file : 복사할 파일을 지정 (fileset으로 복사할 파일 목록을 지정하지 않는 경우 필수)
 2) tofile : 복사될 파일을 지정
 3) todir : 원본을 복사할 디렉토리를 지정
 4) overwrite : 기존 파일 덮어쓰기 여부 (true/false) 기본값 : false
 5) preservelastmodified : 원본의 최종 수정 날짜 유지 여부(true/false) 기본값 : false
 6) includeEmptyDirs : 텅빈 디렉토리도 복사할지의 여부(true/false) 기본값 : true
 사용 예)
 <copy file="${workspace}/readme.txt.200312" tofile="${build}/readme.txt"/>
 <copy file="${workspace}/readme.txt.200312" todir="${build}"/>
 <copy todir="${build}/src">
  <fileset dir="${workspace}/src"/>
 </copy>
 
# mkdir
 사용 예)
 <mkdir dir="${build}/webapp/WEB-INF/classes"/>
 webapp/WEB-INF 또한 존재 하지 않는 경우 생성

# delete
 사용 예)
 <delete>
  <fileset dir="${build}"/>
 </delete>
 
 위의 경우 ${build} 와 그 하위 디렉토리의 모든 파일을 삭제. 그러나 디렉토리는 남아있음.(fileset 은 파일의 집합)
 아래와 같이 해주면 디렉토리도 전부 삭제
 
 <delete includeEmptyDirs="true">
  <fileset dir="${build}"/>
 </delete>
 
# ant : 또 다른 빌드 파일의 실행. 여러개의 서브 프로젝트로 구성되어 있을 경우 유용
 1) antfile : 사용할 빌드 파일을 지정. 명시하지 않을 경우 build.xml. dir 속성에 주어진 디렉토리에 대해 상대경로
 2) idr : 새로운 Ant 프로젝트의 basedir을 지정.
 3) target : 수행할 타켓을 지정
 4) output : 새로운 Ant 프로젝트의 수행 결과를 저장할 파일을 명시
 5) inheritAll : 새로운 Ant 프로젝트에 현재 Ant 프로젝트의 모든 프로퍼티 전달 여부(true/false). 기본값 : true
 6) inheritRefs : 새로운 Ant 프로젝트에 현재 Ant 프로젝트의 모든 참조 전달 여부(true/false). 기본값 : true
 사용예)
 <target name="makeSubProject">
  <ant dir="subproject/logging" target="prepare">
   <property name="module1.4" value="jdk1.4"/>
  </ant>
  <ant dir="subproject/common" target="prepare"/>
 </target>

# java
 1) classname : 실행할 클래스 이름 (classname, jar 둘중 하나 필수)
 2) jar : 실행할 jar 파일의 위치 (classname, jar 둘중 하나 필수)
 3) classpath : 사용할 클래스패스를 지정
 4) classpathref : 미리 지정한 path 태그를 참조
 5) fork : 세러은 가상머신에서 클래스 수행 여부 (true/false). 기본값 : false
 6) maxmemory : 포크된 가상 머신에 할당할 메모리의 최대 크기를 지정 (fork가 false인 경우 무시)
 7) dir : 가상 머신을 호출할 디렉토리 (fork가 false인 경우 무시)
 사용 예)
 <java classname="javacan.main.prepare.TableInitilizer">
  <classpath>
   <pathelement path="${java.class.path}"/>
  </classpath>
  <sysproperty key="module" value="test"/>
  <arg value="-init -d"/>
 </java>
 
# native2ascii : 유니코드로의 변환
 1) src : 변환할 파일들이 위치한 기준 디렉토리
 2) dest : 변환한 결과를 저장할 디렉토리
 3) encoding : 변환할 파일의 인코딩 (기본으로 JVM의 기본 인코딩 사용)
 4) reverse : 이스케이프된 유니코드를 지정한 인코딩을 사용하는 문자열로 변환.
 사용 예)
 <native2ascii src="${config}"
  dest="${build}/config"
  includes="**/*.properties"
  excludes="**/test/*.properties"
  encoding="EUC-KR"/>

사용 예제 )


신고
크리에이티브 커먼즈 라이선스
Creative Commons License

'작업공간 > 프로그래밍' 카테고리의 다른 글

텍스트 검색엔진 Lucene  (0) 2007.01.09
Ant 주요 사용법  (0) 2007.01.09
Log4J 사용하기  (0) 2006.12.27
XML을 String으로 변환  (0) 2006.12.27
Posted by trypsr Trackback 1 Comment 0


티스토리 툴바