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

그 동안 iBATIS 를 Oracle 과 mySQL 에서만 사용해 오다가 JDBC를 사용하며 RDBMS이면 거의 다 지원한다고 하는 iBATIS를 믿고 Altibase 와 연동을 해보았다.

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

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

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


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

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

Driver.properitiesName = propertiesValue

그러나 기존의 접두사 방식과 Driver 접두사 를 같이 사용하면 적용이 안된다는 사실...(이건 내부적으로 어떻게 그리고 왜 구분 하는지? 소스 한번 봐? 귀찮다. -.-;)
신고
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

해당 객체의 주소값을 직접 넘기는 게 아닌 객체를 보는 또 다른 주소값을 만들어서 넘기다는 사실을 잊지 말자~
신고
TAGjava
Posted by trypsr Trackback 0 Comment 2

나를 정말 방황하게 만드는 단어들
- 웹2.0, 롱테일, 개인화 서비스

지금의 나를 포기하고 새로운 나를 위해 준비 과정으로 가야하는데....

너무 두렵다..ㅠ.ㅠ
신고
Posted by trypsr Trackback 0 Comment 0
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;
신고
TAGjava
Posted by trypsr Trackback 0 Comment 1
최근들어 블로그 글을 보는 재미에 사는데 오늘도 역시 좋은 글들이 많이 올라와 있군요.

어떤 한 분이 구글 애드센스를 참조(?) 하여 미아찾기 배너를 만들었다고 하시네요.


그걸을 보고 또 한 분은 아이디어를 더 하는군요


꼬리에 꼬리를 무는 아이디어들..

그런데 이런 것도 광고비용을 줘야 하나?

여하튼, 돈을 떠나서....

우리 나라의 열정적인 누리꾼들에 의해
미아찾기 배너 달기 운동 이라도 했으면 좋겠네요~~

나도 얼릉 달아봐야지...
신고
Posted by trypsr Trackback 3 Comment 0


티스토리 툴바