Whiteship's Note


봄싹 관련 사이트 정리



봄싹 홈페이지: http://springsprout.org
봄싹 그룹스: http://groups.google.co.kr/group/springsprout?hl=ko
봄싹 이슈트래커: http://jira.springsprout.org/browse/SSD
봄싹 위키: http://wiki.springsprout.org
봄싹 코드: http://code.springsprout.org/browse/SpringSprout

이밖에도 몇개 더 있지만... 점점 취미활동 범위를 넘어서는 것 같다...
아니 어쩌면 이미 진작에 넘었는지도 모르겠다...
저작자 표시
신고
top

TAG 봄싹

[봄싹 코딩] DAO 테스트 만들기





지난 KSUG 세미나 때 깜빡하고 못보여드린 내용을 찍었습니다.
외국 서버라 많이 느리네요. ㅠ.ㅠ 일시정지를 눌러두셨다가 한참뒤에 보시기 바랍니다. 흑흑..

국내에도 깔끔하게 광고 없고, ActiveX 설치하지 않아도 되면서, 고화질, 고용량, 장시간 동영상 서비스 좀 제공해주는 곳이 있으면 좋겠습니다.

blip.tv는 다 좋은데 외쿡 서버라 느린다는것만 빼면 정말 완벽합니다.

다운받기
저작자 표시
신고
top


Adobe Flex Builder 4

Adobe : 2010.04.22 19:30


http://www.adoberia.co.kr/pds/down.html?src=text&kw=000026

Flex SDK 4와 Flex Builder 4 standaolne win 버전을 다운 받았습니다. 이클립스 플러그인 형태로도 제공해 주는데.. 플러그인 형태의 용량이 독립 버전보다 용량이 크더라구요.

http://www.adobe.com/devnet/flex/videotraining/xml/vid28.html

이전까지는 별로 필요없지 않을까 생각했는데 위 영상을 보니까 편집기가 쓸만 한 것 같습니다. 마치 비주얼 스튜디오처럼 말이죠.. 흠냐



오우.. 드래그 해보니까 느낌이 꽤 괜찮네요~ 쓸만합니다.


그냥 Run만 하면 툭 뜨는군요. 흠.. 인텔리J에서 작업하는 것보다 편합니다.

트라이얼 버전인데;; 30일 안에 마스터 해야되는건가.. ㅋ
저작자 표시
신고
top


[MXML] mx:style

Adobe : 2010.04.22 18:57


참조: http://www.adobe.com/devnet/flex/tourdeflex/web/#docIndex=0;illustIndex=1;sampleId=9800
http://sses.tistory.com/83

정성들여만든(?) 야바위 게임의 글씨가 너무 작다;; 그래서 찾아봤더니 금방 나온다.

<mx:Style>
        .myclass { 
            color: Red;
        }

        Button { 
            fontSize: 10pt; 
            color: Yellow;
        }
    </mx:Style>

    <mx:Button styleName="myclass" label="Red Button"/>
    <mx:Button label="Yellow Button"/>

이런식으로 스타일을 줄 수 있구나~





저작자 표시
신고
top

TAG Adobe, flex, MXML, style
Adobe : 2010.04.22 18:57 Trackback. : Comment.

[MXML] layout

Adobe : 2010.04.22 18:19


참조: http://www.adobe.com/devnet/flex/videotraining/xml/vid12.html

absolute / vertical / horizontal 이 세개가 끝..

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[
            import mx.controls.Alert;
        ]]>
    </mx:Script>
    <mx:Button click="Alert.show('Hello, world')" label="Say Hello" x="5" y="10"/>
</mx:Application>

absolute로 설정한다음 모든 엘리먼트에 x, y 좌표를 설정하는 노가다를 해서 성능을 향상 시키느냐.. 
레이아웃 계산좀 하게 내비두고 vertical, horizontal을 사용할 것이냐~
나는 당연히 레이아웃;; @_@;;


이런거 만들라고 공부한게 아닐텐데;;

1. 제일 밖에 있는 Application은 기본값(vertical)으로 나뒀고; 
2. '야바위' 패널은 패딩 사이즈만 설정.
3. HBox를 사용해서 이미지랑 VBox를 감싸고.
3. VBox 안에는 Lable과 HBox를 감싸고
4. HBox 안에는 버튼 세개.



저작자 표시
신고
top

TAG flex, layout, MXML
Adobe : 2010.04.22 18:19 Trackback. : Comment.

[KSUG] 10회 스프링 세미나 발표자료




발표를 너무 오랜만에 해서 그런지 너무 못한것 같아요. @_@;; 계획했던 내용도 다 전달하지 못하고 그냥 소녀시대 가지고 장난 친것 밖에 기억나지 않으시는 분들이 많을까봐 걱정이로군요.

원래 계획으로는 조금 전에 올렸던 테스트 관련 내용이 더 있었는데 '장표'에 적어놓지 않았더니 까먹었지 머에요;; 구차한 변명이라면;; 그전날 수도공사 때문에 발표준비를 하나도 못했답니다. 그 전날까지 머릿속에만 담아놨던걸 옮기지 못한거죠. 그렇게 까먹고 있다가 뒤풀이 갈 때 생각이 나더군요. ㅋㅋ

DBUnit을 사용한 DAO 테스트, mocking을 사용한 서비스 테스트, 서비스 통합 테스트, 도메인 모델 테스트 덩덩도 이야기 했었어야 하는데;;; 흑.. 다음 기회에... 

다음에는 좀 더 잘.. 하겠습니다.
저작자 표시
신고
top


서비스 계층의 비즈니스 로직을 도메인으로 옮기자

모하니?/Coding : 2010.04.20 14:06


@RunWith(MockitoJUnitRunner.class) public class StudyServiceImplTest { StudyServiceImpl service; @Mock SecurityService securityService; @Mock StudyRepositoryImpl repository; @Mock UnifiedNotificationService notiService; @Mock MemberRepository memberRepository; @Before public void setUp() throws Exception { service = new StudyServiceImpl(); service.securityService = securityService; service.repository = repository; service.notiService = notiService; service.memberRepository = memberRepository; }

....

@Test
public void addCurrentMember() throws Exception {
Study study = new Study();
study.setMaximum(2);
Member currentMember = new Member();

// check add 1
when(securityService.getPersistentMember()).thenReturn(currentMember);
service.addCurrentMember(study);
checkStudyAndMemberSize(study, 1, currentMember, 1);
// check duplicated member add
service.addCurrentMember(study);
checkStudyAndMemberSize(study, 1, currentMember, 1);
// check add 2
currentMember = new Member("keesun@email.com");
when(securityService.getPersistentMember()).thenReturn(currentMember);
service.addCurrentMember(study);
checkStudyAndMemberSize(study, 2, currentMember, 1);

// check add over limit error!!
        try {
            service.addCurrentMember(study);
            fail();
        } catch(StudyMaximumOverException e) {

        }
checkStudyAndMemberSize(study, 2, currentMember, 1);

        //TODO NO_LIMIT_MEMBER_COUNT test
}

봄싹에 있는 코드입니다. 코드가 좀.. 거시기 합니다. mockito를 사용해서 테스트 했는데 사실 mockito를 잘 모르고 mock 테스트에 대해서도 잘 모르는 상태에서 저런 테스트를 이해하기는 힘듭니다.

문제의 원인은 뭘까요?

1. 테스트 코드가 지저분해서..
2. 로직이 서비스에 있느니까..

1번이라고 생각하셔도 별로 할 말은 없습니다. ㅋㅋㅋ 저는 2번이라고 주장하고 싶습니다. 서비스 계층에 비즈니스 로직이 들어가면 어쩔 수 없어요. 목킹을 해서 저렇게 단위테스트를 하던, 느려터진 통합 테스트를 하면 되는데.. 사실 해결책이 있는 경우가 많습니다.

비즈니스 로직을 도메인 클래스로 옮겨주는거죠.

public void addCurrentMember(Study study) {
study.addMember(securityService.getCurrentUser());
}

StudyService에 있던 코드입니다. 이렇게 서비스 계층에서 도메인 계층으로 로직을 모두 옮겼는데 서비스 계층의 테스트가 필요할까요?? 무엇을 테스트할까요? study의 addMember를 호출하는지? seurityService. .getCurrentUser()를 호출하는지? 그 결과는 잘 오는지? 글쎄요.. 호출하면 당연히 호출하겠죠; 머하러 그런걸 테스트할까요. 화이트박스 테스트인지, 행위 기반 테스트인지를 할 때는 필요할지도 모르겠지만 저는 별로 그러고 싶지 않습니다. (구현 세부 사항을 일일히 확인하느니 그냥 그 시간에 코딩을 하는게;;)

그래서 제 나름대로 내린 결론은 저런 코드는 테스트할 필요가 없다는 겁니다. 당연히 잘 호출하겠죠. 물론 예외는 있습니다.

- 트랜잭션 테스트
- 메서드 보안 테스트

이 녀석들은 서비스 계층의 역할로 할당했는데 이런것들은 스터디 통합 테스트에서 하는게 적절합니다. 이번 글에서 다루고자 하는 주제와는 거리가 있으니 다음으로 미루겠습니다.

그럼 위의 테스트를 지우면 끝일까요? 

아니죠. 테스트 위치가 바뀌어야 합니다. 도메인으로 비즈니스 로직이 옮겨갔으니 도메인 클래스를 테스트해야죠.

    @Test
    public void addMember(){
        Study study = new Study();
        Member member = new Member();

        study.addMember(member);

        assertThat(study.getCurrentMembers().size(), is(1));
        assertThat(member.getStudies().size(), is(1));
    }


    @Test(expected = StudyMaximumOverException.class)
    public void addMemberException(){
        Study study = new Study();
        study.setMaximum(1);

        Member member = new Member();

        study.addMember(member);

        assertThat(study.getCurrentMembers().size(), is(1));
        assertThat(member.getStudies().size(), is(1));
        
        study.addMember(new Member());
    }

그렇게 옮겨간 테스트가 이렇습니다. 모든 경우를 다 옮기진 않았지만 요렇습니다. 서비스에서 테스트 할 때 보다 훨씬 간결하기 때문에 테스트 작성도 쉽고 이해하기도 쉽습니다. 그쵸?? 아님 말구요.ㅋㅋ

사실 이 부분을 KSUG 발표 때 보여드렸어야 하는데;; 소녀시대 때문에 깜빡했어요.
저작자 표시
신고
top


[Econovation Fair] 아이폰 앱 아이디어 & 개발 대회



http://www.econovation.co.kr/HTML/MAIN/introduce.asp

어익후.. 상금과 상품이 아주 빵빵합니다.

거기다 아이디어나 개발한 애플에 대한 권리도 뻇지 않는 것 같아요.

보통 저런거 해서 아이디어나 개발한거 다 가져가던데.. 이번 건 뭔가 다르네요. 캬~~

좋은 아이디어와 애플들이 많이 나올것 같아서 기대됩니다. +_+
저작자 표시
신고
top

TAG KT

[Objective-C] 스탠포드 강좌 4주차

IPhone : 2010.04.18 22:09



애플리케이션 라이프 사이클
- UIApplication이 라이프사이클을 관리한다.
- 실행 -> 초기화 -> (대기 -> 이벤트 처리)* -> 종료
- UIApplicationDelegate 인터페이스를 사용해서 라이프사이클 중에 할 일을 구현할 수 있다.

MVC
- nib가 V 역할함

이벤트
- 세가지 형태로 구현 가능
- 인자없이, :(id)sender, (id)sender withEvent:(UIEvent *)event

저작자 표시
신고
top

TAG iPhone
IPhone : 2010.04.18 22:09 Trackback. : Comment.

[JMX] JMX API 직접 사용하여 JMX MBean 공개하고 모니터링 및 관리하기

Java : 2010.04.15 18:39


참조: Spring Enterprise Recipe


오호.. JDK 1.5부터 그냥 들어있는 JMX 클라이언트 jconsole을 실행해봤습니다. 모니터링 정보가 나오는 군요. 머.. 이건 나중에 살펴보기로 하고;; 일단은 저렇게 모니터링 할 MBean을 공개하는 방법을 보겠습니다.

public class Main {

    public static void main(String[] args) throws IOException {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("sandbox/jmx/beans-jmx.xml");
        FileReplicator documentReplicator =
                (FileReplicator) context.getBean("documentReplicator");
        try {
            MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();

          ObjectName objectName = new ObjectName("bean:name=documentReplicator");
            
            RequiredModelMBean mbean = new RequiredModelMBean();
          mbean.setManagedResource(documentReplicator, "objectReference");
            
            Descriptor srcDirDescriptor = new DescriptorSupport(new String[]{
                    "name=SrcDir", "descriptorType=attribute",
                    "getMethod=getSrcDir", "setMethod=setSrcDir"});
            ModelMBeanAttributeInfo srcDirInfo = new ModelMBeanAttributeInfo(
                    "SrcDir", "java.lang.String", "Source directory",
                    true, true, false, srcDirDescriptor);
            
           Descriptor destDirDescriptor = new DescriptorSupport(new String[]{
                    "name=DestDir", "descriptorType=attribute",
                    "getMethod=getDestDir", "setMethod=setDestDir"});
            ModelMBeanAttributeInfo destDirInfo = new ModelMBeanAttributeInfo(
                    "DestDir", "java.lang.String", "Destination directory",
                    true, true, false, destDirDescriptor);

            ModelMBeanOperationInfo getSrcDirInfo = new ModelMBeanOperationInfo(
                    "Get source directory",
                    FileReplicator.class.getMethod("getSrcDir"));
            ModelMBeanOperationInfo setSrcDirInfo = new ModelMBeanOperationInfo(
                    "Set source directory",
                    FileReplicator.class.getMethod("setSrcDir", String.class));

            ModelMBeanOperationInfo getDestDirInfo = new ModelMBeanOperationInfo(
                    "Get destination directory",
                    FileReplicator.class.getMethod("getDestDir"));
            ModelMBeanOperationInfo setDestDirInfo = new ModelMBeanOperationInfo(
                    "Set destination directory",
                    FileReplicator.class.getMethod("setDestDir", String.class));

            ModelMBeanOperationInfo replicateInfo = new ModelMBeanOperationInfo(
                    "Replicate files",
                    FileReplicator.class.getMethod("replicate"));

            ModelMBeanInfo mbeanInfo = new ModelMBeanInfoSupport(
                    "FileReplicator", "File replicator",
                    new ModelMBeanAttributeInfo[]{srcDirInfo, destDirInfo},
                    null,
                    new ModelMBeanOperationInfo[]{getSrcDirInfo, setSrcDirInfo,
                            getDestDirInfo, setDestDirInfo, replicateInfo},
                    null);
            mbean.setModelMBeanInfo(mbeanInfo);

            mbeanServer.registerMBean(mbean, objectName);
        } catch (JMException e) {
            e.printStackTrace();
        } catch (InvalidTargetObjectTypeException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        System.in.read();
    }
}

꺄오... 

1. MBeanServer 인스턴스 가져오기
2. ObjectName 인스턴스 만들기 <- MBean의 이름(도메인:name=MBean이름)
2. MBean 인스턴스 만들기<- MBean으로 등록할 객체 설정.
3. ModelMBeanAttributeInfo 인스턴스 만들기 <- 객체의 속성에 해당함.
4. ModelMBeanOperationInfo 인스턴스 만들기 <- 객체의 메서드에 해당함.
5. ModelMBeanInfo 객체 만든 다음 2번에서 만든 MBean에 설정하기. <- 2, 3, 4번 조합
6. 1번에서 가져온 MBeanServer에 2번에서 만든 MBean 등록하기

이렇게 엄청난 과정과 Chekced Exception 들을 처리해주고..
실행할 때는 또 -Dcom.sun.management.jmxremote 이런 VM 인자까지 넘겨줘야지 모니터링이 됨.
그리고 마지막에 애플리케이션 꺼지지 않도록 System.in.read()로 대기 상태 만들어 둠.

콘솔로가서 jconsole 입력하고 MBeans 탭에서 bean 폴더 밑에 documentReplicator 찾으면 속성과 메서드를 바로 바로 실행해볼 수 있음.









저작자 표시
신고
top

TAG jmx
Java : 2010.04.15 18:39 Trackback. : Comment.

[스프링 3.0] 소녀시대와 함께하는 스프링 @MVC

Spring/3.0 : 2010.04.13 23:49


아우 귀찮아 ㅠ.ㅠ 아우 귀찮아... ㅠ_ㅠ 
괜히 만들었어~~ 괜히 소녀시대로 장난쳤어~~

퀴즈1) 태연은 뭐다??
퀴즈2) HandleAdapter는 뉴~규?

정답은 이번주 토요일 KSUG 세미나에서...
저작자 표시
신고
top


[ASM] 클래스 - 만들기

Good Tools : 2010.04.13 17:23


참조: http://download.fr.forge.objectweb.org/asm/asm-guide.pdf

ClassWriter만 사용해서 클래스를 만들수 있다.

        ClassWriter cw = new ClassWriter(0);
        cw.visit(V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE,
                "pkg/Comparable", null, "java/lang/Object",
                new String[]{"pkg/Mesurable"});
        cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "LESS", "I",
                null, new Integer(-1)).visitEnd();
        cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "EQUAL", "I",
                null, new Integer(0)).visitEnd();
        cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "GREATER", "I",
                null, new Integer(1)).visitEnd();
        cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "compareTo",
                "(Ljava/lang/Object;)I", null, null).visitEnd();
        cw.visitEnd();
        byte[] b = cw.toByteArray();

한 줄씩 살펴보자.

ClassWriter cw = new ClassWriter(0);
- ClassWriter 객체를 생성한다. 인자값 0에 대해서는 다음에 설명한단다. 다음에 읽지 뭐... @_@;

cw.visit(V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, "pkg/Comparable", null, "java/lang/Object", new String[]{"pkg/Mesurable"});
- 저 상수들은 import static org.objectweb.asm.Opcodes.*; 이 안에 담겨있다.
- 첫번째 인자(V1_5)는 자바 클래스 버전이다. 자바 1.5 버전으로 컴파일한 클래스를 만들게 될 것이다.
- 두번째 인자(ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE)는 public interface에 해당한다. 객체를 생성할 수 없으니 abstract를 선택한다.(이부분은 좀 애매함. INTERFACE인데 ABSTRACT가 꼭 들어가야 하나;;)
- 세번째 인자("pkg/Comparable")는 클래스 이름인데 풀패키지 경로로 설정해 줘야 한다. 그렇다고 타입명(Type descriptor)은 아니고 internal name으로 표기해준다.
- 네번째 인자(null)는 제네릭이다.
- 다섯번째 인자("java/lang/Object")는 상위 클래스이다. 이 때는 internal name으로 표기해준다.
- 마지막(new String[]{"pkg/Mesurable"})은 구현할 인터페이스 목록이다. 여기서도 클래스 이름을 internal name으로 표기한다.
- visit 메서드는 리턴 타입이 void다.

cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "LESS", "I"
null, new Integer(-1)).visitEnd();
- 첫번째 인자는 패스.
- 두번째 인자는 필드 이름
- 세번째 인자는 타입 (여기선 int)
- 네번째 인자는 Generic
- 다섯번째 인자는 값 (여기서는 final static 값이니까 설정했지. 보통은 null)
- visitFiled 메서드의 리턴 타입은 FieldVisitor 타입 객체다. 이 뒤에 반환받은 객체로 할 일이 없으니 visitEnd() 호출한다.

cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "compareTo"
"(Ljava/lang/Object;)I", null, null).visitEnd();
- 첫번째 인자는 패스
- 두번째 인자는 메서드 이름
- 세번째 인자는 메서드 시그너처 (Object를 인자로 받고 int 타입을 반환 한다.)
- 네번째는 Generic
- 다섯번째는 해당 메서드에서 던지는 예외 타입 목록
- visitMethod 메서드의 리턴 타입은 MethodVisitor 타입 객체다. 이 뒤에 반환받은 객체로 할 일이 없으니 visitEnd() 호출한다.

cw.visitEnd();
- ClassWriter로 할 일 다 했으니 visitEnd() 호출한다.

byte[] b = cw.toByteArray();
- toByteArray()를 호출하여 생성된 클래스를 바이트 배열 형태로 얻을 수 있다. 이 녀석을 ClassLaoder의 defineClass에 넘겨주면 Class 타입을 받아서 사용할 수 있다.

저작자 표시
신고
top


[ASM] 개요

Good Tools : 2010.04.13 15:45


참조: http://download.fr.forge.objectweb.org/asm/asm-guide.pdf

- 프로그램 분석: 파싱에서 부터 애플리케이션의 잠재적인 버그를 찾거나, 사용하지 않는 코드나 역공학에 사용할 수 있다.
- 프로그램 생성: 일반 컴파일러나 Just in Time 컴파일러 같이 분산 프로그래밍에서 사용할 스텁, 스켈레톤 컴파일러가 사용할 프로그램을 작성한다.
- 프로그램 변경: 프로그램을 최적화 하거나 AOP같이 성능 모니터링 이나 디버깅용 코드를 추가한다.

자바 소스 코드보다 컴파일된 자바 클래스를 사용할 때 얻을 수 있는 장점
- 소스코드가 필요 없다
- JVM에 로딩 되기 전에 분석, 생성, 변경 할 수 있다.(소스 코드도 가능하지만 느리고 완전한 컴파일러가 필요하다)
- 스텁 컴파일러나 Aspectj 위버 사용이 사용자로부터 감춰진다.

ASM도 그런 툴 중 하나로 컴파일 된 클래스를 사용하도록 설계되었다.
최대한 빠르고 작게 설계했다.
- 빨라야 런타임에 애플리케이션이 느려지지 않으니까
- 작아야 메모리 소비가 적을테니까

ASM 주요 장점
- 간단하다. 잘 설계되어 있고 모듈화된 API가 있어서 사용하기 쉽다. (근데 나에겐 왜케 어려운건지.. OTL)
- 문서화가 잘 되어 있고 Eclipse 플러그인도 가지고 있다. (홈피에 있는 문서 중에서는 이것밖에 볼만한게 없던데..)
- 자바 최신 버전(Java 6)을 지원한다.
- 작고 빠르고 견고하다.
- 다수의 사용자 커뮤니티가 있으니 새로운 사용자를 도울 것이다.
- 오픈 소스니까 맘대로 쓸 수 있다.

ASM 목적
- 바이트 배열로 표현되는 컴파일 된 자바 클래스를 생성, 변형, 분석 한다.
- 클래스 로딩 프로세스는 범위에 속하지 않는다.

두 종류 API를 제공한다.
- core API: 이벤트 기반 표현체
- tree API: 객체 기반 표현체

이벤트 기반 모델
- 연속적인 이벤트로 클래스를 표현한다.
- 각 이벤트는 클래스의 특정 구성 요소를 나타낸다.
- 이벤트 기반 API는 사용 가능한 이벤트, 반드시 따라야 하는 순서, 파싱할 엘리먼트 당 하나의 이벤트를 생성하는 클래스 파서, 연속적인 이벤트에서 컴파일된 클래스를 생성하는 클래스 작성기를 제공한다.

객체 기반 모델
- 객체 트리로 클래스를 표현한다.
- 각 객체가 클래스 구성 요소를 나타낸다.
- 각 객체는 자신의 하위 구성 요소에 대한 객체들을 나타내는 레퍼런스를 가지고 있다.
- 객체 기반 API는 연속적인 이벤트 모델을 객체 트리 모델로 변경하는 하거나 그 반대로 변경하는 기능을 제공한다.
- 객체 기반 API는 이벤트 기반 API를 근간으로 만들어졌다.

이벤트 기반 API
- 객체 기반 API 보다 빠르고 메모리 소비가 적다.
- 클래스 변형이 객체 기반 모델 보다 어렵다. 한번에 한 엘리먼트만 조작하니까.

ASM 아키텍처
- 이벤트 기반 API는 이벤트 공급자(클래스 파서), 이벤트 소비자(클래스 작성기), 미리 정의해둔 이벤트 필터로 구성되어 있으며 사용자 정의 생성자, 소비자, 필터도 추가할 수 있다.

이벤트 기반 API 사용법
- 이벤트 공급자, 필터, 소비자 컴포넌트를 구성한다. 
- 이벤트 공급자가 일을 시작하도록 지시한다.

구조
- asm.jar: org.objectweb.asm 와 org.objectweb.asm.signature패키지가 들어있고, 이벤트 기반 API를 정의하고 클래스 파서, 클래스 작성기를 제공한다.
- asm-util.jar: org.objectweb.asm.util 패키지는 core API를 기반으로 다양한 툴을 제공한다. (너무 대강이네;;)
- asm-commons.jar: org.objectweb.asm.commons 패키지에서 미리 만들어둔 클래스 변경기(transformer)를 제공한다.
- asm-tree.jar: org.objectweb.asm.tree 패키지는 객체 기반 API를 제공한다. 이벤트 기반 모델과 객체 기반 모델을 변환할 수 있다.
- asm-analysis.jar: org.objectweb.asm.tree.analysis 패키지는 tree API를 기반으로 클래스 분석 프레임워크와 미리 만들어 둔 클래스 분선기를 제공한다.


저작자 표시
신고
top

TAG ASM

지난 주 일요일 안면도 대하




크니까 머리도 먹어야 한다고 구워 주시는...


깨끗하게..


몸통 다 먹고~


머리까지.. 새우 머리 까는 법도 익히고.. 맛나게 냠냠..
저작자 표시
신고
top


[Objective-C] 스탠포드 강좌 3주차

IPhone : 2010.04.12 23:50



이번 강의 듣고 나서 기억나는 것

1. alloc, copy, retain 이라는 이름이 들어있는 메서드를 사용했을 때는 손수 release 해주기. 나머지는 autorelease를 사용해서 반환된거라 가정하고 쓰면 됨. 직접 만드는 클래스에서도 이런 컨벤션을 지원하도록 작성 할 것.

2. 손수 게터 세터 만들지 말고 @property 사용하자. 최신 API에서는 거의다 @property를 사용한다. @property에 옵션을 줘서 getter나 setter 만 만들 수도 있고 setter의 방식 세 가지 (assign, retain, copy) 중 하나를 선택할 수 있다.

생각난 것

자바에서도 @property 애노테이션을 도입해서 게터 세터를 자동으로 만들기를 JVM에서 지원해주면 좋겠다.자바빈 스펙에 추가해주면 안될까? JSR이라고 작성할까?
- 애노테이션 속성에 옵션을 줘서 게터나 세터만 만들 수 있게 한다.
- ASM 공부 계속해야지
저작자 표시
신고
top


[Tell, Don't Ask] 물어보지 말고 시켜라

Design Pattern : 2010.04.07 15:51


http://c2.com/cgi/wiki?TellDontAsk
http://www.pragprog.com/articles/tell-dont-ask
http://www.ccs.neu.edu/research/demeter/related-work/pragmatic-programmer/jan_03_enbug.pdf

주요 내용
- Shy Code를 작성하라.
- 어떤 객체로부터 정보를 가져와서 판단하지 말고 그 객체가 판단하도록 시키자.
- Command와 Query를 구분하자.
- Law of Demeter를 지키자.

메서드가 어디에 어느 클래스에 위치 해야 하는지에 대한 이야기인데, 가끔 코딩하다보면 이 코드가 여기 있어야 되는건지..저기로 가야하는건지 판단의 기준이 잘 서지 않을 때가 있는데 그럴 때 이 말을 떠올리면 도움이 될 것 같습니다.

 public boolean confimMember(String email, String authCode) { Member storedMember = repository.findByEmail(email); if (storedMember == null) { throw new UsernameNotFoundException(email + " 에 해당하는 사용자가 없습니다."); } boolean result = storedMember.getAuthCode().equals(authCode); if (!result) { throw new InsufficientAuthenticationException(authCode + " 인증 코드가 올바르지 않습니다."); } else { storedMember.join(); storedMember.makeAvatar(); addMemberRole(storedMember); update(storedMember); } return result; }
이 코드는 봄싹의 MemberServiceImpl 코드중 일부입니다. 즉 위와 같은 코드는 저 원칙에 위배되는 코드로 객체 지향적이지 못한 코드입니다. 객체 지향적인 코드라면 함수 호출이 아니라 어떤 작업을(method) 지시해야 합니다. 그런데 지금은 authCode를 가져와서 매개변수의 authCode와 같은지 판다하고 있지요. 바로 이 예제가 Tell, Don't Ask에서 지적하고 있는 대표적인 사례입니다.

boolean result = storedMember.isConfirmed(authCode);

이렇게 매개변수로 필요한 정보를 전달하고 결과를 돌려받으면 됩니다. 즉 isConfirmed()라는 Query 메서드를 사용해서 정보를 조회하면 됩니다. Command 메서드가 아니라 Query 메서드기 때문에 당연히 객체 내부 정보를 변경하지 않도록 주의해야 합니다. Command 메서드와 Query 메서드를 잘 구분하는 것이 저 원칙을 지키는 지름길입니다. 또한, 이렇게 하는 것이 '데메테르 법칙'을 지키는 일이기도 합니다. 최측근에게만 일을 시키게 되니까 말이죠.

단, 단점이 있는데 그건 바로. 저 상태로 끝나면 모를까. 그게 아니라 Member 클래스에 isConfirm() 메서드를 만들어 줘야 한다는 거죠. 만약 3중, 4중으로 건너 건너 요청하던 코드를 저 원칙에 따라 고친다면 그만큼 자잘한 코드들이 생길 겁니다. 

그런 단점들 대신에 얻을 수 있는 장점으로 시스템 내부의 클래스간 의존도를 낮출 수 있다는 것입니다. 따라서 그 둘간의 저울질을 잘 하고 선택하시기를...

봄싹 코드는 이제 저 기준에 따라 모든 클래스의 코드를 리뷰하고 코드 뜯어고치기 작업을 진행합니다. 그게 끝나면 패키지 간의 의존성을 점검해봐야겠습니다.

저작자 표시
신고

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

[OOAD] 객체지향 원칙 1. SRP  (2) 2010.05.07
[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
top


[주말 코딩] 봄싹 위키

모하니?/Coding : 2010.04.04 22:51



왼쪽에는 모든 위키 목록, 오른쪽에는 최근 작업한 페이지 목록.. 각 목록의 이미지를 클릭하면 하단에 설명 부분이 열립니다. 페이지 목록에서는 미리 보기 형태로 페이지를 보여주는데;; 디자인이 좀 깨지기 때문에 직접 가서 보는게 좋겠습니다. 해당 위키나 페이지로 이동하려면 이미지가 아니라 제목 주변을 클릭하시면 됩니다.

자바 코딩하는 데는 1시간도 안걸렸는데 화면 설계하고 코딩하는데 3시간 걸리네요. @_@;; 이렇게 보여줄까 저렇게 보여줄까? 이게 보기 편할까? 저게 보기 편할까? JQuery에 toggle을 어떻게 쓰더라. 옵션이 머지. accodoan을 써볼까 어쩔까.. 덩덩덩...

위키 목록은 Confluence REST API를 호출하여 가져오고, 최근 글 목록은 Confluence에서 최근 30일 내에 글 10개를 가져오도록 만들어 둔 Atom Feed를 사용해서 가져옵니다. 매번 요청할 때 마다 두 URL로 요청/파싱을 해서 그런지 느립니다. @_@;

내부 구현을 DAO를 사용하도록 바꾸는 작업은 KSUG에서 발표 할 때 해볼까 합니다.
1. 각 목록에 새로고침 버튼 추가.
2. 해당 버튼은 "관리자" 권한이 있는 사용자만 보이고 사용할 수 있음.
3. 새로고침을 누르면 WikiSpace와 WikiPage DB를 모두 비우고 새 데이터를 추가.
4. 위키 페이지 보여줌.
5. '일반' 사용자가 위키 페이지를 클릭하면 DB에 저장되어 있는 데이터를 가져옴.

이렇게 하면 아마 스프링 시큐리티, 스프링 MVC, 하이버네이트 코딩까지도 보여드릴 수 있을것 같습니다.
Comming Soon!
저작자 표시
신고
top


[ROME] RSS, ATOM 등 피드 다루기

Good Tools : 2010.04.01 17:05


참조
http://wiki.java.net/bin/view/Javawsxml/Rome
http://wiki.java.net/bin/view/Javawsxml/Rome05Tutorials
http://wiki.java.net/bin/view/Javawsxml/Rome05TutorialFeedReader
http://today.java.net/pub/a/today/2006/02/02/tour-of-rome.html

피드 읽기 용으로 사용할 수도 있고 여러 피드를 병합해서 새로운 피드를 만들 수도 있습니다. 
그런데 문서가 좀 시원찮아서;; @_@; JavaDoc만 보고 코딩하라는 건지..

from: http://wiki.java.net/bin/view/Javawsxml/Rome04HowRomeWorks

그나마 제일 보기 좋은 자료입니다.

SyndFeedInput 객체를 만들고, build 메서드를 실행하면서 가져올 Feed의 URL을 전달해주면 일단 준비 끝.

        SyndFeedInput input = new SyndFeedInput();
        SyndFeed feed = input.build(new XmlReader(new URL(FEED_URL)));

API중에서 핵심적인 부분을 세 부류, SyndXxx, RSS용, Atom용으로 나눌 수 있는데 RSS용이나 Atom용 API를 굳이 쓸필요가 없다면 그냥 그 둘의 추상화 API인 SyndXxx를 쓰는게 좋겠습니다.

나머진 API 보면서~ 즐거운 코딩을~

저작자 표시
신고
top

TAG rome

[JSON in Java] JSON에서 필요한 데이터 뽑기

모하니?/Coding : 2010.04.01 15:26


참조: 
http://www.json.org/java/
http://decoder.tistory.com/38

예전에는 JSON.simple 이라는 프로젝트였나본데, 소스 코드를 묶어서 주네요. 의존성도 없고 깔끔하군요. 최근까지도 계속 업데이트를 하고 있는 것 같으니 믿고 써볼만 해 보입니다.

몇일 전 Confluence 위키 내용을 RestTemplate을 이용해서 가져온 적이 있는데, 그 데이터 타입을 XML로 받을까 JSON으로 받을까 고민했었는데 그냥 JSON으로 받기로 했습니다. XML 받아서 OXM으로 파싱해도 되는데 일단 전송되는 텍스트량이 XML은 너무 많고 JSON은 꽤 간결하기 떄문입니다. 그 뒤에 객체로 변환하는 과정이 둘 중에 어떤게 편하냐를 가지고도 판단해보려고 했는데 OXM 써보기도 전에 JSON으로 기울태세 입니다.

        RequestCallback callback = new SpringSproutDefaultRestRequestCallBack();
        ResponseExtractor<String> extractor = new SpringSproutJsonRestResponseExtractor();

        RestTemplate restTemplate = new RestTemplate();
        String result = restTemplate.execute(SPACE_LIST_URL, HttpMethod.GET, callback, extractor);
        System.out.println(result);

        // ref: http://decoder.tistory.com/38
        JSONObject spaceListJSON = new JSONObject(result);
        JSONArray spaceJSONArray = spaceListJSON.getJSONArray("space");
        for(int i = 0 ; i < spaceJSONArray.length() ; i++){
            JSONObject spaceJSON = spaceJSONArray.getJSONObject(i);
            System.out.println(spaceJSON.getString("name"));
            System.out.println(spaceJSON.getString("key"));
            System.out.println(spaceJSON.getString("description"));
        }

캬.... 간단하군요. 이제 저 코드를 Extractor 쪽으로 옮겨서 RestTemplate 호출할 때 자동으로 ConfluenceSpace 컬렉션 객체가 튀어나오도록 해봐야겠습니다.

저작자 표시
신고
top


[ASM] 클래스 - 파싱하기

Good Tools : 2010.04.01 11:16


참조: http://download.fr.forge.objectweb.org/asm/asm-guide.pdf

ClassVisitor 인터페이스를 구현하여 간단하게 파싱하는 클래스 작성 가능.

public class ClassPrinter implements ClassVisitor {

    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
        System.out.println(name + " extends " + superName + " {");
    }

    public void visitSource(String s, String s1) {
    }

    public void visitOuterClass(String s, String s1, String s2) {
    }

    public AnnotationVisitor visitAnnotation(String s, boolean b) {
        return null;
    }

    public void visitAttribute(Attribute attribute) {
    }

    public void visitInnerClass(String s, String s1, String s2, int i) {
    }

    public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
        System.out.println(" " + desc + " " + name);
        return null;
    }

    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        System.out.println(" " + name + desc);
        return null;
    }

    public void visitEnd() {
    }
}

이 클래스 사용하기

    public void asm() throws IOException {
        ClassPrinter cp = new ClassPrinter();
        ClassReader cr = new ClassReader("java.lang.Runnable");
        cr.accept(cp, true);
    }

ClassReader 인스턴스를 만들 때 어떤 클래스를 파싱할지 지정한다.
accept를 호출하면 전달받은 ClassVisitor(여기서는 그 구현체 ClassPrinter)의 메서드를 호출하여 파싱할 클래스 정보를 파싱한다.(꼬인다 꼬여;)

java/lang/Runnable extends java/lang/Object {
 run()V

결과는 위와 같음.

ClassReader 객체를 만드는 방법은 여러 가지가 있다.


ClassLaoder의 getResourceAsStream 메서드를 이용하여 가져온 InputStream으로 만들 수도 있다.

cl.getResourceAsStream(classname.replace(’.’, ’/’) + ".class");

하지만 복잡하다. 너무 저수준 API 아닌가... @_@ 이렇게까지 쓰고 싶진 않다.
저작자 표시
신고
top


[ASM] 클래스 - 인터페이스와 구성요소

Good Tools : 2010.04.01 10:23


참조: http://download.fr.forge.objectweb.org/asm/asm-guide.pdf

컴파일된 클래스 생성 또는 변경할 때 사용하는 핵심 API는 ClassVisitor 인터페이스.


이 API는 다음 순서대로 사용해야 함.

1. visit 호출.
2. visitSource 최대 한번 호출 가능.
3. visitOuterClass 최대 한번 호출 가능.
4. visitAnnotation과 visitAttribute 원하는 만큼 호출 가능.
5. visitInnerClass, visitField, visitMethod 원하는 만큼 호출 가능.
6. visitEnd 호출.

주요 구성요소
- ClassReader: 바이트 배열로 받은 컴파일된 클래스를 파싱하고 accept 메서드의 인자로 전달된 ClassVisitor 객체에 있는 visitXxx 메서드를 호출한다. 이벤트 공급자.
- CLassWriter: ClassVisitor 인터페이스 구현체로, 직접 바이트 형식으로 컴파일된 클래스를 만든다. toyteArray 메서드로 컴파일된 클래스를 담고 있는 바이트 배열을 가져올 수 있다. 이벤트 소비자.
- ClassAdapter: ClassVisitor 인터페이스 구현체로, 이 객체에 대한 모든 메서드 호출을 다른 ClassVisitor 인스턴스에 위임한다. 이벤트 필터.


저작자 표시
신고
top

TAG ASM, class

[아이튠즈] 아이폰이나 터치보다 중요한거~

Good Tools : 2010.04.01 08:19




요즘은 RSS를 거의 보지 않는다. 피드 관리를 잘못해서;; 언제 한번 초기화 하고 다시 모아야 하는데 귀찮아서 안하고 있다. @_@;

애니웨이, 아이튠즈 U는 대단하다. 예일, 하버드, 스탠포드 등 유명 대학의 강의들이 제공된다. 특히 요즘 보고 있는건 스탠포드에서 강의했던 아이폰 개발 강의다. 애플 직원이 나와서 학생들한테 강의를 한다. 그리고 그걸 무료로 아이튠즈를 통해서 볼 수 있다. 그뿐인가, 다운도 받을 수 있고, Podcast로 등록되고, 귀찮으면 자동으로 동기화 시켜 아이폰이나 터치에 넣고 다닐 수 있다. 인코딩 따윈 필요없다. 이미 되어 있는 걸 제공하니깐.

한국의 대학들은 등록금 올리기만하고 발전하는 기미가 보이지 않는다. 고대생과 서울대 용자들을 보면 발전은 커녕 오히려 퇴보하고 있는 것 같기도 하다. 시대에 필요한 인재를 만들어 내려면 시대에 맞는 수업과 시대에 맞는 수단으로 학습을 꾀하는게 좋치 않을까? 어쩌면 한국의 대학들은 인재를 만들고 싶은게 아니라 돈을 만들고 싶어하기 때문에 그런 발전이 없는 걸지도 모르겠다.

힘들게 번 돈, 수준 낮은 대학 강의 들으려고 등록금(졸업까지 약 4천만원)으로 날리지 말고, 그냥 200배 싼 아이폰이나 터치(약 20만원)를 사자. 응?!!
저작자 표시
신고
top







티스토리 툴바