Whiteship's Note

'2008/07'에 해당되는 글 98건

  1. 2008.07.31 Mockito - Verifying exact number of invocations / at least once / never
  2. 2008.07.31 Mockito - How about some stubbing?
  3. 2008.07.31 이클립스 타겟 플랫폼에 Spring DM 번들 돌리기
  4. 2008.07.31 20080731 GMP
  5. 2008.07.31 FLV 파일 합치기 (4)
  6. 2008.07.31 맥북에서도 Spring DM 웹 번들 설치 성공
  7. 2008.07.30 5시에 들어온 미션~
  8. 2008.07.30 assertThat()으로 null 여부 확인하기
  9. 2008.07.30 하이버네이트 Criteria 다루기 - 중복일까 아닐까 (2)
  10. 2008.07.30 20080730 GMP
  11. 2008.07.29 Spring DM 1.1.1 배포
  12. 2008.07.29 ItemReader - Spring Batch Chapter 3 (7)
  13. 2008.07.28 The Domain Language of Batch - Spring Batch Chapter 2 (4)
  14. 2008.07.28 혹시 "빠삐놈"을 모르시나요?
  15. 2008.07.28 로컬에서는 무사히 빌드가 되는데, 왜 서버로 올라가서 CI가 돌리면 컴파일 에러가 날까
  16. 2008.07.28 메이븐 플러그인 탐험기1 - UMLGraph
  17. 2008.07.28 20080728 GMP
  18. 2008.07.26 JSF 기초 2
  19. 2008.07.25 도메인 질렀습니다. 이제부터 whiteship.me는 내꺼 (2)
  20. 2008.07.24 JSF 기초 1
  21. 2008.07.24 20080724 GMP
  22. 2008.07.24 Maven 2.0.10 배포 임박!!! (8)
  23. 2008.07.23 맥에서 mov 파일 swf로 인코딩하기
  24. 2008.07.23 텍스트박스에서 엔터키 누르면 ~~~하기
  25. 2008.07.23 log4j 설정 파일 위치를 명시적으로 설정하고 싶을 때.. (5)
  26. 2008.07.23 바코드를 출력 및 읽기 코딩할 때 주의할 것
  27. 2008.07.23 스프링 DM 모듈에서 단위 테스트하기(링크)
  28. 2008.07.22 불신자를 위한 JSF 시리즈
  29. 2008.07.21 20080721 GMP
  30. 2008.07.21 닷넷에서 웹 서비스 참조하기

Mockito - Verifying exact number of invocations / at least once / never

모하니?/Coding : 2008.07.31 17:59


Mockito 사용해서 정확한 메소드 호출 횟 수 / 최소한 한 번 / 전혀~ 한 번도 호출 안했는지 검증하기

  //mock 사용하기
  mockedList.add("once");
 
  mockedList.add("twice");
  mockedList.add("twice");
 
  mockedList.add("three times");
  mockedList.add("three times");
  mockedList.add("three times");
 
  //다음 두 번의 검증은 똑같다. 기본으로 times(1)를 사용하기 때문에..
  verify(mockedList).add("once");
  verify(mockedList, times(1)).add("once");
 
  //정확한 호출 횟 수 검증
  verify(mockedList, times(2)).add("twice");
  verify(mockedList, times(3)).add("three times");
 
  //neber()를 사용한 검증, times(0)과 같다.
  verify(mockedList, never()).add("never happened");
 
  //atLeastOnce()를 사용한 검증
  verify(mockedList, atLeastOnce()).add("three times");
 
Whiteship's Exercise

EasyMock Code

    @Test
    public void delete() {
        Member member = new Member();
        mockDao.delete(member);

        replay(mockDao);

        service.delete(member);

        verify(mockDao);
    }

Mockito Code

    @Test
    public void delete() {
        Member member = new Member();
        service.delete(member);
        verify(mockDao).delete(member);
    }



신고
top

TAG Mockito

Mockito - How about some stubbing?

모하니?/Coding : 2008.07.31 17:25


참조 : http://mockito.googlecode.com/svn/branches/1.4/javadoc/org/mockito/Mockito.html

 //인터페이스가 아니라, 클래스의 mock 객체도 생성할 수 있다.
//easymock 보다 편하군요. easymcok은 extention 라이브러리를 설치해야 사용할 수 있죠.
 LinkedList mockedList = mock(LinkedList.class);
 
 //Stubbing
 stub(mockedList.get(0)).toReturn("first");
 stub(mockedList.get(1)).toThrow(new RuntimeException());
 
 //"first"를 출력할 것이고..
 System.out.println(mockedList.get(0));
 
 //RuntimeException을 던질 것이고..
 System.out.println(mockedList.get(1));
 
 //get(999)는 stubbing 하지 않았으니까 "null"을 출력할 겁니다.
 System.out.println(mockedList.get(999));
 
 //Stubbing 한 호출들은 암묵적으로 검증을 합니다. 여러분이 원하는 예외적인 흐름 상 해야만 한다면 해도 상관없습니다.
 //명시적으로 스텁 호출을 검증하는게 가능하긴 한데, 대부분의 경우 그럴필요까진 없습니다.
 verify(mockedList).get(0);

  • 기본적으로, 반환 값이 있는 모든 메소드들은, mock은 null을 반환하거나, 비어있는 콜렉션 또는 적절한 primitive 값을 반환합니다.(e.g: 0, false, ... for int/Integer, boolean/Boolean, ...).
  • 스텁 작업은 오버라이딩 할 수 있습니다. 예를 들어, 스텁으로 fixture를 만들어 둘텐데 그걸 테스트 메소드내에서 재정의할 수 있습니다.
  • 한 번 스텁을 만들어 두면 mocking한 메소드는 몇 번을 호출하든 상관없이 항상 스텁 값을 반환합니다.
  • 같은 메소드를 여러번 스텁 했을 때는 마지막에 스텁한 녀석이 더 중요합니다.
  • 명시적으로 스텁 호출을 검증하는 것이 가능하긴 한데, 대부분의 경우 불필요 합니다. 스텁 호출은 암묵적으로 검증을 합니다. 여러분이 작성한 코드의 실행 흐름에 따라 알아서 해줄 겁니다.

EasyMock Code

    @Test
    public void get() {
        int id = 1;
        Member member = new Member();
        member.setId(id);
        expect(mockDao.get(id)).andReturn(member);
       
        replay(mockDao);
       
        assertEquals(member, service.get(id));
       
        verify(mockDao);
    }

Mockito Code

    @Test
    public void get() {
        int id = 1;
        Member member = new Member();
        member.setId(id);

        stub(mockDao.get(id)).toReturn(member);
       
        assertThat(service.get(id), sameInstance(member));
    }


흠 오늘은 service 패키지 테스트들을 전부 Mockito로 바꿀려고 했는데, 오늘 안엔 다 못하겠군요. 오늘은 Mockito나 좀 더 공부하고 내일까지 해야겠네요.
신고
top

TAG Mockito

이클립스 타겟 플랫폼에 Spring DM 번들 돌리기



어때요. 참 쉽죠?
신고
top


20080731 GMP

모하니?/GMPing : 2008.07.31 09:42


News

stamp 승인
sue 쑤: 고소하다
products 프로닥츠

The federal trade commission(FTC) wants tobacco compannies to remove its stamp of approval for those tests. The proposal could open the door for the FTC to sue companies that call their products light or raw tar.

Screen English

I see her every day. I see her in your goodnees Jein, and Kera your passion, and Rilly your eyes and your smiles. So here is what I'm going to do. I'm grounding myself here for life. I'm sticking with you. I'm gonna be with you.

Pop's English

See your pretty face in the sunshine.
In the morning after staying up all night.
I want to wake you. just here you tell me. "It's all right"

Talk Play Learn

I want you to (네가 ~ 해주길 바래)
I want you to join us.
I want you to know this.
I want you to promise me.
I want you to quit smoking.
I want you to remember me.
I want you to practice more.
I want you to take a message.
I want you to have confidence

Learn More

끝마치다. 포장하다. = wrap up
Would you wrap this up as a gift?
Lets's wrap up the meeting.

신고

'모하니? > GMPing' 카테고리의 다른 글

20080821 GMP  (0) 2008.08.21
20080819 GMP  (0) 2008.08.19
20080813 GMP  (0) 2008.08.13
20080807 GMP  (0) 2008.08.07
20080801 GMP  (0) 2008.08.01
20080731 GMP  (0) 2008.07.31
20080730 GMP  (0) 2008.07.30
20080728 GMP  (0) 2008.07.28
20080724 GMP  (0) 2008.07.24
20080721 GMP  (0) 2008.07.21
20080718 GMP  (0) 2008.07.18
top

TAG GMP

FLV 파일 합치기

Good Tools : 2008.07.31 08:19


스크린캐스팅과 관련되서 점점 달인이 되가는 기분입니다. 녹화 툴, 인코딩 툴, 이제는 동영상 파일 편집까지...ㄷㄷㄷ.. 한 방에 튜토리얼을 녹화했더니, 30분 가까이 되는 영상이 나와서, 다시 녹화를 했습니다. 좀 빠르게 진행을 해서 26분짜리가 나왔는데, 파일 용량이 너무 커서 스트리밍하는데 문제가 있었습니다. 그래서 이번엔 튜토리얼의 세부 실습 메뉴 9개에 따라 9개로 나눠서 녹화를 했습니다. 이 순간.. 그래 이거야. 내가 왜 통짜로 녹화해서 고생을 했지.. 디바이드 앤 퀀쿼!! 통짜로 녹화하는 것 보다 Export나 Encoding이 훨씬 편했습니다. 하지만... 너무 파일이 많아서 링크 클릭하기가 귀찮다는 -_-;;; 그렇다고 다시 녹화하기에는 이미 충분히 시간을 소비한 프로젝트였습니다.

그냥 합치자!!..

그래서 구글링을 통해 찾아낸 툴이 avidemux. 무료지만, 아주 편하고 쉽게 flv 파일들을 붙여줍니다.

사용자 삽입 이미지

간단하게 file -> open으로 첫 번째 파일을 열고, 그 뒤에 붙일 파일은 file -> append로 열면 됩니다. 그럼 맨 아래 왼쪽 Time에 전체 시간이 표시 되는데, 그걸 보면서 적정량을 붙여주시면 됩니다.

그다음 save 하면.. flv 파일로 저장이 됩니다. 시간도 오래 안걸리고 좋았습니다.
신고
top

TAG avidemux, FLV

맥북에서도 Spring DM 웹 번들 설치 성공

Spring DM/exercise : 2008.07.31 00:03


인증샷 1. 번들 목록

사용자 삽입 이미지

인증샷 2. simple-web-app 첫 화면

사용자 삽입 이미지
인증샷 3. 서블릿

사용자 삽입 이미지
인증샷 4. JSP는.. 또 실패;;

사용자 삽입 이미지
흠... 리소스가 제대로 등록이 안 되있는건지.. 원인을 좀 찾아봐야겠습니다.


맥북에서 Spring DM 웹 번들 돌린게 왜 기쁘냐면요;; 안 해보신 분들은 몰라요... 윈도에서 돌리는 Equinox(줄여서 윈E)랑 맥에서 돌리는 Equinox(맥E)가 좀 차이가 나는 것 같습니다. 버그 같은데, 그게 맥E 의 버그인지, Spring DM web extender의 버그 인지, catalina의 버그인지 도통..잘 모르겠습니다.

spring web extender가 catalina 번들이 제공하는 서비스를 필요로 하는데, 만약에 catalina 보다 먼저, start 시키면 당연히.. resolved 상태로 못가고 해당 서비스가 들어올 때까지 좀 기다립니다. 그러다가 특정 시간이 되면 타임되서 넘어갑니다. 이게 정상이죠. 윈E에선 이렇게 정상적으로 동작합니다. 그래서 설치할 번들 목록에서 spring web extender 가 catalina 보다 위에 있어도(즉 먼저 start를 시도하겠죠.) 상관없습니다. 기다리다 보면, 다른 번들들 모두 Active 상태가 되고, spring web extender만 Resolved 상태로 남아있습니다.(catalina도 Active 상태가 됐으니 web extender가 필요로 하는 서비스가 제공 되서 상태가 변한겁니다.) 그러면... 이제 web extender만 다시 start 명령어로 Active 상태로 만들어 주면 됩니다.

하지만.... 맥E에선, 한 번 해보세요~ 해보셨어요? 안 해보셨으면 말을 하지마세요.

사용자 삽입 이미지
사용자 삽입 이미지


참.. 테스트 환경은. Eclipse 3.4. Spring DM 1.1.1 입니다.

ps: Bad case에 걸렸을 때 Good case를 찾아 빠져 나가는 방법이 있긴 있는데.. 그건 비밀입니다. 캬캬캬
신고
top


5시에 들어온 미션~

모하니?/Coding : 2008.07.30 17:57


1. 상품 그리드에 $ 가 보이는데, 찾아서 없애기
2. 상품 정보 엑셀로 업로드 했더니, 바코드가 설명 필드로 들어가버렸네. 수정.
3. 바코드 유/무 검색 조건이 이상하게 말을 잘 안 듣네.

미션이 들어온 시간은 5시 1분, 지금은 5시 47분.

1. $ 찾아서 없애기
우선 상품 그리드 말고 다른 그리드에도 저 $가 보이는지 몇 개 걸쳐가며 확인해본 결과, 상품 그리드에만 표시가 되고 있음. 그래서 IE에서 소스 보기 누른 다음, Ctrl+F로 $를 찾아봤더니, EL들 몇 개 지나가고, 맨~~~ 아래 </html> 이 끝나고 $ 하나가 썰렁하게 놓여있는거 발견!! 이클립스에서 Ctrl + Shift + R 눌러서 해당 JSP 찾아간 다음에 맨 아래에서 $ 삭제.

2. ExcelUpload 구현한 메소드로 들어가서, 엑셀 컬럼 읽어서 객체에 세팅하는 부분 발견. 코드를 보니까, 바코드 필드가 설명 필드 앞에 추가가 되서, 발생한 문제, 양식함에 만들어둔 양식에는 바코드 필드가 없어서 괜찮을 줄 알았는데, 그리드에서 바로 엑셀 다운로드 한 담에 그걸 양식삼아서 업로드 하느라 발생한 문제. 이 경우는 "양식함이 그리드와 똑같다" 라는  "사용자 경험" 때문에 나온 것이므로 이 경험을 유지시켜주기 위해서 양식함과 업로드 로직을 수정하는게 좋을 듯 싶어서. 후다닥 작업. 테스트.

3. 바코드 유/무는

if(params.getHasBarcode() == YesNoType.YES)
   c.add(Restrictions.isNotNull("suppbarcode"));
else if(params.getHasBarcode() == YesNoType.NO)
   c.add(Restrictions.isNull("suppbarcode"));

이렇게 코딩을 해놨는데, 썩 좋치가 않았구나. 해당 필드가 엑셀에서 읽어와서 null 이라아니라 그냥 공백 "" 경우에는 조건에 제대로 안걸려서 무조건 전부 not null 이니.. 이건 뭐.. 어떻게 할까 잠시 고민...
Exel에서 읽을 때 공백이면 null로 채워주는 메소드를 ExcelUtil에 하나 추가하고 바코드는 그걸로 읽어오자. 캬캬.

끝~~
신고
top


assertThat()으로 null 여부 확인하기

모하니?/Coding : 2008.07.30 14:34


JUnit 4.4 전에는 assertNotNull(dao); 이런식으로 확인했었습니다.

그러나 4.4부터 assertThat()을 사용해서 다음과 같이 테스트 할 수 있습니다.
assertThat(dao, is(notNullValue()));

여기서 is를 빼면 어법이 좀 그렇긴 하지만.. 그래도 동작합니다.
assertThat(dao, notNullValue());

처음엔 이렇게 작성했었습니다.
assertThat(dao, is(not(null));

하지만 위에 코드는 안 됩니다. null이 값이 아니기 때문에, 값 비교 하는데 null 때문에 NullPointerException이 발생합니다.

Maven을 사용하고 계시다면..

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.4</version>
        </dependency>

        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-library</artifactId>
            <version>1.1</version>
        </dependency>

이렇게 라이브러리를 추가해주신 다음에 해야 합니다. static import를 추가해두면 편하겠죠.

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

신고
top


하이버네이트 Criteria 다루기 - 중복일까 아닐까

모하니?/Coding : 2008.07.30 13:31


    @Override
    public List<T> search(P params, OrderPage orderPage) {
        // total rowcount
        orderPage.setRowcount((Integer) (addRestrictions(
                getSession().createCriteria(this.persistentClass), params)
                .setProjection(Projections.rowCount()).uniqueResult()));

        // pages list
        Criteria c = addRestrictions(getSession().createCriteria(
                this.persistentClass), params);
        orderPage.applyPage(c);
        orderPage.applyOrder(c);

        return c.list();
    }

    /**
     * template method for search
     *
     * @param c
     * @param params
     * @return
     */
    protected Criteria addRestrictions(Criteria c, P params) {
        return c;
    }

위 코드에서 중복이 보이시나요? 안 보이신 다구요?

    @Override
   public List<T> search(P params, OrderPage orderPage) {
       // total rowcount
       orderPage.setRowcount((Integer) (addRestrictions(
               getSession().createCriteria(this.persistentClass), params)
               .setProjection(Projections.rowCount()).uniqueResult()));

       // pages list
       Criteria c = addRestrictions(getSession().createCriteria(
               this.persistentClass), params);
       orderPage.applyPage(c);
       orderPage.applyOrder(c);

       return c.list();
   }

어떤가요. 중복 이죠? 그러나..

Criteria c = addRestrictions(getSession().createCriteria(
               this.persistentClass), params);
orderPage.setRowcount((Integer) (c.setProjection(Projections.rowCount()).uniqueResult()));
orderPage.applyPage(c);
orderPage.applyOrder(c);

대강 이런 식으로 리팩터링 해보면 하이버네이트는 요상한 쿼리와 함께 에러를 뱉어냅니다.

전체 Row 갯수를 반환하는 Criteria(쿼리는 select count(*).. )이런식으로 시작)를 다시 Order와 Page 처리를 할 때 사용하면 이상한 쿼리(select count(*).. order by ... 이게 이상한 이유는 order by에서 사용한 컬럼이 group by에 있어야 하는데 groupd by를 정의한 적이 없거니와, 사실 두 번째 쿼리는 count(*)가 없어야 하는데 앞에서 만들어둔 Criteria에 이어 붙인 꼴이 되어서 이상해졌습니다.)가 되버립니다.

중복처럼 보이지만 제거하면 코드가 깨지는... 요상한 경우. 이거 어떻게 처리하는게 좋을까요? 전 요리 조리 해보다가 그냥 뒀습니다.
신고
top


20080730 GMP

모하니?/GMPing : 2008.07.30 10:15


News

ill-~ : ~이 부족한(ex. ill-housed 주거환경이 안 좋은)

Around the world, woman are far more likely then man to be pool, ill-housed, undereducated, and vitimized by war and discrimination.

Screen English

I can't explain this.
Let him explain.
Remember the woman at the bookstore? Here she is.
You told me to go after her. and I didn't.
It was not planned.
I know how this looks.

Pop's English

Hey, grab your clothes and get gone.
You'd better hurry up. because spring coollers come on.
Girl I love you. you are the one. This is just looks like a re-run.
Please what else is on.

Talk Play Learn

I prefer A to B. (나는 B 보다 A가 좋아요.)
I prefer girls to boys.
I prefer sea food to meat.
I prefer summer to winter.
I prefer snailmail to email.
I prefer baseball to soccer.
I prefer urban life to rurul life.
I prefer aisle seats to window seats.

바쁜데 짬을 내다 = squeez in


신고

'모하니? > GMPing' 카테고리의 다른 글

20080819 GMP  (0) 2008.08.19
20080813 GMP  (0) 2008.08.13
20080807 GMP  (0) 2008.08.07
20080801 GMP  (0) 2008.08.01
20080731 GMP  (0) 2008.07.31
20080730 GMP  (0) 2008.07.30
20080728 GMP  (0) 2008.07.28
20080724 GMP  (0) 2008.07.24
20080721 GMP  (0) 2008.07.21
20080718 GMP  (0) 2008.07.18
20080717 GMP  (0) 2008.07.17
top

TAG GMP

Spring DM 1.1.1 배포

Spring DM/etc : 2008.07.29 23:44


http://www.springframework.org/node/718

버그들을 좀 수정했나봅니다. 눈에 확 들어오는 뭔가는 없어서 코멘트 할 께 없네요;;
신고
top


ItemReader - Spring Batch Chapter 3



DB에서는 단일 레코드, 애플리케이션에서는 단일 도메인 객체, 배치 작업에서는 Item. 이 녀석을 읽어들일 때 사용하는 것이 바로 ItemReader.

public interface ItemReader {

  Object read() throws Exception;

  void mark() throws MarkFailedException;

  void reset() throws ResetFailedException;
}

아주 깔끔한 인터페이스 read()는 읽고, mark()는 표시해두고, reset()은 최근에 mark() 된 곳으로 이동. 마치 책갈피가 있는 Iterator 느낌이 납니다.

그리고 이 인터페이스를 구현한 녀석이 DB나 파일등에 연결이 필요한 경우 반드시 같이 구현하는 인터페이스가 있는데 그건 바로 ItemStream.

public interface ItemStream {

  void open(ExecutionContext executionContext) throws StreamException;

  void update(ExecutionContext executionContext);
 
  void close(ExecutionContext executionContext) throws StreamException;
}

ExecutionContext를 사용해서 처음 위치부터 시작하지 않고 이전에 멈췄던 곳에서 다시 시작 할 수 있는 방법을 제공합니다. open() 해서 연결하고, update()는 ExecutionContext에서 현재 상태 읽어옵니다. 따라서 커밋하기 전에 update()를 호출해서 현재상태가 DB에 보존되고 있는지 확인할 때 사용하고, close()는 open으로 읽어온 자원들 반납합니다. 작업 마친 담에 꼭 호출해주는게 좋겠네요.

DB에 있는 Item을 읽어올 때, 스프링의 JdbcTemplate에서는 RowMapper를 사용해서 반환된 ResultSet에 있는 데이터들을 모두. 왕창. 한방에. 객체로 맵핑해서 반환해줬습니다. 이게 이슈가 되기도 합니다. 왜냐면, 데이터가 너무 많으면 메모리가 모자라서 죽게 될테니까요. 그런데 배치에서도 역시 RowMapper를 사용하는데, 그런 일이 벌어지지 않게 하기 위해서 두 가지 방법을 마련했습니다. 하나는 커서Cursor, 하나는 드라이빙쿼리DrivingQuery.

Cursor 스타일이란?
맵핑을 한 번에 전부 하는게 아니라, 한 번에 한 줄씩 합니다. "스트리밍" 방식이라고 할 수 있습니다. 위에서 살펴본 ItemReader의 next()를 호출 할 때마다 한 줄(레코드)씩 이동합니다.

  HibernateCursorItemReader itemReader = new HibernateCursorItemReader();
  itemReader.setQueryString("from CustomerCredit");
  //For simplicity sake, assume sessionFactory already obtained.
  itemReader.setSessionFactory(sessionFactory);
  itemReader.setUseStatelessSession(true);
  int counter = 0;
  ExecutionContext executionContext = new ExecutionContext();
  itemReader.open(executionContext);
  Object customerCredit = new Object();
  while(customerCredit != null){
    customerCredit = itemReader.read();
    counter++;
  }
  itemReader.close(executionContext);

itemReader.read()를 할 때마다 RowMapper를 적용해서 객체를 던져주고, 다음 레코드로 넘어갑니다.

Driving Query 스타일이란?
레코드 전체를 가져오는게 아니라, 주키만 가져온 다음에 필요시에 애플리케이션의 DAO를 사용해서 객체를 DB에서 로딩하는 방법. 이 방법을 쓰는 이유는 DB2 처럼 Pessimistic Locking(읽는 롹킹)하는 경우에 Cursor 방법이 비효율적일 수 있기 때문입니다.

이 녀석의 구현체인 DrivingQueryItemReader가 의존하고 있는 인터페이스 KeyCollector.
 public interface KeyCollector {

    List retrieveKeys(ExecutionContext executionContext);

    void updateContext(Object key, ExecutionContext executionContext);
  }

첫번째 메소드야 뻔하고, updateContext는 현재 어디까지 읽었나, 책갈피를 끼워두는 겁니다.

KeyCollector 구현체
- SingleColumnJdbcKeyCollector : 주키가 컬럼 하나 일때 사용.
  SingleColumnJdbcKeyCollector keyCollector = new SingleColumnJdbcKeyCollector(getJdbcTemplate(),
  "SELECT ID from T_FOOS order by ID");

  keyCollector.setRestartSql("SELECT ID from T_FOOS where ID > ? order by ID");

  ExecutionContext executionContext = new ExecutionContext();

  List keys = keyStrategy.retrieveKeys(new ExecutionContext());

  for (int i = 0; i < keys.size(); i++) {
    System.out.println(keys.get(i));
  }
흠.. 이 예제 코드는 잘 이해가 안 가네요. ItemReader 인터페이스는 안 사용하나;;

복합키 일땐?? ExecutionContextRowMapper

신고

'Spring Batch > Chapter 3' 카테고리의 다른 글

ItemReader - Spring Batch Chapter 3  (7) 2008.07.29
top


The Domain Language of Batch - Spring Batch Chapter 2



배치 개념을 익히기 정말 좋은 챕터가 아닌가 생각됩니다. 스프링 배치의 도메인 언어인지, 일반적인 배치의 도메인 언어인지는 구분하기 힘들지만, 상당히 많이 정제되어 있다는 느낌을 받을 수 있었습니다. 분명, 수 많은 프로젝트의 배치 작업을 하면서 도출해낸 도메인 언어들이 아닐까 생각됩니다.

요즘은 귀찮아서 그림을 안 그렸었는데, 오랜만에 그려봐야겠습니다. 레퍼런스에 나와있는 그림에 표현하지 않은 도메인(JobParameters, ExecutionContext, Persistence 여부)도 있어서요.

사용자 삽입 이미지

후광이 있는 녀석들은 Persistent Domain입니다. 즉 (DB를 사용한다는 가정하에) Step이라는 테이블이 없다고 (즉, Step 정보를 유지하지 않는다고) 봐도 됩니다. 그래서 StepExecution 테이블에는 JobExecution의 주키를 참조하는 외례키 컬럼만 있고 Step_ID와 같은 컬럼은 없습니다.

연한색 박스는 인터페이스, 진한 색은 클래스입니다.

ExcutionContext는 StepExcuion 당 하나씩 생성됩니다.

재미있는 건 저 도메인들을 저장하는 책임을 지닌 JobRepository라는 인터페이스인데, 이 녀석의 구현이 어떻게 되어 있을까 궁금했는데, 구현체는 없었습니다. 어떻게 구현해야 할런지... JDBC 말고 애노테이션 기반 하이버네이트를 써서 구현하는 방법이 궁금해집니다. JobRepositoryHibernate 야.. 뭐 SessionFactory만 있으면 알아서 넣어줄테니 걱정되지 않는데, 저들 도메인의 맵핑 정보를 넘겨줘야 하는데 말이죠. 그걸 어떻게 애노테이션으로 할 방법은 없을까요. 흠... XML로만 해야 할까요. XML 로 해야 한다면, 맵핑 정보는 어떻게 만들면 될까요? 어느정도 고정적인 도메인이니까, 하나 만들어 두는게 좋을 것 같습니다.

흠.. Spring Batch + 하이버네이트를 기반으로 한 어떤 프레임워크가 되겠군요.

자세한 설명은 http://static.springframework.org/spring-batch/spring-batch-docs/reference/html/core.html 를 참조하세요.


신고

'Spring Batch > Chapter 2' 카테고리의 다른 글

The Domain Language of Batch - Spring Batch Chapter 2  (4) 2008.07.28
top


혹시 "빠삐놈"을 모르시나요?



빠삐놈 원작(?)
http://gall.dcinside.com/list.php?id=composition_dc&no=63183&page=1

빠삐놈 8마일


그밖에도.. 참 많은 빠삐놈 노래들이 있더군요. 그 중에 짧고 재밌었던 건.. 빠삐밴드.

신고
top


로컬에서는 무사히 빌드가 되는데, 왜 서버로 올라가서 CI가 돌리면 컴파일 에러가 날까

Build/Maven : 2008.07.28 14:45


이럴 때가 정말 황당하고 답답한데, 뭐 방법은 역시 에러 메시지를 잘~~ 살펴보면 됩니다. 아님, 사부님한테 물어보던지요.ㅋㅋ

문제 분석

일단 CI 서버에서 문제가 생기면, 로그 메시지를 보고 어느 Phase에서 에러가 난건지 확인 합니다. 컴파일 에러가 났으면 당연히 compile Phase에서 에러가 난거겠죠. 그럼 로컬에서는 어떤지 로컬에서 compile을 해봅니다. 즉 mvn compile 이라고 하면 되죠. 이 때 서버랑 똑같이 컴파일 문제가 생기면 아주 아주 좋은겁니다. 그런데 이 글의 제목처럼 로컬에서는 잘 돌아간다면, 약간 당황스러워 집니다. 이 때부턴 여태까지의 경험과 로그 분석으로 난국을 헤쳐나가야 합니다. mvn 로그를 보려면, -X를 추가해서 실행하면 됩니다. 서버로 가서 mvn -X compile 이라고 서버에서 실행하고 자세히 들여다 봅니다. 어떤 라이브러리들을 가져왔는지, 플러긴은 제대로 가져왔는지 등등..

문제 해결

0. 로컬에서 빌드가 제대로 돌았다는 사실을 의심해야 합니다.

"왜 서버에선 안 돌아갈까?" 전에.. "왜 로컬에서는 돌아가는거지?" 라는 생각을 먼저 해보는게 문제 해결의 지름길 입니다. '서버에서 돌린 스크립트를 그대로 돌렸나??' 라고 생각해본다거나, 이클립스에서 실행한건 아닌지.. 의심해야 합니다.

1. 인코딩 문제

로그를 보다가 UTF-8 뭐시기.. 인코딩 뭐시기 하는 메시지가 쭉~~~~~~~~~뜨는 경우가 있습니다. 이 때는 소스 파일 인코딩이랑 서버의 인코딩이 맞지 않아서 그런데, 리눅스의 경우 export LANG=ko_KR.eucKR 이런식으로 인코딩을 변경할 수 있으니, 인코딩을 변경한 다음에 다시 빌드를 해봅니다. 되면 귿!

2. 라이브러리 참조 문제

사용자 삽입 이미지

필요한 라이브러리들을 제대로 참조 했는지, 내가 원하던 버전을 참조하고 있는지 확인합니다. -X 옵션을 주면 볼 수 있으니까 잘 보면서 확인합니다.

2-1. 원하던 라이브러리가 없다.

<dependency> 엘리먼트 안 에 정의한 <scope>를 의심해보시기 바랍니다. <scope>에 test라고 입력했다면, 소스 코드 compile 시점이 아니라 테스트 코드 compile 시점에 참조하게 됩니다. 따라서 mvn compile 할 떄는 해당 라이브러리가 없겠죠.

2-2. deps 들이 꼬였다.

deps가 꼬일 일이 없으면 좋겠지만, 간혹... 정말 간혹.. 꼬일 수도 있습니다. managed deps 들이랑, transient deps들이 잘못해서 꼬이면 정말 찾기가 힘들지만, 어떻게 하겠습니까? 로그를 보면서 찾아야 합니다. 찾으면 그 담엔 제외 시키던지, 아니면 새로 deps를 정의해서 nearest first 전략을 활용하면 됩니다.

저의 에피소스

문제는 금요일 저녁에 발생했는데, 해결은 방금 전에 했습니다. 똑같은 컴파일 에러.. 똑같은 상황... 10번도 넘게 빌드를 해봤지만, 문제 원인은 쉽게 떠오르질 않고, 왜 자꾸 spring에 있는 mock 패키지를 못찾는 다고 하는 건지.. 로컬에선 잘 돌아갔는데.. mvn compile을 해도 돌아갔는데.. 대체 왜 이러니...

조금 전 연결이 된 사부님에게 문제 상황을 말씀 드렸더니, 저번에도 겪은 문제(deps가 꼬인 경우)가 아니겠냐고, -X 옵션으로 확인해보라는 대답을 들었습니다. 속으로는 '아.. 안 되는데.. 그 문제면 정말 귀찮은데...' 이러면서 확인해 봤더니, 컴파일에러에서 찾지 못한다는 그 클래스를 가진 라이브러리가 없었습니다. '뭐지.. 왜 spring-test.jar가 없지?' 제가 돌린 프로젝트는 스프링 테스트를 확장한 클래스(테스트 클래스가 아니라 그냥 일반 소스 코드로써의 클래스)를 가지고 있었기 때문에 spring-test.jar가 필요했습니다. '올커니... scope 때문이구나.' 아니나 다를까. pom.xml을 열어봤더니, 해당 라이브러리가 test 스콥으로 잡혀있었습니다. 해당 라인을 지워버리니까 빌드는 무사히 성공~
신고
top


메이븐 플러그인 탐험기1 - UMLGraph

Build/Maven : 2008.07.28 13:18


소스코드를 보고 UML을 만들어 주는 UMLGraph라는 툴을 메이븐 빌드 과정 중에 플러긴으로 설치해서 리포트를 뽑아내는게 목적입니다. 물론 최종 목적은 코드와 모델을 항상 최신의 상태로 똑같은 상태로 유지하는 것입니다. 코드 보다 그림이 보기 좋은데, 그림이 실제 코드랑 다른 상태에서 어떤 결정을 하게되면.......

그래서 소스 코드에서 UML을 뽑아내는 툴을 사용해보기로 결정했습니다. 구글 검색을 통해서 잘 정리해둔, 불어로 된 블로그의 글 발견. 어차피 코드만 있으면 되기 때문에..ㅋㅋ

1. 먼저. Graphviz를 설치합니다. 이 녀석은 .dot 파일을 .png 파일로 만들어준 녀석입니다. 실제 그림을 들고 다니는 것 보다 그림을 그릴 정보들을 텍스트로 들고 다니는게 가볍기 때문일까요?

http://www.graphviz.org/Download..php

2. 환경 변수 path에 위에서 설치한 Graphciz의 bin 폴더를 설정해줍니다. 그 안에 있는 dot 이라는 명령어를 사용해야 하기 때문입니다.

3. 누가 doc 명령어를 사용하냐면, UMLGraph 메이븐 플러긴이 사용합니다. maven에 UMLGraph 플러그인 설정은 간단합니다.

    <reporting>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <configuration>
                    <doclet>
                        gr.spinellis.umlgraph.doclet.UmlGraphDoc
                    </doclet>
                    <docletArtifact>
                        <groupId>gr.spinellis</groupId>
                        <artifactId>UmlGraph</artifactId>
                        <version>4.6</version>
                    </docletArtifact>
                    <additionalparam>
                        -inferrel -inferdep -quiet -hide java.*
                        -collpackages java.util.* -qualify
                        -postfixpackage -nodefontsize 9
                        -nodefontpackagesize 7
                    </additionalparam>
                </configuration>
            </plugin>
        </plugins>
    </reporting>

자세한 설정 값은.. 나중에 살펴보구요.

4. mvn javadoc:javadoc 또는 mvn site를 실행하면, target/site 폴더가 생기고 그 아래에 apidocs 폴더가 생겼을 겁니다. 거기부터가 javadoc 문서입니다.

5. 구경하기

사용자 삽입 이미지

귿~

신고
top


20080728 GMP

모하니?/GMPing : 2008.07.28 11:53


News

I recently visited California Silicon Vally and a new hightech startup. No not computers, it's a car company. And All they wanna do is change the world. "And an electronic sports car? That's right!"

Screen English

a.k.a(also known as): 또한 ~라고 알려진

Look. I'm not your parents. But I think you should know love is a dangerous feeling.
No Sir.
Are you arguing with me?
Love is not a feeling. It's an ability.

Pop's English

You look so dump right now.
Standing outside my house.
Trying to apology you are so ugly when you cry.
Please just cut it out.(=knock it off)

Talk Play Learn

I enjoied ~ing
I enjoied staying here.
I enjoied talking to you.
I enjoied studying history.
I enjoied working with you.
I enjoied walking with you.
I enjoied reading this book.
I enjoied watching the movie.

공공연한 비밀 = Open secret
신고

'모하니? > GMPing' 카테고리의 다른 글

20080813 GMP  (0) 2008.08.13
20080807 GMP  (0) 2008.08.07
20080801 GMP  (0) 2008.08.01
20080731 GMP  (0) 2008.07.31
20080730 GMP  (0) 2008.07.30
20080728 GMP  (0) 2008.07.28
20080724 GMP  (0) 2008.07.24
20080721 GMP  (0) 2008.07.21
20080718 GMP  (0) 2008.07.18
20080717 GMP  (0) 2008.07.17
20080716 GMP  (0) 2008.07.16
top

TAG GMP

JSF 기초 2

JSF/exercise : 2008.07.26 22:02


참조 : JSF for nonbelievers: The JSF application lifecycle

JSF 라이프사이클

사용자 삽입 이미지
1. Restore view

요청이 FacesSevlet으로 전달되면, 컨트롤러는 요청을 분석해서 뷰 ID를 뽑아낸다. (JSP 페이지 이름을 바탕으로)

JSF 프레임워크 컨트롤러는 뷰 ID를 사용해서 현재 뷰에서 사용할 컴포넌트들을 가져온다. 뷰가 없으면, 새로 만들어서 사용한다. 만약에 뷰가 이미 있으면, 그것을 사용한다. 뷰에는 모든 GUI 컴포넌트들이 있다.

이 단계에서는 세 가지 경우가 있는데 각각 new view, initial view, postback 이다.

new view: 이 경우에 JSF는 Faces 페이지 뷰를 만들고 이벤트 핸들러와 벨리데이터를 컴포넌트에 연결시킨다. 그렇게 만들어진 뷰는 FacesServlet 객체에 저장된다.

initial view: 이 경우에는 비어있는 뷰를 만든다. 비어있는 뷰는 사용자가 이벤트를 발생시켰을 때 만들어지고, 이 다음 단계는 render response로 넘어간다.

postback: 이미 만들어둔 페이지를 다시 보여줄 때가 postback이다. 이 경우에 JSF는 기존에 존재하던 뷰의 상태 정보를 유지한채 보여준다. 이 다음 단계는 apply request values가 된다.(원래 그 단계인데, 뭘 새삼 언급해주는거지;;)

2. Apply request values

이 단계의 목적은 각각이 컴포넌트들이 현재 상태를 가져오는 것이다. 컴포넌트들은 반드시 그 값들을 사용해서 FacesContext 객체에서 가져오거나 새로 만들어진다. 컴포넌트 값들은 보통 요청 파라메터에서 가져오는데, 쿠키나 헤더에서 가져올 수도 있다.

컴포넌트의 immediate event handling 속성이 true 가 아닐 경우: 값의 타입을 객체의 속성 타입으로 변환하는 작업을 한다. 이 때 만약 캐스팅 시에 에러가 나면, response render 단계에서 validation error랑 같이 보여준다.

컴포넌트의 immediate event handling 속성이 true 일 경우: 타입 변환 + 검증작업까지 한다. 그리고 변환된 값을 컴포넌트에 저장한다. 만약 값 변환이나 값 검증이 실패하면, 에러 메시지를 생성해서 FacesContext에 있는 큐에 넣는다. 그럼 다른 검증 에러들과 함께 response render 단계에서 보여준다.

3. Process Validation

사용자가 입력한 값이 검증 룰에 비교해봤을 때 적당한지를 살펴본다. 적절치 않을 때는 FacesContext에 에러 메시지를 추가하고 컴포넌트를 invalid 상태로 표시한다.

만약 컴포넌트가 invalid로 표시되어 있다면: JSF는 바로 render response 단계로 넘어간다.

만약 invalid 컴포넌트가 아니면: update model values 단계로 간다.

4. Update model values

서버쪽에 있는 모델이 가진 속성 값들을 수정한다. 이 단계는 항상 validation 단계 다음에 오기 때문에 빈 속성값의 유효함을 보장받는다.(물론 폼 필드 수준일 뿐, 비즈니스 룰 수준에서는 유효하지 않을 수도 있다.)

5. Invoke application

JSF 컨트롤러는 폼 처리를 할 애플리케이션을 호출한다. 컴포넌트 값이 그에 따라 바뀔 것이고, 검증될 것이고(여기선 비즈니스 룰 수준의 검증을 말하는 거겠죠), 모델 객체에 반영이 될 것이다. 즉 비즈니스 로직을 수행한다.

이 단계에서, 다음에 보여줄 논리적인 뷰를 명시할 수 있다. 간단하게 폼 처리의 성공 여부를 반환하면 된다. 네비게이션 룰은 faces-config.xml에 정의한다. 네비게이션이 이루어지면, 최종 단계로 이동한다.

6.  Render response

모든 컴포넌트의 현재 상태를 화면에 보여준다. 그림2는 객체 상태 다이어그램으로 JSF 라이프사이클 6 단계를 보여주고 있다.

사용자 삽입 이미지

신고

'JSF > exercise' 카테고리의 다른 글

JSF의 universal EL  (0) 2008.09.20
초간단 JSF 예제 돌리기 성공  (0) 2008.09.16
JSF 기초 2  (0) 2008.07.26
JSF 기초 1  (0) 2008.07.24
top


도메인 질렀습니다. 이제부터 whiteship.me는 내꺼




도메인이 좀 비싸네요;; whiteship을 선박 관련된 업체들에서 쓰고 있어서 com, net, info 이런 거는 꿈도 못 꾸고 co.kr이랑 kr이 있긴한데 그닦 신선한 느낌이 아니라서, me로 결정했습니다.

아주 가끔 작성하는 이력서에 블로그 주소를 http://whiteship.tistory.com 이라고 쓸 때마다 도메인을 하나 사야겠다 싶었는데, 이 참에 질렀습니다.

저야 URL을 직접 입력해서 들어오는 경우가 거의 없지만(저는 주로 즐겨찾기 버튼으로 들어오거나 RSS 리거기에서 링크로 들어오거든요), 혹시나 URL 입력해서 들어오시거나, 검색해서 들어오시는 분들은 앞으로 주소창에 whiteship.me 라고 쳐주세요~

사용자 삽입 이미지

신고
top


JSF 기초 1

JSF/exercise : 2008.07.24 23:26


참조 : JSF for nonbelievers: Clearing the FUD about JSF

기본 아키텍처

사용자 삽입 이미지

JSF 예제

1. web.xml 과 faces-config.xml 설정하기

1-1. web.xml

<!-- Faces Servlet -->
<servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup> 1 </load-on-startup>
</servlet>

<!-- Faces Servlet Mapping -->
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/calc/*</url-pattern>
</servlet-mapping>

이건 뭐 별 설명이 필요 없을 것 같네요. 스프링의 DispatcherServlet하고 비슷한 일을 할 듯 합니다. 중요 클래스니까 언제 한 번 열어봐야겠네요.

1-2. faces-config.xml

<faces-config>
    ...
  <managed-bean>
    <description>
      The "backing file" bean that backs up the calculator webapp
    </description>
    <managed-bean-name>CalcBean</managed-bean-name>
    <managed-bean-class>com.arcmind.jsfquickstart.controller.CalculatorController</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
  </managed-bean>

<navigation-rule>
  <from-view-id>/calculator.jsp</from-view-id>
  <navigation-case>
    <from-outcome>success</from-outcome>
    <to-view-id>/results.jsp</to-view-id>
  </navigation-case>
</navigation-rule>

</faces-config>

흠.. JSF에서 사용할 컨트롤러 빈의 이름과 스코프를 등록하고, 네비게이션을 등록해두네요. 네비게이션을 등록해둔 걸 보면, 서브밋 할 때 action="result.jsp" 같은 코드를 사용하지 않아도 알아서 가주겠죠?

2. 모델 객체 만들기

package com.arcmind.jsfquickstart.model;

/**
 * Calculator
 *
 * @author Rick Hightower
 * @version 0.1
 */
public class Calculator {
    //~ Methods ----------------------------------------------------------------

    /**
     * add numbers.
     *
     * @param a first number
     * @param b second number
     *
     * @return result
     */
    public int add(int a, int b) {
        return a + b;
    }

    /**
     * multiply numbers.
     *
     * @param a first number
     * @param b second number
     *
     * @return result
     */
    public int multiply(int a, int b) {
        return a * b;
    }
   
}

3. 컨트롤러 만들기(완전 POJO)

package com.arcmind.jsfquickstart.controller;

import com.arcmind.jsfquickstart.model.Calculator;


/**
 * Calculator Controller
 *
 * @author $author$
 * @version $Revision$
 */
public class CalculatorController {
    //~ Instance fields --------------------------------------------------------

    /**
     * Represent the model object.
     */
    private Calculator calculator = new Calculator();

    /** First number used in operation. */
    private int firstNumber = 0;

    /** Result of operation on first number and second number. */
    private int result = 0;

    /** Second number used in operation. */
    private int secondNumber = 0;

    //~ Constructors -----------------------------------------------------------

    /**
     * Creates a new CalculatorController object.
     */
    public CalculatorController() {
        super();
    }

    //~ Methods ----------------------------------------------------------------

    /**
     * Calculator, this class represent the model.
     *
     * @param aCalculator The calculator to set.
     */
    public void setCalculator(Calculator aCalculator) {
        this.calculator = aCalculator;
    }

    /**
     * First Number property
     *
     * @param aFirstNumber first number
     */
    public void setFirstNumber(int aFirstNumber) {
        this.firstNumber = aFirstNumber;
    }

    /**
     * First number property
     *
     * @return First number.
     */
    public int getFirstNumber() {
        return firstNumber;
    }

    /**
     * Result of the operation on the first two numbers.
     *
     * @return Second Number.
     */
    public int getResult() {
        return result;
    }

    /**
     * Second number property
     *
     * @param aSecondNumber Second number.
     */
    public void setSecondNumber(int aSecondNumber) {
        this.secondNumber = aSecondNumber;
    }

    /**
     * Get second number.
     *
     * @return Second number.
     */
    public int getSecondNumber() {
        return secondNumber;
    }

    /**
     * Adds the first number and second number together.
     *
     * @return next logical outcome.
     */
    public String add() {
       
        result = calculator.add(firstNumber, secondNumber);

        return "success";
    }

    /**
     * Multiplies the first number and second number together.
     *
     * @return next logical outcome.
     */
    public String multiply() {

        result = calculator.multiply(firstNumber, secondNumber);
       
        return "success";
    }
}


흠.. 이 코드를 보고서 좀 놀랐습니다. 스프링 2.5로 컨틀롤러를 만들어도, 가능하긴 한데, 수많은 애노테이션들이 붙고, 그 애노테이션들을 정말 잘 알고 있어야 했는데.. 결국 그 애노테이션들 없이는 스프링의 컨트롤러는 의미도 없고 재사용할 수도 없기 떄문에 엄밀히 따지면 POJO라고 하긴 좀 뭐했습니다. 그런데 JSF의 저 컨트롤러는 뭐.. 틈잡을것이 하나도 없습니다.

4. 뷰 만들기

4-1. index.jsp

<jsp:forward page="/calc/calculator.jsp" />

흠.. 얘는 네비게이션에 등록하지도 않았고, JSF Servlet이 담당할 URL로 들어오지 않을테고.. 저기서 JSF  Servlet이 담당할 URL로 포워딩시키는 군요.

4-2. calculator.jsp

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>

<f:view>
  <h:form id="calcForm">
     <h:panelGrid columns="3">
    <h:outputLabel value="First Number" for="firstNumber" />
    <h:inputText id="firstNumber" value="#{CalcBean.firstNumber}" required="true" />
        <h:message for="firstNumber" />   

    <h:outputLabel value="Second Number" for="secondNumber" />
    <h:inputText id="secondNumber" value="#{CalcBean.secondNumber}" required="true" />
        <h:message for="secondNumber" />
    </h:panelGrid>
   
    <h:panelGroup>
    <h:commandButton id="submitAdd" action="#{CalcBean.add}"  value="Add" />
    <h:commandButton id="submitMultiply" action="#{CalcBean.multiply}" value="Multiply" />
</h:panelGroup>
  </h:form>
</f:view>

흠~ 이제 좀 재밌는 코드가 나왔습니다.

맨위에 첫 줄은, 폼을 비록한 HTML 관련 태그들이 담겨있고, 두 번째 줄은 JSF가 사용할 로직, 벨리데이션, 컨트롤러등을 위한 태그들이 담겨있다고 합니다.

<f:view> 안에 들어가야 JSF 컴포넌트 트리를 만든다고 합니다. JSF 를 사용할 땐 저 안에 모든 JSF 컴포넌트를 넣어야 겠군요.

<h:form> 은, html 폼을 나타내는 JSF 컴포넌트인가 봅니다. 속성중에  column=3은 한 줄에 세칸이라는 뜻이고, 따라서 저 안에 있는 컴포넌트들은 세줄씩 마침 코드에서도 한 줄 띄어쓰기로 구분해주고 있네요.

<h:message>는 에러 메시지 보여줄 때 사용할 것 같은데, 뭘 참조하라는게 없군요. 자동으로 메시지 생성해서 넣어줄 것 같은데... 내가 원하는 메시지를 보여주고 싶을 땐 어떻게 해야되지??

의문 1. 내가 원하는 메시지를 보여주고 싶을 땐 <h:message>를 어떻게 설정해야 하나?

JSP의 EL 처럼 JSF에도 EL 이 있는데, 그건 바로 #{}. CalcBean은 아까 faces-config.xml이였나.. 거기에 등록했던 컨트롤러이고, value 속성은 해당 컨트롤러의 필드값을 참조하고, action은 메소드를 호출하고 그 결과를 가져오나 보군요.

의문 2. 인자가 있는 메소드도 지원할까? 지원한다면, 어떻게 써야 하나?

예상했던 것처럼 역시나 저 폼을 서브밋하면 어디로 갈지를 폼에다가 적지 않았습니다. 아까 저 페이지? URL?에 대한 네비게이션을 정의해두었죠.

4-3. result.jsp

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
...
<f:view>
  First Number: <h:outputText id="firstNumber" value="#{CalcBean.firstNumber}"/>
  <br />
  Second Number: <h:outputText id="secondNumber" value="#{CalcBean.secondNumber}"/>
  <br />
  Result: <h:outputText id="result" value="#{CalcBean.result}"/>
  <br />
</f:view>


흠.. 이번에도 역시 <f:view>를 써서 JSF 컴포넌트 트리로 감싸고, <h:outputText> 라는 컴포넌트를 쓰고 있군요. value를 사용해서 필드값들만 참조합니다. 간단하군요.

돌리는 건 내일해야 겠습니다. 11시 반도 안 됐는데 졸리네요;

신고

'JSF > exercise' 카테고리의 다른 글

JSF의 universal EL  (0) 2008.09.20
초간단 JSF 예제 돌리기 성공  (0) 2008.09.16
JSF 기초 2  (0) 2008.07.26
JSF 기초 1  (0) 2008.07.24
top

TAG JSF

20080724 GMP

모하니?/GMPing : 2008.07.24 21:34


News

tough 텊: 질긴, 힘든
Spiting 스핏ㅇ(남부발음)

Spiting watermelon seeds. It's a sound that defines the summer. No more at the grocery store, at the farmer's market It's tough to even find a watermelon with seeds these days.

Screen English

So~ You are a doctor.
Yes.
What's your specialty?
I'm a plastic surgion.
Oh~ of course you are.
I know what your are thinking. But I work exclusively only burned victims and borned with defomaties.

Pop's English

Mustang Sally I guess you better slow that Mustang down.
Mustang Sally now baby. I guess you better slow that Mustang down.
You've been running all over the town.
I guress you've gotta put your flat feet on groud.

Talk Play Learn

Is it possible for me to ~?(내가 ~ 하는게 가능할까요?)
Is it possible for me to pay later?
Is it possible for me to get a refund?
Is it possible for me to meet Jhones?
Is it possible for me to check my order?
Is it possible for me to change my room?
Is it possible for me to take these brochures?
Is it possible for me to cancle metting?

Learn More

일을 꼼꼼하게 마무리하다. = dot one's I's and cross one's t
ex) She always dot her's I's.
답답해 = I'm frustrated.
신고

'모하니? > GMPing' 카테고리의 다른 글

20080807 GMP  (0) 2008.08.07
20080801 GMP  (0) 2008.08.01
20080731 GMP  (0) 2008.07.31
20080730 GMP  (0) 2008.07.30
20080728 GMP  (0) 2008.07.28
20080724 GMP  (0) 2008.07.24
20080721 GMP  (0) 2008.07.21
20080718 GMP  (0) 2008.07.18
20080717 GMP  (0) 2008.07.17
20080716 GMP  (0) 2008.07.16
20080715 GMP  (0) 2008.07.15
top

TAG GMP

Maven 2.0.10 배포 임박!!!

Build/Maven : 2008.07.24 10:37


참조: http://blogs.sonatype.com/brian/2008/07/23/1216860133767.html



중요 변경 사항
# [MNG-2562] - expose current time as a property for POM interpolation
# [MNG-3652] - set a user agent for Maven HTTP requests
# [MNG-3571] - Allow use of ! when deactivating profiles
# [MNG-3268] - Command line doesn't handle multiple -P correctly
# [MNG-3314] - offline build not running, when having SNAPSHOT dependencies
# [MNG-2068] - Multiple inheritance fails to find "grand" parent in ../../pom.xml when the groupIds differ (Test Case Attached)

그러다 저것들 보다 훨씬 더 중요한 변경 사항이 있었으니.. 그것은 바로!! 두둥!!!
http://jira.codehaus.org/browse/MNG-3520

사용자 삽입 이미지

캬캬캬. 바로 한국어 메시지 프로퍼티 파일의 추가!! 누가 번역해서 올렸는지 참.. 착하죠?
신고
top


맥에서 mov 파일 swf로 인코딩하기

Good Tools : 2008.07.23 21:23


무료 툴 중에 mov 파일을 flw 파일로 변환해 주는 건 있던데, swf로 해주는건 못찾았습니다. 이번에도 맥토렌트 사이트와 멜론 콤보가 작렬했습니다. 맥토렌트에서 토렌트 받아서 멜론한테 던지면, 멜론이 애플리케이션을 가져다 줍니다. 캬캬캬.

덕분에 무사히 맥에서도 인코딩 할 수 있겠습니다.

사용자 삽입 이미지

신고
top


텍스트박스에서 엔터키 누르면 ~~~하기

DotNet : 2008.07.23 16:41


1. Key Down 이벤트 설정.

사용자 삽입 이미지

2. 이벤트 핸들러에 구현하기.

if (e.KeyCode.Equals(Keys.Return))
{
       MessageBox.Show("하이");
        processlogin();
}

Keys라는 Enum 스타일 클래스가 왠지 있을 것 같아서 그냥 입력해 봤더니, 역시나 있었습니다.ㅋㅋ 키 코드 모음인가본데, Enter키가 Enter가 아니라 Return이라서 삽질을 또 좀 했습니다. 닷넷 삽질은 이번 주 만 하고 빨리 끝내야지 슬슬 지겨워집니다.

신고

'DotNet' 카테고리의 다른 글

텍스트박스에서 엔터키 누르면 ~~~하기  (0) 2008.07.23
닷넷에서 웹 서비스 참조하기  (0) 2008.07.21
닷넷에서 DataSource 사용하기  (0) 2008.07.21
top

DotNet : 2008.07.23 16:41 Trackback. : Comment.

log4j 설정 파일 위치를 명시적으로 설정하고 싶을 때..

모하니?/Coding : 2008.07.23 13:51


Junit4 기반 테스트시 Log4 설정파일 위치 지정 방법이 있을까요?

질문에 답이 있었습니다.

질문의 내용은 웹 애플리케이션이 돌아갈 때 사용할 log4j 설정파일은 web.xml에서 설정할 수 있었는데, 테스트 할 때 사용할 설정 파일의 위치는 어떻게 설정할 수 있느냐 입니다. 저도 잘 모르겠어서 어떻게 해야 되지? 라는 고민을 하다가 가장 먼저 떠오른 방법은 문제를 우회하는 방법이었습니다. "왜 위치를 명시적으로 설정해야 되지?" 싶어서 말이죠.

그래서 생각한 방법이 소스 폴더에 설정 파일을 두는 방법입니다. Maven이 아닐 경우 보통 src와 test 라는 소스 폴더를 만들어서 사용할텐데요. 그 경우 둘 중 아무곳에나 설정 파일을 두기만 하면 output 폴더(이클립스 자바 프로젝트 기본 outpu 폴더는 bin폴더)로 이동하게 됩니다. 그럼 그 파일을 log4j가 찾아서 사용하죠. Maven일 경우네는 src/main/resouces에 두거나 src/test/resource에 두면 됩니다.

그러나 Maven일 때 주의 할 것이 있는데, 바로 해당 폴더 루트에 위치 시켜야 한다는 겁니다. src/main/recouces에 두지 않고 그 안에 새로운 폴더 하나를 만들어서 두면 그건 소스 폴더로 인식하지 않습니다. 따라서 log4j가 설정파일을 못찾게 되죠.

결론적으로 명시적으로 log4j 설정파일 위치를 설정해주고 싶습니다. 굳이 소스폴더가 아니여도 참조할 수 있게 말이죠. 그래서 살펴본 것이 web.xml에 등록되어 있는 org.springframework.web.util.Log4jConfigListener 이 클래스 입니다. 분명 저 클래스가 설정 파일 위치 정보를 가져가니까 어디선가는 그 파일을 읽어서 설정하겠죠.

그래서 Log4jConfigListener 이 클래스를 찾아갔더니 별로 코드가 없습니다.

public class Log4jConfigListener implements ServletContextListener {

    public void contextInitialized(ServletContextEvent event) {
        Log4jWebConfigurer.initLogging(event.getServletContext());
    }

    public void contextDestroyed(ServletContextEvent event) {
        Log4jWebConfigurer.shutdownLogging(event.getServletContext());
    }

}

이 코드에서 사용하고 있는 Log4jWebConfigurer를 찾아갔습니다. 그리고 그 안에 있는 initLogging 메소드 안에서 다음의 코드를 발견했습니다.

Log4jConfigurer.initLogging(location, refreshInterval);

빙고!! 게임은 끝났습니다.

유겐 휄러가 2003년에 만든 클래스더군요. Log4jConfigurer 클래스를 감상하면서.. 참 멋지다는 생각을 했습니다.

/*
 * Copyright 2002-2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.net.URL;

import org.apache.log4j.LogManager;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.DOMConfigurator;

/**
 * Convenience class that features simple methods for custom log4j configuration.
 *
 * <p>Only needed for non-default log4j initialization, for example with a custom
 * config location or a refresh interval. By default, log4j will simply read its
 * configuration from a "log4j.properties" or "log4j.xml" file in the root of
 * the classpath.
 *
 * <p>For web environments, the analogous Log4jWebConfigurer class can be found
 * in the web package, reading in its configuration from context-params in
 * <code>web.xml</code>. In a J2EE web application, log4j is usually set up
 * via Log4jConfigListener or Log4jConfigServlet, delegating to
 * Log4jWebConfigurer underneath.
 *
 * @author Juergen Hoeller
 * @since 13.03.2003
 * @see org.springframework.web.util.Log4jWebConfigurer
 * @see org.springframework.web.util.Log4jConfigListener
 * @see org.springframework.web.util.Log4jConfigServlet
 */

public abstract class Log4jConfigurer {


    /** Pseudo URL prefix for loading from the class path: "classpath:" */
    public static final String CLASSPATH_URL_PREFIX = "classpath:";

    /** Extension that indicates a log4j XML config file: ".xml" */
    public static final String XML_FILE_EXTENSION = ".xml";


    /**
     * Initialize log4j from the given file location, with no config file refreshing.
     * Assumes an XML file in case of a ".xml" file extension, and a properties file
     * otherwise.
     * @param location the location of the config file: either a "classpath:" location
     * (e.g. "classpath:myLog4j.properties"), an absolute file URL
     * (e.g. "file:C:/log4j.properties), or a plain absolute path in the file system
     * (e.g. "C:/log4j.properties")
     * @throws FileNotFoundException if the location specifies an invalid file path
     */
    public static void initLogging(String location) throws FileNotFoundException {
        String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(location);
        URL url = ResourceUtils.getURL(resolvedLocation);
        if (resolvedLocation.toLowerCase().endsWith(XML_FILE_EXTENSION)) {
            DOMConfigurator.configure(url);
        }
        else {
            PropertyConfigurator.configure(url);
        }
    }

    /**
     * Initialize log4j from the given location, with the given refresh interval
     * for the config file. Assumes an XML file in case of a ".xml" file extension,
     * and a properties file otherwise.
     * <p>Log4j's watchdog thread will asynchronously check whether the timestamp
     * of the config file has changed, using the given interval between checks.
     * A refresh interval of 1000 milliseconds (one second), which allows to
     * do on-demand log level changes with immediate effect, is not unfeasible.
     * <p><b>WARNING:</b> Log4j's watchdog thread does not terminate until VM shutdown;
     * in particular, it does not terminate on LogManager shutdown. Therefore, it is
     * recommended to <i>not</i> use config file refreshing in a production J2EE
     * environment; the watchdog thread would not stop on application shutdown there.
     * @param location the location of the config file: either a "classpath:" location
     * (e.g. "classpath:myLog4j.properties"), an absolute file URL
     * (e.g. "file:C:/log4j.properties), or a plain absolute path in the file system
     * (e.g. "C:/log4j.properties")
     * @param refreshInterval interval between config file refresh checks, in milliseconds
     * @throws FileNotFoundException if the location specifies an invalid file path
     */
    public static void initLogging(String location, long refreshInterval) throws FileNotFoundException {
        String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(location);
        File file = ResourceUtils.getFile(resolvedLocation);
        if (!file.exists()) {
            throw new FileNotFoundException("Log4j config file [" + resolvedLocation + "] not found");
        }
        if (resolvedLocation.toLowerCase().endsWith(XML_FILE_EXTENSION)) {
            DOMConfigurator.configureAndWatch(file.getAbsolutePath(), refreshInterval);
        }
        else {
            PropertyConfigurator.configureAndWatch(file.getAbsolutePath(), refreshInterval);
        }
    }

    /**
     * Shut down log4j, properly releasing all file locks.
     * <p>This isn't strictly necessary, but recommended for shutting down
     * log4j in a scenario where the host VM stays alive (for example, when
     * shutting down an application in a J2EE environment).
     */
    public static void shutdownLogging() {
        LogManager.shutdown();
    }

    /**
     * Set the specified system property to the current working directory.
     * <p>This can be used e.g. for test environments, for applications that leverage
     * Log4jWebConfigurer's "webAppRootKey" support in a web environment.
     * @param key system property key to use, as expected in Log4j configuration
     * (for example: "demo.root", used as "${demo.root}/WEB-INF/demo.log")
     * @see org.springframework.web.util.Log4jWebConfigurer
     */
    public static void setWorkingDirSystemProperty(String key) {
        System.setProperty(key, new File("").getAbsolutePath());
    }

}


유틸 클래스인데, abstract로 해놨습니다. 인스턴스 만들지 말라는거죠. 멋지지 않나요. 캬캬. 유틸 클래스를 보통 무심하게 그냥 public class로 해놓기 일수인데, abstract라는 키워드 하나가 정말 멋지게 느껴지지 않나요. 그리고 저 충실한 JavaDoc 코멘트들.. 정말 유겐은 대단합니다.

그러니까... 저런 코드를 출처(스프링 프로젝트 홈피 링크 덜렁 남기는게 아니라, 저 클래스나 javadoc URL을 걸어놔야 출처를 명시했다고 생각합니다. 그게 보통 말하는 출처 아닌가요?? 장난이 아니고서야 누가 대체 출처를 www.google.com 이라고 달죠?)도 없이 원작자 이름도 빼고 베끼는 코드를 보면, 어떻게 흥분을 안 하겠습니까.. 에흄.. 유겐은 참 착하기도 하지.

얘기가 좀 샜는데, 어쨌거나 저 클래스를 잘 이용하면 이 글의 제목에 대한 답은 된 것 같습니다. 역시나 멋진 스프링은 아직도 공부할 것들이 무궁무진 합니다. 특히 전 소스코드는 자세히 들여본적이 거의 없는데, 저 코드를 보고나니까 좀 관심이 갑니다. 쉬운 클래스 부터 하나씩 갈펴봐야겠습니다. BeanFactory나 ApplicationContext는 넘 어려워서 원~
신고
top


바코드를 출력 및 읽기 코딩할 때 주의할 것

모하니?/Coding : 2008.07.23 11:39


바코드 언어에서는 시작과 끝을 알리는 기호로 * 를 쓰겠다는 룰이 있답니다. 그래서 출력할 때

e.Graphics.DrawString("*" + barcode + "*", barcodefont, Brushes.Black, 20, 35);

이런식으로 *로 감싸줘야 하고..

반대로 읽을 때는 그냥 *는 알아서 때어내고 읽어줍니다. 따라서 읽을 때는 별도의 작업 필요 없이 그냥 읽으면 된다는거~

첨에 저 코드를 보고 '흠.. 앞뒤에 왜 저런걸 붙여 놓으셨을까..괜히 길어지게.. 지우자.' 해서 지웠더니 바코드를 못 읽습니다. 크허헐 이유를 모르니 역시 또 사부님께 물어봤는데, 뭐 대답이 그냥 바로바로 나옵니다.

643388035488643388035488643388035488643388035488643388035488643388035488

쿄쿄쿄쿄. 닷넷이 재밌는게 아니라, 새로운 걸 알게 되고 새로운 걸 해보는게 재미있는 것 같습니다.
신고
top

TAG 바코드

스프링 DM 모듈에서 단위 테스트하기(링크)

Spring DM/etc : 2008.07.23 08:53


http://springtips.blogspot.com/2008/07/unit-test-with-spring-dynamic-modules.html

제목은 단위 테스트인데, 사실 OSGi 환경에서 번들로 설치한 담에 실행하는 것이고, 스프링 ApplicationContext도 사용하고 있으니까 정확하게는 통합 테스트 입니다. 제목이 굳이 단위 테스트인 이유는 몰겠네요. 흠.. 단위 테스트를 왜 OSGi 환경에서 실행했을라나..

어쨌든, 스프링 DM에서 테스트를 작성하는 방법을 설명해주고 있는 괜춘한 글입니다. 벌써 저렇게 자기 애플리케이션을 스프링 DM 번들로 전환하는 작업을 마친 사람들도 많은데, 저도 좀 분발해야겠습니다.
신고
top


불신자를 위한 JSF 시리즈

모하니?/Reading : 2008.07.22 18:25


JSF for nonbelievers: Clearing the FUD about JSF
JSF for nonbelievers: The JSF application lifecycle
JSF for nonbelievers: JSF conversion and validation
JSF for nonbelievers: JSF component development

외국에선 상당히 많은 개발자들이 사용하고 있다는 JSF.. 저도 한 번 써보고 싶어서 공부를 시작합니다. 위에 두 개의 아티클은 한국 IBM DeveloperWorks에 번역된 기사를 찾긴 했는데, 번역이.. 좀;; 그래서 걍 원문을 읽기로 했습니다.

나머지 두 개는 제가 번역해야겠습니다. ㅋㅋ
신고
top

TAG JSF

20080721 GMP

모하니?/GMPing : 2008.07.21 20:40


News

acknowledge 엨널리지 인정하다
rebound 반등하다

The president acknowledges this is difficult time for an Amerian famillies, but he says the economy will  eventually rebound.

Screen English

encourage 엔커리지
inappropriate 부적절한

And there are other things you can do. Such as not exist,
Ah. Thank you.
That not. I said it. I didn't mean it. But I said it. Do you know whatelse I'm gonna do?
I'm going to make myself less attractive. So as not to encourage any inapproprivate feelings.

Pop's English(She will be loved)

Beauty quean of only eighteen, she had some trouble with herself.
He was always there to help her. She always belonged to someone else.

Talk Play Learn

Don't you think it's ~? (~라고 생각하지 않아?)
Don't you think it's easy?
Don't you think it's wrong?
Don't you think it's funny?
Don't you think it's cheap?
Don't you think it's too late?
Don't you think it's a bit early?
Don't you think it's expensive?
Don't you think it's really nice here?

Sound Sound Play

'스' 발음 다음에 it 가 오면 '싯'
since it
notice it
You cann't miss it
guess it
pass it
fix it
replace it

Today Expression

Make faces = 얼굴을 찌푸리다
신고

'모하니? > GMPing' 카테고리의 다른 글

20080801 GMP  (0) 2008.08.01
20080731 GMP  (0) 2008.07.31
20080730 GMP  (0) 2008.07.30
20080728 GMP  (0) 2008.07.28
20080724 GMP  (0) 2008.07.24
20080721 GMP  (0) 2008.07.21
20080718 GMP  (0) 2008.07.18
20080717 GMP  (0) 2008.07.17
20080716 GMP  (0) 2008.07.16
20080715 GMP  (0) 2008.07.15
20080710 GMP  (0) 2008.07.10
top

TAG GMP

닷넷에서 웹 서비스 참조하기

DotNet : 2008.07.21 18:22


1. 프로젝트의 Web References에서 new 클릭
2. 웹 서비스 URL을 적어주면 끝.
사용자 삽입 이미지

사용자 삽입 이미지

웹 서비스로 참조할 수 있는 타입과 서비스 목록은 더블클릭하여 확인 가능.

주의할 것.
- 닷넷 코드에서 사용하지 않는 타입은 목록에 나오지 않는 경우가 있는데, 이 때는 일단 해당 타입을 사용하는 코드를 작성하고 빌드를 하면 그 뒤에 나타난다. 당장 자동완성에 나타나지 않더라도 일단 코딩하고 보자.
신고

'DotNet' 카테고리의 다른 글

텍스트박스에서 엔터키 누르면 ~~~하기  (0) 2008.07.23
닷넷에서 웹 서비스 참조하기  (0) 2008.07.21
닷넷에서 DataSource 사용하기  (0) 2008.07.21
top




: 1 : 2 : 3 : 4 :





티스토리 툴바