레이블이 Java인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Java인 게시물을 표시합니다. 모든 게시물 표시

2010년 9월 5일 일요일

TypeHandlerCallback 예시

package com.naver.jr.fun.model.quiz.handler;
import java.sql.SQLException;
import org.apache.commons.lang.StringUtils;
import com.ibatis.sqlmap.client.extensions.ParameterSetter;
import com.ibatis.sqlmap.client.extensions.ResultGetter;
import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;
import com.naver.jr.fun.model.quiz.QuizCategory;
public class QuizCategoryTypeHandler implements TypeHandlerCallback {
 @Override
 public Object getResult(ResultGetter getter) throws SQLException {
  String str = getter.getString();
  if (StringUtils.equals(QuizCategory.COMMON.toString(), str)) {
   return QuizCategory.COMMON;
  } else if (StringUtils.equals(QuizCategory.COUNTRY.toString(), str)) {
   return QuizCategory.COUNTRY;
  } else if (StringUtils.equals(QuizCategory.PROVERB.toString(), str)) {
   return QuizCategory.PROVERB;
  } else if (StringUtils.equals(QuizCategory.RIDDLE.toString(), str)) {
   return QuizCategory.RIDDLE;
  } else if (StringUtils.equals(QuizCategory.TEXTBOOK.toString(), str)) {
   return QuizCategory.TEXTBOOK;
  } else if (StringUtils.equals(QuizCategory.TV.toString(), str)) {
   return QuizCategory.TV;
  }
  else {
   throw new SQLException("Unexpceted value " + str + " found. " + QuizCategory.class.toString()
    + " was expected.");
  }
 }
 @Override
 public void setParameter(ParameterSetter setter, Object parameter) throws SQLException {
  switch ((QuizCategory)parameter) {
   case COMMON:
    setter.setString(QuizCategory.COMMON.toString());
    break;
   case COUNTRY:
    setter.setString(QuizCategory.COUNTRY.toString());
    break;
   case PROVERB:
    setter.setString(QuizCategory.PROVERB.toString());
    break;
   case RIDDLE:
    setter.setString(QuizCategory.RIDDLE.toString());
    break;
   case TEXTBOOK:
    setter.setString(QuizCategory.TEXTBOOK.toString());
    break;
   case TV:
    setter.setString(QuizCategory.TV.toString());
    break;
   default:
    throw new SQLException("Unexpceted value found. " + QuizCategory.class.toString() + " was expected.");
  }
 }
 @Override
 public Object valueOf(String str) {
  if (StringUtils.equals(QuizCategory.COMMON.toString(), str)) {
   return QuizCategory.COMMON;
  } else if (StringUtils.equals(QuizCategory.COUNTRY.toString(), str)) {
   return QuizCategory.COUNTRY;
  } else if (StringUtils.equals(QuizCategory.PROVERB.toString(), str)) {
   return QuizCategory.PROVERB;
  } else if (StringUtils.equals(QuizCategory.RIDDLE.toString(), str)) {
   return QuizCategory.RIDDLE;
  } else if (StringUtils.equals(QuizCategory.TEXTBOOK.toString(), str)) {
   return QuizCategory.TEXTBOOK;
  } else if (StringUtils.equals(QuizCategory.TV.toString(), str)) {
   return QuizCategory.TV;
  }
  return null;
 }
}

2010년 8월 5일 목요일

Unitils와 DBUnit 에서 NoSuchColumnException 에러

분명히 DB에 컬럼이 존재함에도 불구하고

Unitils에서 DBUnit를 연동해서 dataset의 내용을 처리할때

아래와 같은 에러가 발생할 경우가 있다.

 

org.dbunit.dataset.NoSuchColumnException

 

이것은 라이브러리 버전의 문제일수도 있다.

 

DBUnit 2.4.7 과 Untils- DBUnit 3.1을 사용했더니 위의 문제가 발생되었다.

DBUnit 의 버전을 2.2.2 로 내리고 나니 해결이 되었다.

(pom.xml에서 빼면 자동으로 2.2.2를 포함한다)

2010년 8월 4일 수요일

java.lang.NoSuchMethodError 에러메시지

간혹 NoSuchMethodError가 발생할 경우가 있다.

 

메소드를 찾지 못해서 발생하는 에러인데

코드상, 라이브러리상에서 전혀 문제가 없는 경우 발생할 때에는

 

주로 classpath상에서 중복되는 class가 있어서 정상적으로 method를

찾지 못해서 발생하는 문제이므로 아래와 같이 조치를 해보자

  1. lib폴더에서 중복되는 jar파일의 존재를 확인한다
  2. maven의 pom.xml파일에서 dependency 부분에서 complict가 발생되는 라이브러리가

    없는지 확인해보도록 하자

 

2010년 7월 25일 일요일

Ant의 FileSet을 Source 이용하기

Apache의 Ant에서는 FileSet라는 파일 및 폴더 관리 방식이 있다.

 

매우 유연하게 폴더 및 파일을 접근할 수 있는데 그부분은 Java 소스에서

 

이용하는 방법을 알아보도록 하자.

 

예제1

  String fileSet = "**/F*.jsp,**/T*.jsp";
  String fileSetExclude = "**/S.jsp";
  File ws = new File("D:/Projects/lucy/text-finder/work/jobs/Test/workspace");
 
        FileSet fs = new FileSet();
        org.apache.tools.ant.Project p = new org.apache.tools.ant.Project();
        fs.setProject(p);
        fs.setDir(ws);  // Root경로를 지정
        fs.setIncludes(fileSet);  //포함할 파일 조건
        fs.setExcludes(fileSetExclude);  //제외할 파일 조건
        DirectoryScanner ds = fs.getDirectoryScanner(p);

        // Any files in the final set
        String[] files = ds.getIncludedFiles();
        if (files.length == 0) {
         System.err.println("FileSet Empty");
            throw new Exception();
        }

        for (String file : files) {
            File f = new File(ws, file);
            if (!f.exists()) {
             System.err.println("Error Find File : " + f);
                continue;
            }
            if (!f.canRead()) {
             System.err.println("Error Read File : " + f);
                continue;
            }
           
            System.out.println("File : " + f.getName());
           
        }

 

 

위의 소스가 간단하기 때문에 쉽게 파악할 수 있을것이다.

 

FileSet의 조건을 주는 방식은 ant의 설명을 참고하길 바라며 콤마(,)를 이용해 다수의 경로조건을 입력할 수 있다.


 

2010년 7월 19일 월요일

Spring Test Context Framework 사용시 Type mismatch 에러

TDD기반의 프로그래밍 중 스프링의 IC를 사용할때 Spring TestContext Framework를 사용하게 된다.

 

그럴 때 편의를 위해서 어노테이션을 사용하게 되는 경우가 많은데

 

아래와 같이 테스트용 메소드 상단에 기록을 하는 것이 일반적이다.

 

@RunWith(SpringJUnit4ClassRunner.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration(locations={"daos.xml"})
public final class HibernateTitleDaoTests {

    // this instance will be dependency injected by type
    @Autowired   
    private HibernateTitleDao titleDao;

    public void testLoadTitle() throws Exception {
        Title title = this.titleDao.loadTitle(new Long(10));
        assertNotNull(title);
    }
}


그런데 이렇게 설정을 해놓고 실행시에 아래와 같은 오류가 발생할 경우에는

 

Type mismatch: cannot convert from Class<SpringJUnit4ClassRunner> to Class<? extends Runner>

 

설치된 JUnit 의 버전을 확인 해보자.

 

JUnit 4.4 이후의 버전을 사용하게 되면 위의 오류는 사라질 것이다.

 

설치된 JUnit 의 버전을 확인 해보자.

 

 

 

또한 위와 같이 Autowire를 설정시에는 꼭 ApplicationConext.xml 파일의 beans 설정에 defalt-autowire속성이 설정되었는지 확인해야 한다.

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" ... 중략 ...  default-autowire="byName">
 <bean id="boardDAO" class="com.naver.bbs.dao.BoardDAOImpl" />
</beans>


 

 

 

 

2010년 7월 12일 월요일

JDBC와 DAO

JDBC

 

 1. Java DataBase Connectivity
  - 자바의 표준 DB접속 방법
  - DataBase와 독립적인 구현
 
 2. JDBC Driver Type
  - type1 : JDBC-ODBC 브리지(UserCode -> JDBC -> JDBC-ODBC -> ODBC -> DB)
  - type2 : native API Driver (UserCode -> JDBC -> DB library(native) -> DB)
  - type3 : network-protocol driver (UserCode -> JDBC -> DB Midleware -> DB)
  - type4 : native protocol driver (UserCode -> JDBC -> DB)
  
 3. JDBC Spec.
  - 커넥션, SQL 질의 및 파라미터, 결과의 수신,
  - 기본 매핑(SQL Type & Java Type), 메타데이터 제공, 트랜잭션, 로깅 등
  
 4. 커넥션 방법
  - DriverManager로 접속하는 방법
    Driver 로딩 : Class.forName("com.driver.class.name");
    DriverManager로 커넥션 획득 : DriverManage.getConnection("접속정보");
   
  - javax.sql.DataSource(JDBC 2.0)
    WAS start(DataSOurce Configuration) -> Referenceable -> JNDI
    Context.lookup(UserCode <-> JNDI <-> DataSources)
    DataSource.getConnection(UserCode <-> DataSource)
   
  - PooledDataSource
    UserCode <-> Pooled Connection <-> ConnectionPool <-> PoolingDataSource

 

Data Access Layer

 

 1. DAO FrameWorks
   - JDBC Templates
   - SQL Mappers
   - OR Mappers
  
 2. JDBC Templates
   자주 사용하는 표준적인 DB접근, 질의 등을 템플릿 형태로 사용함
   장점 - 쉽다, 설정필요이 따로 필요 없다
   단점 - 코드안에 모든내용포함 된다, 코드가독성이 낮다, DB 의존적이다
  
 3. SQL Mappers
   쿼리 등을 외부로 빼내고 쿼리에 대한 결과를 매핑해주는 기능으로 bean에 결과를 매핑한다.
   장점 - 코드가 줄어듦, 배우는게 쉽다, 코드와 쿼리가 분리된다
   단점 - XML설정이 필요하다, DB에 의존적이다
  
 4. OR Mappers
   테이블의 Row를 하나의 객체로 인식하고자 함
   설정을 통해서 테이블과 클래스, Row와 인스턴스를 연결하고 객체만을 사용
   장점 - 코드가 줄어듦, 직관적이다, 쿼리와 DB의존적이지 않다
   단점 - XML설정이 필요하다, 배우기 어렵다
  

2010년 1월 21일 목요일

Android 에서 Handler와 Message 란?

Android(안드로이드) 개발시 사용되는 Handler(핸들러)와 통신에 사용되는 Message(메시지)에 대해서 알아보자.

 

핸들러란?

 

안드로이드의 시스템은 사용자가 작성한 UI에서 빠른 응답을 요구하고 있다.

만약 5초 이상의 응당이 없을 경우 최악의 경우 작성된 프로그램이 강제로 종료가 되는 경우도 발생할 수 있다.

이런 상황을 방지하기 위해서 시간이 오래걸리는 작업이 필요한 경우 두가지의 방법으로 해결을 할 수 있다.

첫번째는 시간이 오래걸리는 작업은 서비스로 만들어서 처리하는 방법

두번째는 새로운 쓰레드로 처리를 하는 방법

 

두번째 방법으로 쓰레드를 생성해서 데이터 처리등의 시간이 오래걸리는 작업을 지원하기 위한 클래스가 존재하는데 그것이 핸들러(Handdler)이다.

 

간략하게 요약을 해보면

  • 백그라운드 쓰레드 생성을 위한 가장 유연한 방법이다.
  • 인스턴스 생성시 자동으로 안드로이드가 실행 관리한다.
  • 메시지를 전달받게 되면 호출 되는 handlerMessage()에 실제 처리내용을 구현한다.
  • post(), postDelayed()를 통해서 인자로 실행하고 자하는 Runnable객체를 전달할 수 있다.
  • View단에도 Runnable객처를 인자로 전달가능하고 이럴경우 코드가 심플해지는 경우도 있을수 있지만 Handler를 추천한다.

 

 

메시지(Message)란?

 

UI등에서 실제로 처리를 담당하는 쓰레드로 데이터를 전송하거나 작업을 요청하기 위해서 전달하는 객체이다.

 

  • 핸들러로 전달되는 객체이다.
  • 전달된 메시지는 메시지 Queue를 통해서 핸들러가 가져다 사용한다.
  • 메시지를 전달하기 위해선 핸들러의 obtainMessage()호출해서 메시지 풀의 메시지를 획득해서 전달해야한다.
  • 메시지를 전달하기 위해서는 sendMessage() 등을 사용한다.

 

메시지 전달 방식의 종류

  • sendMessage() - 큐의 마지막에 메시지를 삽입한다.
  • sendMessageAtFrontQueue() - 큐의 맨앞에 메시지를 삽입한다.(우선처리)
  • sendMessageAtTime() - 장비기동시간을 기준으로 삽입한다.(SystemClock.uptimeMillis()참고)
  • sendMessageDelayed() - 특정시간만큼 지연 삽입한다.

 

 

2009년 12월 31일 목요일

에뮬레이터(Emulator) 기동시 AVD 에러 해결방법

안드로이드(Android) SDK를 설치하고 에뮬레이터를 기동시에

아래와 같은 에러가 나타나는 경우가 있다.

 

emulator: ERROR: unknown virtual device name: 'Test-AVD'
emulator: could not find virtual device named 'Test-AVD'


 

위와 같은 문제는 에뮬레이터와 안드로이드 툴킷의 설정 문제이다.

 

위와 같은 상황일때에는 Win+R 을 눌러서 Cmd명령을 입력해서

커맨드 창을 열고

echo %USERPROFILE% 를 입력해서 출력되는 내용을 보면

필자는 아래와 같이 C드라이브로 설정되어 있고

 

실제로 사용하고 있는 유저의 프로파일 경로는 아래와 같이 E드라이브를 사용하고 있다.

 

에뮬레이터는 C로 만들어진 어플리케이션으로 %USERPROFILE%를 참고해서 AVD를 찾고

안드로이드툴은 Java로 만들어진 어플리케이션으로 실제 사용중인 프로파일 경로의 .android

폴더를  참조하게 된다. 이러한 차이로 AVD를 찾지 못하는 것이다.

 

이것을 해결하기 위한 방법은 여러가지로 제시가 되고 있지만 최고의 방법은

 

아래와 같이 환경변수에 ANDROID_SDK_HOME을 설정하는 것이다.

 

위와 같은 설정을 하게 되면 .android폴더가 지정한 경로의 하위 폴더로 설정되어 AVD들이

동일한 곳에 저장되어 툴킷과 에뮬레이터가 같은 곳을 참조하게 되므로

문제를 해결할 수 있다.

 

2009년 10월 27일 화요일

JDK5의 새로운 기능 - 1부. 비정형인자(Varargs)

과거 JDK2버전부터 개발해온 입장에서 항상 새로운 JDK가 릴리즈되면

무엇이 차이인지 궁금한 마음에 이것 저것 찾아보았지만

막상 JDK5의 기능으로 구성된 소스들을 보게 되면 아리송한 내용이 많았다.

그래서 정리를 해보도록 하겠다.

 

1부 비정형인자(Varargs)

 

개발을 하다보면 메소스 생성시 인자의 수가 정해지지 않은 메소드가 필요할 경우가 있다.

보통은 이런 경우에 Set나 Map, List 등의 Collection을 이용해서 인자로 전달하게되는데

Collection들의 경우 전달하는 측에서 Instance를 생성해야한다는 불편과 더불어

처리하는 쪽에서도 Casting을 해야하는 불편이 있다.

(Casting문제는 다음편에 다룰 제너릭에서 답을 구할 수있다)

 

JDK5에서는 이러한 불편함을 해소하기 위해서 임의의 수의 인자를 전달하는 선언이 가능하게 되었다.

 

인자로 받는 수를 더해주는 add 라는 메소드가 필요할 경우

 

//JDK 1.4 이전

List args = new ArrayList();

args.add(10);

args.add(11);

args.add(12);

add(args);

 

public int add(List args) {

  int sum = 0;

  for(Iterator iter=args.iterator(); iter.hasNext(); ) {

    int arg = (Integer) iter.next();

    sum += arg

  }

  return sum;

}

 

//JDK 5

add(10,11,12);

public int add(int... args) {
  int sum = 0;
  for(int arg : args) {
    sum += arg;
  }
}

 

대단히 간편하게 인자의 수를 지정할 수 있다.

 

한가지 주의해야할 점은

비정형 인자도 다수의 인자와 함께 사용이 가능하지만 인자 선언부에서

비정형인자는 마지막에 단 한번만 사용할 수 있다.

 

public int add(String a, int... args) //올바른 선언(O)
public int add(int... args, String a) //잘못된 선언(X), 비정형인자가 마지막이 아님
public int add(int... args, String... a) //잘못된 선언(X), 비정형인자가 두번 사용됨

 

 

2009년 9월 30일 수요일

Google App Engine(GAE)를 사용하자 -1부

Google App Engine (이하 GAE)가 무엇인가?

gae는 직접 개발한 web application을 구글의 인프라에서 운영이 가능하게 한다.
단지 application을 upload하는 것만으로
쉽게 만들고, 쉽게 유지보수하고, 특히 쉽게 트래픽과 데이터 스토리지를 확장할 수 있다.

개별적인 도메인(물론 자신가 보유한)을 사용할 수도 있고 appspot.com이라는 도메인의 서브도메인을 사용할 수도 있다.

또한 Java 런타임 환경을 제공해 줌으로 JVM을 포함한 Servlet 등을 사용할 수 있다.

GAE는 초기 구축 비용이 들지 않으며, 리소스(스토리지,대역폼)등은 기가바이트 단위로 측정된다.
그리고 자금한도내에서 최대 리소스의 양을 조절할 수 있따.

처음 GAE를 구축하게 되면 500M의 스토리지와 충분한 CPU자원이 할당이 되며 월 5백만페이지뷰를 커버할만한 대역폭이 주어지며 무료이다.
그리고 대역폭을 넘어서는 리소스에 대해서만 합당한 비용을 지불하면 된다.

어플리케이션의 환경

GAE는 많은 부하와 큰 데이터를 신뢰성있고 쉽게 운영이 가능하다.
GAE는 다음과 같은 특징을 가지고 있다.

  • 일반적인 web 기술을 전부 사용가능한 동적 web 서비스
  • 쿼리, 정렬, 트랜잭션이 가능한 저장공간
  • 자동으로 처리되는 확장과 로드밸런싱
  • Google 계정을 이용한 이메일 송수신을 위한 API
  • 완벽하게 로컬 PC에서 개발가능한 환경
  • 웹상의 요청이 아닌 작업이 처리가능한 task queue
  • 특정시간이나 일정한 주기로 스케줄되어져서 실행이 가능한 작업

샌드박스

application은 운영체제로의 접근이 제한된 보안 환경에서 작동된다. 이러한 제한은 GAE가 다수의 서버에서 웹 요청을 처리하는것과 요청이 있을때만 서비스를 기동시키는 것이 가능하게 한다. 샌드박스는 application을 하드웨어와 운영체제 및 서버의 위치에서 독립된 보안되고 안정적인 환경으로 구별지어 준다.

자바환경

일반적인 Java API의 환경에서 자바 개발이 가능하다. JSP를 포함한 표준 Servlet 환경을 사용할 수 있다.
Java runtime은 Java 6를 사용하며 GAE Java SDK는 Java 5 와 6에서의 개발을 지원한다.

기본적으로 개발환경은 JRE 6을 포함하고 있다. 샌드박스 환경에서의 제약은 JVM에서 구현된다는 것이다.
모든 app는 샌드박스의 제약을 벗어나지 않는 한도내에서  라이브러리나 JVM bytecode를 사용할 수 있다.
예를들어 소켓을 열거나 파일을 저장하려는 bytecode는 runtime exception이 발생한다.