Whiteship's Note

'2008/09'에 해당되는 글 82건

  1. 2008.09.30 DisplayTag 히든 컬럼(hidden column) 추가하기 (1)
  2. 2008.09.30 그리드 태그 파일 으윽.. 머리야~ (2)
  3. 2008.09.29 DisplayTag 데코레이터 사용하기
  4. 2008.09.29 메이븐 settings.xml 살펴보기
  5. 2008.09.28 스프링 공부하다 보면 공부하게 되는 것들 (2)
  6. 2008.09.27 Using Spring Security 2 (2)
  7. 2008.09.27 http://www.parleys.com 멋진 싸이트 (2)
  8. 2008.09.26 JDK 6.0에서 CGLib과 JDK 프록시 성능 비교 (2)
  9. 2008.09.26 프록시(Proxy) 패턴
  10. 2008.09.25 HP CP1215 맥에서 사용하기
  11. 2008.09.25 OSAF 검색 폼 태그 파일 완성
  12. 2008.09.25 JavaScript Calendar
  13. 2008.09.25 ReadWriteLock 인터페이스
  14. 2008.09.25 Shared Mutable State (2)
  15. 2008.09.25 The Price of Freedom
  16. 2008.09.25 Concurrency and OSGi
  17. 2008.09.25 Generic 팩토리 메소드 (2)
  18. 2008.09.24 베토벤 바이러스 잼나네요. (2)
  19. 2008.09.24 Principle of least astonishment
  20. 2008.09.24 썬 테크데이 참가할 세션
  21. 2008.09.24 How to Design a Good API & Why it Matters
  22. 2008.09.24 KSUG 9번째 스프링 세미나 (2)
  23. 2008.09.23 S1A 비행기 예약 + 호텔 예약
  24. 2008.09.22 자바의 숨겨진 기능들 (6)
  25. 2008.09.22 S1A(Spring One America) 질렀다. 가는거다. (2)
  26. 2008.09.22 context:component-scan 엘리먼트는 annotation-config도 등록해줌.
  27. 2008.09.22 Clover 2.3.2(for Maven) (4)
  28. 2008.09.22 아.. 카드한도. (4)
  29. 2008.09.22 BeanLifeCycle 인터페이스를 없애보자. (2)
  30. 2008.09.22 delete 요청 처리 컨트롤러 코드 고민

DisplayTag 히든 컬럼(hidden column) 추가하기

View/JSP : 2008.09.30 17:02


캬오.. 간단하지 않네요. media 속성 값중에 "none"이라는 값을 지원해주면 좋을텐데, 이 값은 지원하지 않습니다. 이슈 트래커에 올리면 반영해주려나.. 흠..

방법은.. 일단 CSS에 hidden이라는 클래스 하나를 추가합니다.

.hidden {
    display: none;
}

그리고 컬럼의 class와 headerClass의 값을 hidden으로 설정해줍니다.

    <d:column property="id" class="hidden" headerClass="hidden" />

끝~ 나중에 OSAF 태그 파일로 감싸서 좀 더 간단하게 이 기능을 제공할 수 있겠습니다. isHidden 이라는 속서을 추가해서 말이죠. 간단하게~ 명시적으로~
신고
top


그리드 태그 파일 으윽.. 머리야~

View/JSP : 2008.09.30 10:24


사용자 삽입 이미지

현재 그리드에 스타일 적용과 데코레이터 사용법까지 확인을 했고, 뭘 해야 할지 잠시 정리해 봤습니다. 곰곰히..

1. 페이지 네비게이션 바 추가.(완료)
-> displaytag가 제공하는 네비게이션바도 있지만, 그건 이미 많은 양의 데이터를 세션에 집어넣고 그 중에서 페이징처리를 하는거기 때문에 별로입니다. 제대로 페이징을 하려면 서비스 단에서 제공하는 만큼의 데이터가 한 페이지 분량이 되고, 페이징 로직도 서비스단에서 제공하는 걸 이용해야 합니다.

2. id값을 히든 컬럼으로 추가.(완료)
-> 한 Row가 하나의 객체 정보를 보여주고 있고 그 중에 선택을 해서 삭제/수정 작업을 하려면 id를 물고 있어야합니다. 따라서 id 값은 테이블에 안 보이는 컬럼으로 추가되어 있어야합니다.

3. 순번 표시(완료)
-> id가 아닌, 컬럼 줄 수를 표시해야 합니다. 500개의 데이터 중에 해당 줄이 몇 번째 데이터에 해당하는지, 기본적으로 이 순서로 정렬해서 보여줄 필요가 있겠죠. 이 기능도 역시 서비스 단과 맞물려서 동작해야겠습니다. displaytag에서도 뭔가 제공해주겠지만, 그건 저 한 페이지 내용에 대한 순번일 뿐, 전체 데이터에 대한 순번은 서비스 단이 알고 있을테니 말이죠.

4. 정렬 기능(에러)
-> 각 컬럼 헤더에 정렬 단추를 달고, 해당 단추를 눌러서 정렬 할 수 있는 기능을 제공해야 합니다. 이 기능은 displaytag가 제공하기 때문에, 설정만 추가하면 됩니다.

5. 링크 기능
-> 어떤 줄을 더블클릭하면, 바로 수정 화면으로 이동하도록 설정하고 싶습니다. 이 기능은 displaytag가 제공하는 링크 기능을 이용하면 간단하게 될 듯 합니다.

6. 컬럼 데이터 포맷
-> 금액이나 날짜 데이터의 경우 포맷을 설정할 수 있는 기능을 displaytag가 제공합니다. 그 패턴을 좀 익혀서 정리해둬야 겠습니다.

7. 체크 박스
-> 그리드 맨 왼쪽에 체크 박스 컬럼을 만들어서 다중 선택을 지원합니다. 다중 선택으로 해당 객체의 id 값들의 배열을 특정 요청 매개변수로 넘겨줄 수 있다면, 그 뒤엔 여러가지 일들을 할 수 있겠죠.

이밖에도 그리드 편집/새로운 줄 추가 등 여러 기능이 있을 수 있겠지만.. 일단 저 위의 것들부터도 그닥 만만해 보이지 않습니다. 저것만 끝내면 OSAF 공개인데... ㅠ.ㅠ 파이팅 하자 파이팅 해..

updated today 6:00


신고
top


DisplayTag 데코레이터 사용하기

모하니?/Coding : 2008.09.29 15:47


참조 : http://displaytag.sourceforge.net/11/tut_decorators.html

어떻게 만드는지에 대한 설명은 없고 사용법만 나와있습니다. 에잉~ 어쩔 수 없이 Javadoc을 살펴봤습니다. 뭔가 인터페이스를 만들어 놓고 그걸 구현하게 해 뒀겠지.. 싶어서 찾아봤습니다.

올커니.. 너였구나. ColumnDecorator. 에엥; 왠걸 Deprecated 됐습니다. DisplaytagColumnDecorator 1.1부터는 이 인터페이스를 사용하라네요. 자세한건 귀찮아서 패~스.

구현해야 할 메소드는 딱 하나.

    public Object decorate(Object object, PageContext context, MediaTypeEnum typeEnum)
            throws DecoratorException {
    }

object로 넘어온 값을 원하는 형태로 저 안에서 변형시킨 다음에 넘겨주면 됩니다. 저는 인터페이스를 타입 구현체에서 구현하게 했습니다.

public class SexType extends AbstractType implements DisplaytagColumnDecorator {

    public static final int MALE = 10;
    public static final int FEMALE = 20;
   
    public SexType() {
        super(Arrays.asList(
            new Pair(MALE, "남성"),
            new Pair(FEMALE, "여성")));
    }
   
    private static SexType sexType = new SexType();
   
    public static SexType getInstance(){
        return sexType;
    }

    @Override
    public Object decorate(Object object, PageContext context, MediaTypeEnum typeEnum)
            throws DecoratorException {
        return this.decode((Integer)object);
    }
   
}

이렇게 말이죠. 그럼 뷰에서는 저 데코레이터 인터페이스를 구현한 클래스 풀 패키지 경로를 포함한 이름으로 설정해주면.. 됩니다.

<d:table name="list">
    <d:column property="name" />
    <d:column property="loginId" />
    <d:column property="sex" decorator="org.opensprout.sample.model.enumeration.SexType" />
    <d:column property="location" />
    <d:column property="birthday" />
    <d:column property="hobbies" />
</d:table>

흠.. 고민이 있는데, 저런 데코레이터를 지금처럼 특정 타입에 대한 데코레이터니까, 타입 클래스가 구현하는게 좋을지 아니면 별도의 클래스로 분리하는게 좋을지.. 잘 모르겠습니다. 또 고민이 있는데, 저 인터페이스가 jsp 인터페이스에 종속되어 있어서(PageContext), SexType이라는 클래스가 디스플레이 태그 API와 JSP API의 침략을 당한다는 것입니다. 이 부분이 상당히 껄끄러운데.. 어쩜 좋을지.. 고민이 됩니다.

어차피 decode()라는 메소드가 AbstractType에 존재한다는 건, 디코딩 역할을 하겠다는 것이고, 뷰에서도 디코딩 역할을 이 녀석이 책임지는 것이 그리 나쁘지 않을 것 같다는 판단하에 타입 클래스가 구현하게 했습니다. 훔~

아니면..

저렇게 데코레이터를 사용하지 않고 도메인 클래스에 getSexDecode()라는 메소드를 추가하고, 뷰에서는 sex가 아니라, property="sexDecode" 라고 참조하는 방법도 있습니다.

단, 이 방법은 도메인 클래스의 역할이 역시 좀 이상해 집니다. 뷰에서 어떤 값을 보여주기 위해 디코딩하는 일이 도메인 클래스에 들어있는게, 그리 아름다워 보이지가 않아서 말이죠. 하지만, 이 방법을 쓰면 디스플레이 태그 API가 침범하지도 않고, 따라서 JSP API의 침범도 없습니다.

갈등이네요. (-- ) ( --) 어찌하면 좋을꼬...
신고
top


메이븐 settings.xml 살펴보기

Build/Maven : 2008.09.29 11:44


참조 : http://maven.apache.org/ref/2.0.8/maven-settings/settings.html
사용자 삽입 이미지

현재 제가 사용하고 있는 settings.xml 파일에서 1단계 엘리먼트만 보여주고 있습니다.

1. settings

최상위 엘리먼트로, 하위 엘리먼트들로 메이븐 설정함.

2. pluginGroups

  <pluginGroups>
  <pluginGroup>com.atlassian.maven.plugins</pluginGroup>
  </pluginGroups>

열어보면 이렇게 설정되어 있습니다. Maven-Clover2-Plugin 설치할 때 settings.xml에 추가한 기억이 납니다. 뭔 내용인지 몰랐는데, 지금 살펴봅니다.
List of groupIds to search for a plugin when that plugin groupId is not explicitly provided.
groupid 리스트로 플러그인의 groupId가 명시적으로 설정되어 있지 않을 때 플러그인을 찾을 곳이로군요.

            <plugin>
                <groupId>com.atlassian.maven.plugins</groupId>
                <artifactId>maven-clover2-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <generateXml>true</generateXml>
                    <generateHtml>true</generateHtml>
                    <licenseLocation>/app/webapp/opensprout/clover/clover.license</licenseLocation>
                    <includesTestSourceRoots>
                        false
                    </includesTestSourceRoots>
                </configuration>
            </plugin>

흠..그럼 pom에서 저렇게 플러긴의 groupId를 명시했으니까, 설정을 지워도 되겠군요.

3. mirrors

  <mirrors>
    <mirror>
      <id>Nexus</id>
      <name>Nexus Public Mirror</name>
      <url>http://www.opensprout.org:8082/nexus/content/groups/public</url>
      <mirrorOf>central</mirrorOf>
    </mirror>
  </mirrors>

이렇게 설정되어 있습니다. mirrors는
Configuration of download mirrors for repositories.
저장소에 대한 다룬로드 미러들을 설정이로군요. 그럼. mirror는
A download mirror for a given repository.
하나의 저장소에 대한 하나의 미러 설정이군요. 각각의 속성들은

mirrorOf        The server ID of the repository being mirrored, eg "central". This MUST NOT match the mirror id.
name     The optional name that describes the mirror.
url     The URL of the mirror repository.
id     No description.

4. profiles

흠.. 이 녀석을 사용해서, JDK 버전 별 또는 OS 마다 빌드 구성을 달리 할 수 있는 거로군요. 하지만, 복잡하니까 나중에 다루기로 하고, pass

5. activeProfiles

   <activeProfiles>
     <activeProfile>dev</activeProfile>
</activeProfiles>

List of manually-activated build profiles, specified in the order in which they should be applied.
위에서 설정한 여러 프로파일중에서 직접 활성화 시킬 빌드 프로파일 목록. 설정한 순서대로 적용된다.

6. servers

  <servers>
    <server>
      <id>release</id>
      <username>admin</username>
      <password>---</password>
    </server>
    <server>
      <id>snapshot</id>
      <username>admin</username>
      <password>---</password>
    </server>
  </servers>

Configuration of server-specific settings, mainly authentication method. This allows configuration of authentication on a per-server basis.

서버와 관련된 설정으로, 주로 인증하는 방법을 제공. 이것을 통해 서버 당 인증 정보를 담고 있을 수 있다.

이 때, 위에서 사용한 id의 값은 pom에서 설정한 저장소의 id와 일치해야 하는 듯.. pom.xml을 보면 짐작할 수 습니다.

    <distributionManagement>
        <repository>
            <id>release</id>
            <url>http://www.opensprout.org:8082/nexus/content/repositories/releases</url>
        </repository>
        <snapshotRepository>
            <id>snapshots</id>
            <url>http://www.opensprout.org:8082/nexus/content/repositories/snapshots</url>
        </snapshotRepository>
    </distributionManagement>

신고
top


스프링 공부하다 보면 공부하게 되는 것들

모하니?/Thinking : 2008.09.28 22:22


사용자 삽입 이미지

맥용 마인드맵 애플리케이션이 있길래 사용해 볼 겸.. 그려봤습니다.

저는 스프링 공부하다 보면 자연스래 이것 저것 공부할 것들이 많아지고 배울 것들이 많아서 개발자 능력 향상에 도움이 된다고 생각합니다. 프레임워크를 어떻게 대하느냐에 따라 좀 차이가 있겠지만, 스프링은 대충 API만 익혀서 대충 쓰고 끝내기엔 너무 아까운 프레임워크라는 생각이 드네요.

그동안 2년이 넘게 스프링을 공부하고 있지만, 끝이 보이질 않습니다. 캬오~


신고
top


Using Spring Security 2

Spring Security/etc : 2008.09.27 10:32


참조: http://www.parleys.com/display/PARLEYS/Home#slide=1;title=Using%20Spring%20Security%202;talk=19267601

귿. 발표자 말투도 느린편이고, 억양도 알아들을만 합니다. 어제 들은 아리드안 코일러의 AOP 발표에 비하면 훨씬 알아 듣기 쉬운것 같네요.

데모 코드는 스크린캐스팅에 잡히지 않아서 참조할 수 없었지만, 대충 말해주면서 코딩하기 때문에 어떻게 코딩하는지 눈치챌 수 있습니다. 물론 Spring Security 2에 새로 도입한 스키마들을 알고 계셔야게죠.

몇 가지 정리해둡니다.

1. URL 권한 확인으로는 충분하지 않다.
- 리소스랑 URL이랑 1:1로 맵핑되는게 아닌 경우.
/listCustomers.html 과 /print.view?page=listCustomers 이 두 개의 URL이 같은 리소스를 나타낼 경우 권한처리를 어떻게 할 것인가
- URL이 없을 수도 있다.
Web Application이 아닌 경우 권한 처리는?
- 여러 Ajax 요청을 처리하는 하나의 URL
헤더 정보만 조금씩 다른데, 그 정보에 따라 권한 처리해야 할테네 어떻게 할텐가?

=> Method Authonrization!!

2. 메소드 권한처리
- AspectJ 포인트컷 표현식 사용 가능
- @Secured 애노테이션 사용 가능
- JSR 250의 @RoleAllowed 사용 가능

3. 베스트 프랙티스
- URL 체크로 개괄적인(corse grained) 권한 처리를 한다.
- 메소드 체크로 세밀한(fine grained) 권한 처리를 한다.
- Role 사용하지 말고, Right를 사용하라. User <--> Role <--> Riht
@Secured("PERM_DELETE_USER)
public oid deleteUser(User user)

마지막 문구

Spring Security is more powerful than Acegi was
... and now it is also easy ;-)


신고
top


http://www.parleys.com 멋진 싸이트

모하니?/Watching : 2008.09.27 09:23


사용자 삽입 이미지

Adobe Air로 만들어서, 그걸 설치해줘야 하는데 간단하네요. 설치한 뒤에 발표를 볼 수 있습니다. Spring One 2008 발표자료 중 하나가 떴네요. 캬오~ 멋져부러.

- Using Spring Security 2
http://www.parleys.com/display/PARLEYS/Home#slide=14;title=Using%20Spring%20Security%202;talk=19267601
신고
top


JDK 6.0에서 CGLib과 JDK 프록시 성능 비교

Spring/Chapter 7 : 2008.09.26 17:58


테스트 환경

JDK 1.6
CGLib 2.1_3 nodep
Spring 2.5.5

테스트 클래스

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="springContext.xml")
public class HelloAspectTest{

    @Autowired
    Hello goodHelloImpl;
   
    @Test
    public void createProxy() throws Exception {
        assertNotNull(goodHelloImpl);
        StopWatch stopWatch = new StopWatch();
        testProxiedMethod(10, stopWatch);
        System.out.println("total " + stopWatch.getTotalTimeMillis());
    }

    private void testProxiedMethod(int count, StopWatch stopWatch) {
        while(count > 0){
            stopWatch.start();
            for(int i = 0 ; i < 1000000 ; i++)
                goodHelloImpl.hi();
            stopWatch.stop();
            System.out.println(stopWatch.getLastTaskTimeMillis());
            count--;
        }
       
    }
}

CGLib을 사용할 때는 Concrete class 타입을 써도 상관없는데, JDK 프록시를 사용할 때는 인터페이스 타입을 써야 합니다. 이유는 아시죠? 설명은 패스합니다.

StopWatch 클래스는 스프링이 제공해주는건데, 위처럼 요긴하게 쓸 수 있습니다. API는 설명이 필요 없을 만큼 작명을 잘 해뒀기 때문에 그냥 읽어보시면 어떤 일을 하는지 알 수 있으실 겁니다.

스프링 설정 파일

    <context:component-scan base-package="org.opensprout.sandbox.proxy">
        <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect" />
    </context:component-scan>

    <aop:aspectj-autoproxy proxy-target-class="true" />

윗 부분에 주의해야 합니다. proxy-target-class="true" 이 설정을 삭제하면, JDK 프록시를 사용하는 것이고, 저 설정 그대로면, CGLib을 사용하는 겁니다.

어드바이스 적용 대상 인터페이스 => 타겟 인터페이스

public interface Hello {
   
    public String hi();

}

어드바이스 적용 대상 구현체 => 타겟 클래스

@Component
public class GoodHelloImpl implements Hello {
   
    public String hi(){
        return "";
    }

}

클래스 이름이나 메소드 이름 등에 너무 신경쓰지 말아주세요. 흑흑..ㅠ.ㅠ 대충 만든거란 말에요. 그것 보단, 이 녀석이 인터페이스를 구현하고 있기 때문에, 스프링이 프록시를 만들 때 proxy-target-class="true" 이 설정이 없으면 기본적으로 JDK 프록시를 생성한다는 사실.. 아시죠?

자 그럼 이제부터 쇼타임.

1. CGLib 사용시

위 설정 그대로 입니다.

1250
1204
1203
1218
1204
1203
1203
1219
1218
1219
total 12141

2. JDK 프록시 사용시

스프링 설정에서  proxy-target-class="true" 이걸 삭제합니다.

1687
1657
1656
1656
1656
1672
1672
1672
1656
1656
total 16640

3. CGLib 프록시를 서버 모드로

위 설정 그대로 사용합니다.
테스트 실행시 VM 인자에 -server 추가합니다.

813
796
797
813
797
797
812
797
797
total 8172

4. JDK 프록시를 서버 모드로

스프링 설정에서  proxy-target-class="true" 이걸 삭제합니다.
테스트 실행시 VM 인자에 -server 추가합니다.

1078
922
922
937
906
938
906
922
937
938
total 9406

캬요~ 자바지기님께서 테스트 했을 때에 비하면 JDK 프록시 성능 많이 좋아졌죠?

신고
top


프록시(Proxy) 패턴

Design Pattern : 2008.09.26 14:46


참조: Java 언어로 배우는 디자인 패턴 입문

- 필요해지면 만들기
- Proxy는 대리인
- 대리인이 처리할 수 있는 일은 대리인이 처리하고, 본인이 필요할 때에만 할 일을 본인에게 위임.

사용자 삽입 이미지
출처: http://en.wikipedia.org/wiki/Proxy_pattern

- 무거운 객체 생성이 필요할 때, 해당 객체가 정말로 필요한 시점에 생성하고, 그 전까지는 프록시가 해당 객체 역할을 대신하여 애플리케이션 성능을 높일 수 있다.

- 프록시 종류: Virtual Proxy, Remote Proxy, Access Proxy
신고

'Design Pattern' 카테고리의 다른 글

[Tell, Don't Ask] 물어보지 말고 시켜라  (8) 2010.04.07
Visitor 패턴  (2) 2010.03.12
Holub on Pattern 좋은데요~  (4) 2008.12.07
프로토타입 패턴(Prototype Pattern)  (2) 2008.10.31
데코레이터(Decorator) 패턴  (0) 2008.10.01
프록시(Proxy) 패턴  (0) 2008.09.26
JUnit 공부하자.  (0) 2008.09.01
H.F.OOAD 5장 문제  (0) 2007.11.20
상위 클래스 보다는 인터페이스를...  (4) 2007.08.31
Singletons and lazy loading  (2) 2007.01.27
객체지향 디자인 원칙  (2) 2006.12.11
top


HP CP1215 맥에서 사용하기



참조: http://www.herzz.com/blog/2008/08/28/setting-cp1215-on-a-mac/

공식적인 방법은 없는 것 같고, 뭔가 돌아가는 방법으로 사용법이 있었네요. 단, 컬러 출력시에 색이 이상합니다. 큐브 공식 F2L 외우려고 하는데, 도무지 흑백 출력으로는 알아보기가 쉽지 않아서, 컬러 출력을 했습니다.

꺄악;;; 노란색과 주황색, 빨간색은 비슷하게 나왔는데 파란색은 분홍색으로 나오고, 녹색은 노란색으로 나왔습니다. ㅎㅎ; 에잇. 윈도우로 부팅해서 출력해야지 ㅠ.ㅠ


신고
top

TAG hp cp1215

OSAF 검색 폼 태그 파일 완성

모하니?/Coding : 2008.09.25 15:59


사용자 삽입 이미지

태그 파일을 활요한 JSP 코드는 다음과 같습니다.

<o:searchpage title="사원관리">
    <o:searchbuttons popupheight="400" popupwidth="700" />

    <o:searchform action="grid.do">
        <o:searchrow>
            <o:stext path="name" label="이름" size="20" maxlength="30" />
            <o:sselect path="location" label="국적" items="${ref.locations}" isCOV="yes" />
            <o:sdate path="birthday" label="생일" />
        </o:searchrow>
        <o:searchrow>
            <o:sradiobuttons path="sex" label="성별" items="${ref.sexType}" />
        </o:searchrow>
        <o:searchrow>
            <o:scheckboxes path="hobbies" label="취미" items="${ref.hobbyType}" />
        </o:searchrow>
    </o:searchform>
</o:searchpage>

뭔가 많아 보여도, <o:searchrow>를 사용해서 세 줄로 표시했을 뿐, <o:searchrow>를 빼면 별거 없습니다. 이젠 정말 폼 태그 파일 만들차례.. ㅎㄷㄷㄷ.. 어려울텐데.. ㄷㄷㄷㄷ DisplayTag로 만들어봐야지
신고
top


JavaScript Calendar

View/JavaScript : 2008.09.25 13:52


참조: http://www.dynarch.com/projects/calendar/
사용자 삽입 이미지

저렇게 달력을 뿌려주는 자바스크립트 라이브러리입니다. Date 정보를 입력받을 때 사용하면 유용하겠죠. 여러 가지 스타일 시트도 제공해주고, 여러 포맷으로 데이터를 조작할 수도 있고, 좋습니다.

jscalander가 제공하는 예제 소스 코드를 보면 어떻게 이용할 수 있을지 대충 알 수 있습니다.
<form action="#" method="get">
<input type="text" name="date" id="f_date_b" /><button type="reset" id="f_trigger_b">...</button>
</form>

<script type="text/javascript">
    Calendar.setup({
        inputField     :    "f_date_b",      // id of the input field
        ifFormat       :    "%m/%d/%Y %I:%M %p",       // format of the input field
        showsTime      :    true,            // will display a time selector
        button         :    "f_trigger_b",   // trigger for the calendar (button ID)
        singleClick    :    false,           // double-click mode
        step           :    1                // show all years in drop-down boxes (instead of every other year as default)
    });
</script>

친절하게 주석도 있기 때문에, 금방 적용하실 수 있겠죠. 하지만, 약간의 번거로움은 감수를 하셔야 하며, 저런 컴포넌트가 여럿 필요할 때는 복사 붙여넣기 코드가 JSP 페이지 사방에 나타날 수 있을 겁니다. 그럴 땐 태그 파일을 만들어서 컴포넌트화 해 두면 매우 편합니다.

언젠가 공개할 OSAF를 사용하신다면, 간단한 태그 파일 sdata.tag로 쉽게 저런 UI 컴포넌트를 만들 수 있습니다.

<o:sdate path="birthday" label="생일" />

이렇게 한 줄이면 끝이죠. 캬오~ 태그 파일 만쉐이! OSAF 만쉐이!!
신고
top


ReadWriteLock 인터페이스

Java : 2008.09.25 11:55


참조 : http://java.sun.com/j2se/1.5.0/docs/api/

두 개의 Lock을 제공하는 인터페이스로, 동시에 여러 쓰레드가 사용할 수 있는 읽기 Lock과 베타적인 쓰기 Lock을 제공한다.

하나의 쓰레드(쓰기 쓰레드)만 공유 데이터를 변경할 수 있고, 공유 데이터를 읽으려는 쓰레드(읽기 쓰레드)는 여럿이 동시 읽을 수 있다. 이론적으로 이러한 접근이 예전의 상호베타적인 접근에 비해 성능상 좋다고 하는데, 실제로는 멀티 프로세서 환경에서 성능 향상을 볼 수 있다.

정해야 할 규칙들.
  • Determining whether to grant the read lock or the write lock, when both readers and writers are waiting, at the time that a writer releases the write lock. Writer preference is common, as writes are expected to be short and infrequent. Reader preference is less common as it can lead to lengthy delays for a write if the readers are frequent and long-lived as expected. Fair, or "in-order" implementations are also possible.
=> 읽기 쓰기 롹 둘 다 대기 중일 때, 어떤 것 부터 허용할지. 쓰기 부터 허용하는게 흔한데, 쓰기가 보통 짧게 끝나기 때문, 읽기부터 허용하는건 드문데 리더가 오래 걸려서. 물론 순서대로 적용하는 것도 가능함.
  • Determining whether readers that request the read lock while a reader is active and a writer is waiting, are granted the read lock. Preference to the reader can delay the writer indefinitely, while preference to the writer can reduce the potential for concurrency.
=> 리더가 활성화 상태고 롸이터가 대기중일 때 리더의 리드 롹 요청할 경우 어떻게 할까. 리더를 우선시하면 롸이터는 무한대기 할지도 모른다. 쓰기를 우선시 하면 점유율을 줄일 수 있다.
  • Determining whether the locks are reentrant: can a thread with the write lock reacquire it? Can it acquire a read lock while holding the write lock? Is the read lock itself reentrant?
=> 롹이 reentrant한지 결정. 쓰기 롹을 가진 쓰레드가 그걸 다시 요구할 수 있는지? 쓰기 롹을 가진 상태에서 읽기 롹을 얻을 수 있는지? 읽기 롹 자체가 reentrant 한지?
  • Can the write lock be downgraded to a read lock without allowing an intervening writer? Can a read lock be upgraded to a write lock, in preference to other waiting readers or writers?
=> 쓰기 롹을 읽기 롹으로 다운그레이드 할 수 있는지? 읽기 롹을 쓰기롹으로 업그레이드 할 수 있는지?

어이쿠.. 어려워 어려워; -_-;;

신고
top

Java : 2008.09.25 11:55 Trackback. : Comment.

Shared Mutable State

Spring DM/OSGi : 2008.09.25 11:33


공유하는 불변 객체

가능한한 최소한의 객체만 공유하고, 가능한한 공유하는 객체를 immutable하게 유지함으로써, 기본적으로 "동시성 문제" 크기를 줄인다. 불행히도 이 방법으로는 문제 크기를 0으로 만들지는 못한다. 실제 대부분의 애플리케이션에서 공유하는 불변 객체 사용을 완전히 없애진 못하기 때문에, 그럴 때 안전한 방법을 찾아야 한다.

서비스 기반 코드 예제를 살펴보자. 등록된 메일 박스 서비스의 Map을 관리한다고 가정해보자. 이름을 키로 사용하고 getMailboxByName 이라는 public 메소드를 제공하여 특정 메일 박스 또는 대응하는 박스가 없으면 null을 반환하도록 한다. 이 예제 코드는 6.1에서처럼 자바 synchronized 블럭을 사용하여 쓰레드 세이프티를 보장한다. 이 클래스는 잘 동작한다. 동일한 객체에 접근할 땐 해당 객체의 롹을 지니고 접근해야 하기 때문이다. 비록 맵 필드 자체는 final 이지만, map이 가지고 있는 내용물은 mutabl하며 여러 쓰레드가 공유하고 있다. 따라서 lock으로 보호해야 한다. 또란, 동기화 블럭은 가능한한 짧고, 빨리 롹을 반환해야 한다.

=> 음.. 글쿤 mutale한 객체를 공유하는 경우가 어떤건지 감이 오는군. 역시 예제가 있어야 이해하기 쉽네.

하지만, 코드 6.1은 Java 5에 도입된 새로운 동시성 기능의 장점은 하나도 이용하고 있지 않다. 자바 5의 기능을 사용하면 동시에 여러 쓰레드가 getMailboxByName 메소드를 호출하는 것이 가능하다. 이전 동기화 블럭은 읽기와 쓰기를 구분할 수 없었다. 모든 메소드 접근시에 불필요하게 롹 객체를 요구했다. 하지만 Java 4에 도입된 Read/Write 롹은 이를 구분할 수 있게 해준다. 코드 6.2는 이 기능을 사용하여 여러 쓰레드가 동시에 맵에서 읽기 작업을 할 수 있게 해준다. 물론 동시에 변경은 못하게 막고 있다.

만약 자바 5를 사용할 수 있는 환경이라면, 그 안에 들어있는 새로운 concurrnt 라이브러리를 확인해보는게 좋겠다. 자바 1.4를 사용하고 있다면 동기화 블럭 사용을 주저하지 말아라. 많은 개발자들은 성능 문제로 동기화 블럭 사용을 주저하지만, 실제로 동기화 블럭을 최대한 작게 유지만 한다면 그렇게 성능이 나쁘진 않다.  그리고 무엇보다 성능 조금 높이자고 동기화 문제를 방치한다는 건 말이 안 된다.

=> 옳커니~. 자바 5에 그런 게 있었구나.. 우와;; 평소에 쓰레드 다룰 일이 거의 없으니 완전 몰랐네.

=> 살펴 볼 클래스
- ReadWriterLock
- ReentrantReadWriteLock



신고

'Spring DM > OSGi' 카테고리의 다른 글

OSGi 툴 세트 Pax  (0) 2008.10.21
Shared Mutable State  (2) 2008.09.25
The Price of Freedom  (0) 2008.09.25
Concurrency and OSGi  (0) 2008.09.25
BundleContext로 할 수 있는 일  (0) 2008.06.25
2 Security Layer  (0) 2008.02.18
1. Introduction  (0) 2008.02.17
top


The Price of Freedom

Spring DM/OSGi : 2008.09.25 11:13


참조 : http://neilbartlett.name/blog/osgibook/

자유의 댓가.

=> 쓰레드를 맘대로 만들어 사용할 수 있는 자유의 댓가.

상상으로 만든 A, B, C 번들에 대한 간다한 시나리오를 살펴보자. 그림 6.1에 UML 시퀀스 다이어그램으로 나타냈다. 번들 A가 쓰레드를 시작시키고 어느 순간 번들 B에 접근하여 해당 쓰레드에서 번들 B의 start 메소드를 호출한다. 그러면 번들 B가 활동을 시작하고(active), 번들 B 액티베이터의 start 메소드가 번들 A가 만든 쓰레드에서 호출될 것이다. 게다가, B의 start 메소드에서 어떤 서비스를 등록하고, C가 서비스 트래커로 이 서비스 타입을 리스닝하고 있다. 번들 C 트래커의 addingService 메소드가 호출되고, 이 역시 A가 만든 쓰레드에서 호출된다. 마지막으로 C가 B가 등록한 서비스를 주기적으로 호출하는 쓰레드를 만들었다고 가정해보자.

=> 아.. 너무해. 이게 뭔리야. 좀 차근 차근 얘기해주지. -_-;; 그러니까...
1. 번들 A가 쓰레드를 만들고 거기서 번들 B의 start 메소드를 호출해서 번들 B를 활성화 시킨다.
2. 번들 B의 start 메소드에서는 번들 C가 리스닝하고 있는 서비스를 서비스 레지스트리에 등록한다.
3. 번들 C는 새로운 쓰레드를 만들어서 주기적으로 B가 등록한 서비스를 가져온다.
이말인가? 그렇다 치고..

사용자 삽입 이미지

클라이언트가 서비스 레지스트리에서 서비스를 가져갈 때, 프록시나 랩퍼가 아닌 진짜 서비스 객체를 찾는다. 따라서 클라이언트가 서비스에 메소드를 호출할 때, 해당 호출들은 기본적으로 동기적인 메소드 호출이다. 즉, 쓰레드에서 실행하는 서비스 메소드를 클라이언트 번들이 "쥐고있다."(owned)라는 뜻이다.

=> 넹.

또한, 많은(전부는 아님) OSGi 내의 알림은 동기적으로 발생한다. 프레임워크가 콜백을 사용하는 메소드(ServiceEvent를 등록되엉 있는 서비스 리스너로 보내는 것이나 번들 엑티베이터의 start 또는 stop 메소드를 호출하는 것 같은)에 의해 호출될 때, 그런 콜백들은 동일한 쓰레드에서 실행되고, 이전 제어권이 프레임워크 메소드를 호출한 쪽에 되돌아가기 전에 완료해야 한다.

=> 아.. 어렵다. 프레임워크의 어떤 메소드에 콜백을 넘겨줬을 때, 그 콜백도 같은 쓰레드에서 호출된다는 것이고, 해당 콜백 실행이 완료한 다음에, 제어권을 넘겨줘야 한다는 것이군.

위와 같은 상황에는 세 개의 주요 가정이 존재한다.
  • 콜백과 서비스 메소드는 어떤 쓰레드에서든 호출될 수 있다. 여러 쓰레드에서 동시에 호출될 수도 있을 것이다. 이를 주시하지 않고 코딩했을 때는 예상하지 못한 문제를 발생시킬 수 있다.
  • 우리가 작성할 콜백과 서비스 메소드를 호출하는 쓰레드는 우리가 만들 것에 "포함되어 있지 않다." 만약 오랜 시간 동작하거나, blocking I/O를 이런 콜백에서 사용한다면 전체 시스템을 지연시킬 수 있다.
  • OSGi API 메소드를 사용하면, 우린 해당 프레임워크가 어떤 리스너나 콜백을 사용하는지 예측할 수 없고, 따라서 해당 콜백에서 어떤 롹을 취하려는지도 알 수가 없다. 만약 그런 메소드를 호출하는 도중 다른 롹을 가지고 있다면, daedlock을 발생키질 위험이 있다.
이런 문제에 대한 해결책은 좋은 동시성 프로그래밍 프랙티스를 사용하는 것이다. 하지만, 안전한 동시성은 그렇게 어렵지 않다. 최소한 블라 블라 하는 것처럼. 천재만 할 수 있는 것이 아니다. 핵심은 (많은 천재들이 하지않는) 훈련이다. 몇 가지 규칙을 적용하여, 우리가 맞닥들이게 될 대부분의 상황을 쉽게 처리할 수 있다.

1. 변하는(Immutable) 객체는 자동적으로 쓰레드 세이프하며, 여러 쓰레드에 걸쳐 공유될 객체가 아니라면 쓰레드 세이프 해야할 이유가 없다. 따라서 가능한 공유할 것을 최소화 하고 가능한 immutable 객체를 사용하라.

2. 공유하는 불변의(mutabl) 객체가 정말로 꼭 필요한 경우, 모든 접근(읽기 쓰기)을 막아서 동일한 객체의 롹을 가지고 필드를 보호하거나 volatile 변수를 사용하라.

3. 이미 롹을 가지고 있는 상태에서 새로운 롹을 얻으려고 하지 말아라. 이 규칙을 따르면 자연스래, 롹을 얻으려는 시도를 할지도 모르는 "아는바없는" 혹은 "외부" 코드를 호출할 때는 어떤 롹도 쥐고 있어서는 안 된다. 이는 서비스 또는 OSGi API를 호출할 때를 말하며, 이들 중 대부분이 다른 번들의 콜백을 우리가 만든 쓰레드에서 실행하게 된다.

=> 글쿤, 롹을 쥐고 있는 상태에서 롹을 가지려고 할지도 모르는 어떤 서비스 또는 OSGi API를 호출하면 deadlock이 발생할 수 있으니, 그럴 땐 롹을 쥐고 있지 말라는 것이로군요.

=> 한가지 궁금한건 2번에서 volatile을 사용하면 모든 쓰레드에서 동일한 값을 사용하게 될텐데 그렇게 되면, 결국엔 mutable 하지 못한게 된느거 아닌가.. 흠.. A 쓰레드에서 foo.name을 a라고 하고 B 쓰레드에서 foo.name을 찍으면 a가 찍힐테고 B 쓰레드에서 다시 foo.name을 b라고 하면, 이번엔 A 쓰레드에서 foo.name을 찍으면 b가 찍힐텐데... 내가 volatile을 잘못이해한건가.. 아닌데, 맞을텐데, 아니면, mutable->immutable하게 사용하라는 것인가.. 차리리 ThreadLocal을 사용하는게 낫지 않을까. 아닌데 저자가 그걸 모를리도 없고, 아. mutable이니까, setter를 막아둬서 값 변경을 막아뒀겠구나.. 위와 같은 내 생각은 immutable객체를 공유할 때 생기는 문제지;. (흠.. 이것도 아닌가 위에선 분명 '읽기와 쓰기'라고 '쓰기'를 언급하고 있자나..) 흠..그럼 뮤터블 객체를 왜 공유해서 쓰는거지. 그럴 때 그 객체 값을 변경하지 못하면, 멀티 쓰레드 걱정 안해도 되는거 아니야? 아.. 다음 챕터를 읽어보자. 아 내 머리.
신고

'Spring DM > OSGi' 카테고리의 다른 글

OSGi 툴 세트 Pax  (0) 2008.10.21
Shared Mutable State  (2) 2008.09.25
The Price of Freedom  (0) 2008.09.25
Concurrency and OSGi  (0) 2008.09.25
BundleContext로 할 수 있는 일  (0) 2008.06.25
2 Security Layer  (0) 2008.02.18
1. Introduction  (0) 2008.02.17
top


Concurrency and OSGi

Spring DM/OSGi : 2008.09.25 10:25


참조 : http://neilbartlett.name/blog/osgibook/

J2EE 같은 무거운(heavyweight) 프레임워크에 비해, OSGi는 쓰레드를 포함한 JVM의 모든 리소스를 제어하려 들지 않는다. J2EE에선 직접 쓰레드를 만들거나 명시적인 동기화(synchronization)를 하는 코드를 작성하는 것을 금하고, 대신에 제한적인 "작업 관리" 프레임워크를 제공한다. OSGi는 여러분이 직접 애플리케이션에서 쓰레드를 만들고 스케쥴링을 할 수 있다. 그렇게 하려면 OSGi 라이브러리들은 쓰레드 세이프해야 하며 어떤 쓰레드에서도 호출할 수 있어야 한다.

=> 즉, OSGi에서는 쓰레드를 직접 다루는 코드를 작성할 수도 있으니, 쓰레드 세이프한 라이브러리를 만드는 것이 중요하다는 뜻인듯..

하지만, 이런 자유에는 댓가가 따르듯이, 우리가 만들 번들에서 쓰레드를 생성하여 사용하는것이 가능하듯이, 우리가 만들 번들이 단일 쓰레드 환경에서만 사용되리라는 보장은 못한다. OSGi는 암묵적으로 멀티 쓰레드다. 따라서 반드시 작성하는 코드가 쓰레드 세이프해야 하며, 특히 이벤트나 콜백을 다른 프레임워크 또는 번들에서 받아올 때 주의해야 한다.

=> 흠. 당연한 말씀.

Brian Goetz의 "Java Concurrency in Practice"에서 자바 동시성에 대해 자세히 다루고 있으니, 프로페셔널 자바 프로그래머라면 항상 이 책을 가까이 하라.

=> 넵.
신고

'Spring DM > OSGi' 카테고리의 다른 글

OSGi 툴 세트 Pax  (0) 2008.10.21
Shared Mutable State  (2) 2008.09.25
The Price of Freedom  (0) 2008.09.25
Concurrency and OSGi  (0) 2008.09.25
BundleContext로 할 수 있는 일  (0) 2008.06.25
2 Security Layer  (0) 2008.02.18
1. Introduction  (0) 2008.02.17
top


Generic 팩토리 메소드

Java : 2008.09.25 08:53


참조: http://www.ibm.com/developerworks/kr/library/j-jtp04298.html

흠.. 제네렉 타입을 사용한 객체를 생성할 때 유용할 것 같습니다.

Box<String> box = new BoxImpl<String>();

보통 제네릭 타입을 사용한 객체를 생성할 때 저렇게 String이라는 타입을 두 번이나 입력해야 하는데..

public class BoxImpl<T> implements Box<T> {

    public static<V> Box<V> make() {
        return new BoxImpl<V>();
    }

    ...
}

이렇게 make라는 팩토리 메소드를 만들어 두면..

Box<String> myBox = BoxImpl.make();

이렇게 타입을 한 번만 지정해도 되는군요. 오호~ 괜찮군요. 근데 굳이 V 라고 안하고 그냥 T 계속 써도 될텐데, 굳이 구분할 필요가 있었나..흠. 어차피 같은 타입 지칭하는건데..

V대신 T를 써도 무방하긴 하지만, 이 예제는 왠지 컴파일러가 제네릭 타입을 선택하는 과정을 보여주기 위해, V를 둔것 같습니다.
신고
top


베토벤 바이러스 잼나네요.

모하니?/Watching : 2008.09.24 23:56


제가 마지막으로 본 드라마는 2002년에 했었던 '네 멋대로 해라'입니다. 평소 TV를 볼 기회도 드물거니와, TV를 볼 필요도 없었는데, 6년만에 드라마를 보게됐습니다. 캬오.. 베토벤 바이러스 왜케 재밌죠;

이 드라마가 일본 '노다메칸타빌레'랑 비슷하다고 해서 노다메도 전부(11화+2화) 봤는데, 느낌이 많이 다르더군요. 노다메는 제목에서도 암시하듯이 노다메구미와 남자 주인공 한테만 너무 집중되어 있는데 반해 베토벤 바이러스는 아줌마의 한풀이도 대신해주고, 돈 없으면 음악도 못하냐고 따지고, 시장에게 '당신 같은 사람이 위대한 음악가를 다 죽인다.'고 시원하게 질러줍니다. 클래식이라는 왠지 차원이 달라 보이는 주제에 비해 내용 흐름은 상당히 서민적이라는 점이 제 관심을 끌었고, 그 다음은 '강마에'라는 캐릭터가 아주 아주 호감을 주고 있습니다.

강마에 대사 중엔 명언이 참 많은데, 그 중 단연은 '똥덩어리' 캬바라에서 온 트럼펫 연주자는 '촛불집회에 물뿌리는 경찰'을 언급했었고, 아줌마는 쌓여있는 한을 터트렸습니다. 직장까지 버리고 꿈을 찾아 떠나는 용자들... 캬오. 이 드라마처럼 신선한 드라마는 정말 오랜만인것 같습니다.



신고
top


Principle of least astonishment

모하니?/Coding : 2008.09.24 22:06


참조: http://en.wikipedia.org/wiki/Principle_of_least_astonishment

astonishment라는 생소한 단어 때문에 뜻을 가늠하기가 어렵습니다. astonishment는 경악, 놀람이라는 뜻으로, "최대한 놀래키지 말라는 원칙"입니다. 

위키피디아의 정의를 인용하면 다음과 같습니다.

In user interface design, programming language design, and ergonomics, the principle (or rule or lawof least astonishment (or surprise) states that, when two elements of an interface conflict, or are ambiguous, the behaviour should be that which will least surprise the human user or programmer at the time the conflict arises.

즉, 두 개의 애매모호 하거나 상이한 인터페이스 요소는 사용자가 프로그래머에게 혼란을 줄 수 있으니 주의하라는 것입니다.

예를 들어, 보통 Ctrl+S는 저장 단축키로 인식되고 있는데, 이 단축키를 창닫기 용으로 사용하면 어떻게 될까요? 좀 더 코딩에 가까운 예를 들면, 오버로딩한 메소드 두 개가 있을 때 그 둘의 행동은 같아야 합니다. 즉, add(Cat)과 add(Dog)은 둘 다 더해주는 객체만 달라질 뿐 내부에서 하는 일은 동일해야 하는거죠. 둘의 행위가 넘겨져온 객체에 따라 상이해질 경우 개발자나 사용자에게 혼란을 줄 수 있을 겁니다.

API 설계시에 주의해야할 원칙인 듯 합니다. OSAF를 다시 한번 검토해봐야겠습니다. Hibernate에는 사실 UPDATE sql을 직접 날릴 필요가 없습니다. 자동으로 dirty checking을 해서 필요한 순간에 flushing(DB와 SessionContext 동기화)를 할 때 필요한 UPDATE 문을 날려주기 때문입니다. 그래도 가끔은 Session의 reattch() 메소드를 사용해서, 원하는 순간에 명시적으로 UPDATE 문을 날리는 것과 비슷한 결과를 만들 수 있습니다. 

이때, reattach()를 DAO에서는 update()로 감싸야 하는게 좋을지. 그냥 reattch()라고 해야 할지 고민입니다.
신고
top


썬 테크데이 참가할 세션

모하니?/Planning : 2008.09.24 16:48


사용자 삽입 이미지

마치.. 꼭.. 찍은것(?) 처럼. 선택했습니다. 요즘 태그 파일을 만들고 있어서 그런지 화면쪽에 좀 관심이 가네요. JavaFX로 Rich 화면을 Easy 만들 수 있는지 어떤지 궁금해서 첫날은 쫙.. JavaFX쪽으로 선택했고, 둘 쨋날은.. 자바와 웹 2.0으로 쫙.. 선택했습니다.

개인적으론 OSGi나 Module에 관한 주제가 없다는 것이 아쉽지만, 뭐.. 생소한 것들도 알아둬서 나쁠 건 없겠죠. :)

그나저나, 점심이 뷔페라던데, 맛난거 나왔으면 좋겠습니다. 꺄오~ 맛난거~

신고
top


How to Design a Good API & Why it Matters

모하니?/Coding : 2008.09.24 14:53


참조 :
http://www.infoq.com/articles/API-Design-Joshua-Bloch
http://www.infoq.com/presentations/effective-api-design;jsessionid=E80287C669787CA7AD3F810A3850932B


Public API(아마 인터페이스를 말하는듯)는 영원한거다. 그만큼 신중하게 만들어야 함.

좋은 API 특징. 문서 없이도 잘 이해가 되는 API

API 설계 프로세스

요구사항을 분명히 할 것

모두를 만족 시킬 순 없다. 모두를 똑같이 실망시켜라.
- 실수 할 수도 있다. API를 진화시켜라.

미심쩍은 것은 무조건 빼내라. 나중에 추가하긴 쉽지만, 빼는 건 불가능에 가깝다.

구현에 대한 세부 사항이 API에 영향을 주지 않게 한다.

최소한의 접근성
- default 접근 지시자가 protected보다 엄격하다. 엄하게 구분해놔야 테스트하기 좋다.

작명은 중요하다.
- 마치 영어 문장처럼 읽히는 코드를 작성하라.

문서화 중요하다.
- 모든 클래스, 메소드, 필드, 파라메터, 예외에 대해 문서화하라.

API 성능에 신경써라.
- Dimension Component.getSize() 같은 API는 매번 새로운 mutable한 Dimention 객체를 생성해내서 성능이 안 좋다.

클래스 설계

mutable은 최대한 최소화하라. 되도록이면 immutable.
- Date랑 Calandar 안 좋아. 변할 수 있는데 왜 안 변해. TimerTask 처럼 좀 변하란 말야.

상속은 리스코프 원칙에 맞게 사용할 것
- is-a 관계 일 때만 사용하기.

메소드 설계

모듈이 할 수 있는 걸 고객이 직접 하게 하지 말아라.
- boilerplate 코드 작성할 필요를 없애라.

Principle of least astonishment를 위배하지 말라.
- Thread의 interrpt의 경우 안 좋은 예에 해당한다. 인터럽트 할 때 현재 상태 정보를 클리어 해버린다. 따라서 clearAndInterrupt라고 하는게 낫겠다.

Fail-Fast
- 컴파일 타임에 에러나면 좋고, 실행 중엔 첫 번째 메소드 호출에서 바로 fail하도록..
- Generic 쓰면 컴파일 타입에 타입 체크 할 수 있으니 좋다.

문자열로 데이터 보여주는 API를 제공하라.
- 안그럼 고객이 직접 작성해야 한다.
- StrackTraceElement 객체의 같은 거 좋다.

오버로딩 사용에 신중하라.
- 오버로딩 할 때는 같은 기능을 제공해야 한다.
- TreeSet의 생성자는 안 좋은 예에 해당한다. 넘겨주는 인자에 따라 행위가 다르다.

파라미터와 리턴타입
- float으로 화폐단위 표시하지 말것. 부정확하다.
- 인터페이스 타입을 사용하면 유연하고 성능에좋다.
- 구체적인 타입일 수록 컴파일 타임에 에러를 잡을 수 있다.
- 문자열 보단 특정 타입을 사용할 수 있도록하자. 문자열은 에러 발생할 여지가 많다.(흠.. 문자열을 써야 할 경우엔 해당 문자열을 상수화해서 쓰면 괜찮지 않을까.)

너무 긴 매개변수 리스트는 피하라.
- 메소드를 나누던가, 헬퍼 클래스를 만들어서 줄여라.

에러 발생 시킬 반환값을 피하라.
- null말고, 비어있는 리스트나 배열을 반환하라.

예외로 흐름 제어 하지 말아라.
- 제어문으로 해라~. 예외는 예외적인 상황일때 그것을 알려주기 위해 사용하라.

언체크드 익셉션을 선호하라.
- checked exception - 사용자가 반드시 복구해야 할 때 사용
- unchecked exception - 프로그래밍 에러

API 설계 리팩토링하기

Vector의 indexOf 메소드
- Vector, List
- ThreadLocal의 string -> Key


신고
top


KSUG 9번째 스프링 세미나



사용자 삽입 이미지

정말 오랜만에 발표를 합니다. 너무 오랜만에 하는 발표라 잘 할 수 있을지 걱정이 되는데요. 이번이 KSUG에서 하는 마지막 발표가 될지도 모르니만큼 준비를 열심히 해서 유익한 시간이 될 수 있도록 하겠습니다. 접수는 이곳에서..

Spring AOP를 주제로 발표를 맡았는데, 구체적으로 어떤 내용들을 다뤘으면 하는지 의견을 듣고 싶습니다. Spring AOP와 관련해서 평소 궁금하셨던 것이 있으신 분들은 이곳에 의견을 주시면 적극 반영하겠습니다.

신고
top


S1A 비행기 예약 + 호텔 예약

모하니?/Planning : 2008.09.23 13:20


사용자 삽입 이미지

맨 위 세 개는 가는거, 아래 세 개는 오는거 입니다.

원래는 나리타에서 1시간, 디트로이트에서 1시간 25분 텀으로 갈아타게 되어있었는데, 너무 촉박한것 같아서 여행사에 문의해서 좀 더 여유롭게 바꿔달라고 요청했습니다.

결국 나리타에서 2시간, 디트로이트에서 8시간을 보내다보니, 도착 시간이.. 12월 1일 오전 1시정도가 됩니다. 호텔에 들어가면 2시가 될 것 같은데.. 그날 자고 일어나서 바로 컨퍼런스에 참여하면 될 것 같네요. 캬오~ 호텔비가 줄어듭니다. 후훗.

나리타 항공에서 갈아타는 방법은 쉬운 것 같더군요. 짐도 알아서 이동하기 때문에, 챙길 필요도 없고, 한국어도 적혀 있으니.. 안심입니다.

디트로이트에서는 일단 입국 심사와 세관을 거친다음 갈아타야 합니다. 이건 좀 불안하지만, 시간은 넉넉하니까 차근차근 하면 될 것 같습니다.

비행기는 결제하려면 여권이 있어야 되서 저녁에 집에가서 해야 할 듯.

사용자 삽입 이미지

호텔 예약은 미리 지불하는게 아니라 다행입니다. 일단 예약 완료.

이것으로... 컨퍼런스 갈 준비는 다 됐습니다. 이제 예습해서 머리를 채우고, 영어 듣기를 해서 귀를 뚫어둬야겠습니다. 가서 주변사람들이랑 할 말도 준비해야되고 말이죠. 할 것들이 많네요.
신고
top


자바의 숨겨진 기능들

Java : 2008.09.22 23:35


대엽님 블로그에서 잼난 글을 발견하고 링크를 따라가보니, 정말 놀라운 것들로 가득찬 페이지를 발견했습니다. 스크롤을 내려가면서 아는 것도 가끔씩 등장은 하는데, 윗 부분은 정말 신기한 것들로 가득합니다. 캬~ 저런게 있었구나.. 싶을 정도로요.

저 포럼은 예전에 영회형 블로그에 올라왔던, Stack과 Heap에 대한 설명에 대해서도 굉장히 잘 설명한 댓글이 달렸던것 같은데, 수준이 상당히 높은 포럼인듯 합니다. 멋지네요.

그 중에 몇 개 살펴봅니다.

1. 더블 괄호
http://www.c2.com/cgi/wiki?DoubleBraceInitialization

더블 괄호 사용해서 컬렉션 객체 만드는 방법인데, 첨 보는 방법입니다. 하지만 개인적으론 저것 보단 자주 사용하고 있는  Arrays.asList()가 명시적이어서 더 좋네요.

2. 상위 타입 제한

public class Baz<T extends Foo & Bar> {}

이런식으로 &를 써서 여러 타입으로 제한할 수도 있었군요;

3. 동적 프록시

http://java.sun.com/j2se/1.3/docs/guide/reflection/proxy.html

이건 좀 공부해야겠습니다.

4. enum

http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.9

이넘. 자세히 보진 않았지만, 역시 잘 알아두는게 좋겠죠.

5. concurrent

http://java.sun.com/javase/6/docs/api/java/util/concurrent/package-summary.html

역시나. 잘 모르는 부분. 기초 공부가 넘 게을렀네..

신고
top


S1A(Spring One America) 질렀다. 가는거다.

모하니?/Planning : 2008.09.22 22:12


리스트의 라 캄파넬라(종소리)

낮에 카드 한도 때문에 고생했는데, 집에 굴러다니던 카드는 한도가 남아있었나봅니다. 캬하하.. 1350달러를 질러보긴 처음인데 기분이 째지는군요. 현재 환율로 155만원 정도 입니다. 몇 주 전까지만 해도 150만원 미만이였는데, 요즘 환율이 갑자기 오르는 바람에.ㅎㅎ. 낭패로군요.

제가 번 돈으로 제가 가고 싶은 세미나에 참석하게 됩니다. 다니는 회사에서 원랜 지원해주기로 했었지만, 사정이 사정이다 보니;; 걍 제 돈으로 질렀습니다. 후훗.

이제 비행기랑 호텔만 지르면 됩니다. 일단은 비행기부터 지르고,, 친구 말로는 호텔 말고 주변 여관가서 싸게 자라는데;;; 그러긴 위험할까봐 싫고, 비싸도 걍 호텔에서;; 혼자 호텔에서 된장남 놀이하는 한이 있더라도..ㅋ

사용자 삽입 이미지

오.. 나 정말.. 가는건가.. ㅎㅎㅎㅎ;; 실감이 나질 않아~

신고
top


context:component-scan 엘리먼트는 annotation-config도 등록해줌.

Spring/Chapter 3 : 2008.09.22 18:43



이클립스에서 F2를 이용해서 읽어봤습니다.

Scans the classpath for annotated components that will be auto-registered as
 Spring beans. By default, the Spring-provided @Component, @Repository,
 @Service, and @Controller stereotypes will be detected. Note: This tag implies the
 effects of the 'annotation-config' tag, activating @Required, @Autowired,
 @PostConstruct, @PreDestroy, @Resource, @PersistenceContext and
 @PersistenceUnit annotations in the component classes, which is usually desired
 for autodetected components (without external configuration). Turn off the
 'annotation-config' attribute to deactivate this default behavior, for example in order
 to use custom BeanPostProcessor definitions for handling those annotations. Note:
 You may use placeholders in package paths, but only resolved against system
 properties (analogous to resource paths). A component scan results in new bean
 definition being registered; Spring's PropertyPlaceholderConfigurer will apply to
 those bean definitions just like to regular bean definitions, but it won't apply to the
 component scan settings themselves.

Content Model : (include-filter*, exclude-filter*)

수확이 있었군, 스프링 공부할 때 살펴볼 클래스가 하나 등장했다. PropertyPlaceholderConfigurer
설정 파일 읽어서 BeanDefinition 객체로 만든다는것 까진 알고 있었는데, 어디서 누가 하는진 몰랐는데 저 녀석이 하고 있었나 봅니다. 캬오~ JavaDoc 귿이야..

신고
top


Clover 2.3.2(for Maven)

Wiki : 2008.09.22 18:27



하핫;; 부끄럽군요. 61% ㅠ.ㅠ util쪽 테스트를 대충했었네요. 크핫;; 보완해야지.

참조 : http://confluence.atlassian.com/display/CLOVER/Clover+Documentation+Home

안 본 사이에 버젼이 많이 올라갔습니다. 예전엔 그냥 maven-clover-plugin 쓰고 있었는데, maven-clover2-plugin이 되어있네요.

1. 메이븐 플러긴 설정

settings.xml 에 플러그인 그룹 설정 추가.
<pluginGroups>
    <pluginGroup>com.atlassian.maven.plugins</pluginGroup>
</pluginGroups>

pom.xml에 플러그인 추가.

<build>
    <plugins>
        ...
        <plugin>
            <groupId>com.atlassian.maven.plugins</groupId>
            <artifactId>maven-clover2-plugin</artifactId>
            <configuration>
                <licenseLocation>${clover2.licenseLocation}</licenseLocation>
            </configuration>
        </plugin>
    </plugins>
</build>

2. 사용하기

mvn clover2:instrument clover2:aggregate clover2:clover

기본으로 /target/site/clover 폴더에 결과물 생성.

3. 기능

3-1. 목표 커버리지 설정

- 목표 % 설정해 놓고, clover2:check를 사용해서 검사할 수 있고, 목표치와 관계없이 빌드 성공시킬려면 커맨드라인에 -DfailOnViolation=false 옵션 추가.

3-2. exclusion/inclusion

- 정규 표현식으로 할 수도 있고, <includesTestSourceRoots>false</includesTestSourceRoots> 이거 한 줄 추가하면 테스트 소스 코드는 전부 제외할 수 있고, <contextFilters>try,static</contextFilters> 이렇게 하면 try-catch, static 코드 블럭을 제외할 수 있음.

3-3. JDK 레벨 설정

3-4. Clover Flush Policy 설정

3-5. 리포트 형식 설정

  <generatePdf>true</generatePdf>
  <generateXml>true</generateXml>
  <generateHtml>false</generateHtml>

3-6. Clover DB 위치 설정

3-7. Clover DB 정보 가져오기

- clover2:log 사용해서 보면 됨.

3-8. 히스토리 리포트 작성

<generateHistorical>true</generateHistorical>

3-9. 커스텀 리포트 작성

몰라 pass

3-10. Clover Goal을 Maven 빌드 Phase에 끼워넣기

괜찮지만 pass
신고

'Wiki' 카테고리의 다른 글

Clover 2.3.2(for Maven)  (4) 2008.09.22
Artifactory 설치하기  (0) 2008.03.18
Confluence 개인용은 공짜.  (2) 2007.11.27
Confluence Markup  (2) 2007.04.24
Confluence Calander 사용법  (4) 2007.03.12
Confluence에서 PDF로 빼낼 때 한글 깨짐 문제 해결  (6) 2007.02.13
Confluence User Guide  (0) 2007.02.12
Confluence 설치하기  (0) 2007.02.10
XWiki 설치  (0) 2007.01.25
JSPWiki 플러긴 설치  (0) 2007.01.07
JSPWiki 플러그인  (0) 2007.01.05
top


아.. 카드한도.

모하니?/Thinking : 2008.09.22 17:53


오늘 하루 종일 반복해서 들은 곡. 베토벤 피아노 소나타 8번(비창)

1350달러를 카드로 질러야 하는데, 결제 에러가 나서 확인해봤더니, 카드 한도 초과. -_-; 카드 한도를 올리려면, 뭘 또 신청하고, 심사를 거치고, 그 뒤에 적용이 되나봅니다. 이번 달 29일까지 못 지르면 300달러를 더 내야하는데 -_-;;

일단, 카드 한도를 300으로 올려달라고 신청해두고, 카드를 새로 하나 만들지.. 아니면 방구석에 굴러다니는 다른 회사 카드를 써볼까.. 생각중입니다.

카드 한도에 걸릴 만큼 질러보긴 첨이로군요~

어라... 큰일이네; 비행기도 이번달 25일까지 질러야 되는데, 그럼 카드 한도를 올려도 모자라자나... 어쩔 수 없이 카드 두 개로 질러야겠네.. 하나는 비행기 하나는 컨퍼런스.. 어휴. 그 카드는 한도가 얼마더라; 이번 달엔 안 썼으니까 150은 지를 수 있겠지?? 흠.. 결국 꼼쳐둔 카드랑 지금 카드 한도 올려서 질러야 되는거구나. 아니다;; 비행기는 그냥 카드 말고 입금해버리면 되지. 국내업첸데 뭐.. 굳이 카드 쓸 필요 없자네. ㅇㅋㅇㅋ.. 그럼 카드 한도 올려서 지르거나, 안쓰던 카드로 컨퍼런스를 지르면 되고, 비행기는 바로 통장에서 이체시키면 되겠군.

가보자. 가봐.
신고
top


BeanLifeCycle 인터페이스를 없애보자.

Spring/Chapter 3 : 2008.09.22 16:50


BeanLifeCycle에 등장하는 여러 인터페이스 들 중에서 BeanFactoryAware, ApplicationContextAware, MessageSoruceAware, ApplicationEventPublisherAware, ResourceLoaderAware 인터페이스를 사용하지 않고도 이들이 해주는 일과 똑같은 작업을 할 수 있습니다.

@Component
public class Bean {

    @Autowired
    ApplicationContext applicationContext;
   
    @Autowired
    MessageSource messageSource;
   
    @Autowired
    ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    ResourceLoader resourceLoader;
   
    @Autowired
    BeanFactory beanFactory;
   
}

이런식으로 @Autowired를 사용하시면 됩니다. 물론 저 중에서 BeanFactory를 뺀 나머지는 ApplicationContext를 사용할 때 이용할 수 있겠죠. 라이프사이클 중에 InitializingBean 인터페이스는 bean 엘리먼트의 init-method 또는 @PostConstruct를 사용하면 대체할 수 있습니다.

꼭 필요하진 않고, 있을 때만 주입하고 싶다면, @Autowired(required=false) 이렇게 설정하면 되겠죠.

다음은 위 코드의 테스트 코드입니다,.

@ContextConfiguration(locations="springContext.xml")
public class BeanTest extends AbstractJUnit4SpringContextTests{

    @Autowired
    Bean bean;
   
    @Test
    public void lifecycle() {
        assertNotNull(bean.beanFactory);
        assertNotNull(bean.applicationContext);
        assertNotNull(bean.messageSource);
        assertNotNull(bean.applicationEventPublisher);
        assertNotNull(bean.resourceLoader);
    }
   
}

테스트는 당연히 잘 돌아갑니다.

아차. 빈 설정파일은 딱 두 줄 한 줄 입니다.
    <context:component-scan base-package="org.opensprout.sandbox.lifecycle" />
   
    <context:annotation-config />

신고
top


delete 요청 처리 컨트롤러 코드 고민

모하니?/Coding : 2008.09.22 15:47


앞선 글에서도 살펴봤지만, Cascade 옵션을 적용하려면, id 값으로 레코드를 제거하는 쿼리를 날리는게 아니라, Session의 delete(object) 메소드 호출을 해야 하는데. 기존의 컨트롤러는 삭제할 객체의 id 값을 가져오고, service.delete(id)를 호출하여 최종적으로는 id로 삭제하는 쿼리를 난리게 됩니다.

방법은 두 가지.

1. Cascade 옵셥을 사용할 녀석만 매번 OSAF가 제공할 기본 컨트롤러 코드를 다음과 같이 재정의하게 할 것인가.

//Employee.java

    @RequestMapping
    public String delete(int id) {
        service.delete(service.get(id));
        return CommonPages.CLOSE_RESEARCH;
    }

2. 아니면, 아예 OSAF 기본 컨트롤러 코드를 변경해서 기본적으로 Session.delete(Object)를 호출하게 할 것인가.

//BaseController.java

    @RequestMapping
    public String delete(int id){
        // This will not trigger additional query, because the deleting object is already exist in Session Context.
        // We'll use Session's delete(Object) method to apply cascade options.
        service.delete(service.get(id));
        return CommonPages.CLOSE_RESEARCH;
    }

두 번째 것을 선택했습니다. 이론적으로는 Session Context에 삭제할 객체가 담겨 있을테니, 추가적인 select 쿼리가 날아가지 않을 것 같아서 선택했고, 테스트를 통해 검증을 해본결과 예상이 맞았습니다. 어차피 같은 쿼리가 날아간다면, 좀더 유연하게 설정값을 가지고 Cascade를 적용할 수 있는 메소드를 사용하도록 OSAF 컨트롤러 코드를 변경했습니다.
신고

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

약간 어설픈.. OSAF 그리드 태그 완성  (0) 2008.10.17
DisplayTag 데코레이터 사용하기  (0) 2008.09.29
OSAF 검색 폼 태그 파일 완성  (0) 2008.09.25
Principle of least astonishment  (0) 2008.09.24
How to Design a Good API & Why it Matters  (0) 2008.09.24
delete 요청 처리 컨트롤러 코드 고민  (0) 2008.09.22
@Resource 활용 팁  (6) 2008.09.08
TDDBE - xUnit 23장  (0) 2008.09.01
TDDBE - xUnit 22장  (0) 2008.09.01
TDDBE - xUnit 21장  (0) 2008.09.01
TDDBE - xUnit 20장  (0) 2008.09.01
top







티스토리 툴바