Categories
Life

처음부터 대작을 만들려고 하지 마세요

괴테는 그의 비서이자 작가지망생이었던 에커만에게 이런 말을 했다.

처음부터 대작을 쓰려고 하지 마세요. 그런 과욕 때문에 많은 시인들이 고민을 했고 나도 그랬습니다. 그러나 나는 곧 그래서는 안 되며 그럴 수도 없다는 것을 깨달았지요. 만일 내가 이 점을 조금만 빨리 깨달았다면 백 권의 책을 더 쓸 수 있었을 것 입니다.
현재에는 현재에 요구되는 것이 있습니다. 그런데 대작을 구상하고 있노라면 현재의 것이 솟아오르지 못합니다. 그럼으로써 시인의 마음속에 나날이 솟아오르는 사상과 감정은 통로를 잃고 막혀버려서 그의 하루하루는 삶의 즐거움을 잃게 됩니다.
세상은 넓고 풍부하며 인생은 다양합니다. 그러므로 시를 쓸 재료가 없어지는 법은 없습니다. 만일 지금 가능한 것만 생각한다면 시는 모든 기회에서 만들어집니다.
나는 휴른슈타인에게 직조공을 소재로 한 시를 쓰라고 권했는데 나는 그가 성공하리라고 확신하고 있습니다. 그는 그 분야를 잘 알고 있거든요. 그처럼, 아직은 손에 없는 미래에나 가능한 대작을 꿈꾸지 말고, 지금 쓸 수 있는 것을 자연스럽고 순수하고 정직하게 생생하게 써보도록 하십시오.

안상헌 씨의 책 자신감 140페이지에 인용된 글인데요.

저는 시인도 아니고 아티스트도 아닌, 필요하거나 재미있는 무엇을 만들기 좋아하는 프로그래머지만 저에게도 괴테의 저 말은 많은 힘이 됩니다. 무엇인가를 공부하려고 할 때, 프로젝트를 시작할 때, 잡다한 TODO를 처리할 때에도 도움이 되는 내용입니다.

GTD에서 Allen이 말하던 ‘물과 같은 마음’과도 통용됩니다.

Allen has found a way to achieve stress-free productivity, what he calls a “mind like water”, to use a karate analogy. You can do things without worrying about what else is being left undone.

마지막으로 자신감 p142, 인상깊은 구절을 하나 더 옮깁니다.

많은 사람들이 살아가면서 하고 싶은 것들이 많지만 언젠가는 그것을 할 자신감이 생기는 날이 올 것이고 그때는 시도하겠다는 결심을 하며 살아간다. 그냥 살다보면 두려움이 사라질 것처럼 생각하는 것이다. 하지만 두려움은 결코 사라지지 않고 지금처럼 우리를 지배해갈 것이다.

안상헌씨 책은 참 좋아요~

Categories
Development

iBATIS 접견

나는 언제까지 원시인 코딩을 계속 할 것인가.

나는 왜 아직도 extends HttpServlet 을 하여 웹프로그램을 만드는가.
나는 왜 아직도 vim 과 editplus 뿐인가.

spring, hibernate <- 이 두녀석은 요상하게 정이 안가서, 계속 쌩까고 있는 중이다.
내 입맛에 맞는 적절한 entry point 가 있어야 된다. 그게 아니면 그냥 ‘저거 뭐하러 써? 저거 없이도 다 되잖아..’ 하며 회피하기 일쑤.

그러다 Apache Wicket 에 관심이 가서 요리조리 공부중이다.
일단 이녀석은 내 마음에 든다!!!

난 GUI 프로그래밍 출신이 아니였던가. jdk 1.1로 MSJVM에서 awt 가지고 했던 수많은 삽질들..
어린 시절, 지금은 꾸리꾸리하기만한 Swing Metal LNF가 어찌나 맘에 들었는지.. applet 에서 swing을 쓸 수 있는 날이 오기만을 기다린 시절도 있었다.

swing 삽질은 JMSN 개발할 때 삽질 정도가 하늘을 찔렀고, 어느덧 swing 코딩은 내게 뇌없이 GUI를 만들 수 있게 해주는 그런 친숙한 녀석이 되었다. 마침 swing을 중급이상으로 다루는 사람이 거의 없는 대한민국에서는 노력대비 고수익 :$ 프리랜서 프로젝트 거리가 많이도 들어왔었다.

그런데!!! Wicket 코드를 보면 swing 스타일이다 :$ 이게 무슨 얘긴고하니, 첫인상이 좋다는 이야기다.
wicket 문서들을 계속 읽다보니 어느덧 이 웹프레임워크에 매력을 느끼게 되었고, 둘러둘러 보다보니.. wicket 에는 db 코딩 쉽게 해주는? 그런 녀석이 없었다. 그래 기왕 딴놈들이 만든 프레임웍 쓸꺼면 풀세트로 써야하지 않겠나.

Wicket 에서 Spring을 통해 iBATIS를 사용하는 방법을 보다가.. 정말 뜬금없이 iBATIS에 꽂힌 것이다. Hibernate을 선택하지 않은 이유는 iBATIS는 ORM이 아니라서.. 더하기 iBATIS는 code generator인 Abator(지금은 iBATOR로 이름이 바뀌었다)를 제공해줘서 그랬다.

그런 연유로 -_- iBATIS를 공부하게됐다.

iBATIS 사이트의 60페이지짜리 pdf 문서와 iBATIS in action을 읽은 후, iBATIS 훈련을 위해 적용해볼만한 서비스를 고려해보다가. 귓속말이 당첨됐다.

그리하여-

귓속말에 iBATIS를 적용했다. 기존 날코딩 되어있던 SQL을 SqlMap.xml 파일에 빼는 것도 일이지만, #melong:VARCHAR# 같은 거 익히고 include refid로 sql들 잘근잘근 쪼개놓기도 하고 # 열고 # 안닫았다가 NoSuchElementException 나서 완전 당황하기도 하고 -_-; 자꾸 <select> 에서 resultClass 빼먹어서 삽질하질 않나 -.-;;

여튼 80여개의 쿼리가 50여개로 줄었으며, java 소스코드는 정말 화악- 줄어들었다.
이정도의 효과를 보여주면서.. 이렇게 배우기 쉽고 적용하기도 편한 framework 이 있을까 +_+

마지막으로 귓속말에 iBATIS를 적용하기 시작한 지난 새벽 2시부터 마이그레이션 및 테스트를 마친 오후 2시까지 사투의 흔적 -_-

OpenID-Whisper Error mails

Wicket 공부 및 귓속말에 적용하기가 끝나면 그 다음엔 Hibernate과 함께 ORM 고고싱~

Categories
Development

commons-daemon jsvc 개선

첫 회사를 다닐때부터.. 리눅스에서 Java 프로세스 띄울 때 setproctitle 도 먹게 하고 싶기도하고
/etc/init.d/named start|stop 처럼 Java 로 만들어진 데몬들을 제어하고 싶었다.

예전 xrath.com 서버에서 invoker 란 이름으로 자그마한 개인프로젝트를 했었는데, 이녀석은 JNI로 CreateJavaVm 을 실행하고 요짓죠짓을 하는 녀석으로 윈도우면 서비스에 등록하고 start/stop 시그널을 받게 하는 거였고 (한창 resin 2.0 시절에 -install 옵션을 주면 설치되는 멋진 모습도 기억이!) 리눅스면 sigint sigterm sighup 같은 것을 처리하..지는 못하고 그저 jvm 을 실행해주는 native executable을 빌드해주는 정도였다.

이 프로젝트의 가장 큰 문제점은 native executable로 만들 프로그램이 돌 시스템에 컴파일 환경이 구축되어있어야 한다는 것이였다. 필요한 클래스패스나 JVM 옵션들을 설정파일로 빼두긴 했지만 c 코딩이 똑바로 안되던 시절이였기 때문에 필요한 프로젝트 프로퍼티들을 c 코드 템플릿 내에 쳐박고 cl.exe 나 gcc 로 고고싱하는 지금 생각해보면 참 무서운 ;; 녀석이다.

하지만 윈도우즈 서비스 목록에서 Java Launcher <- 라고 나오면 참 자존심 상하지 않겠는가!
Super Fantastic Chatting Server <- 이렇게 등록하고 싶단 말이였다;;

암튼 서론은 끝

미루고 미루다 본 apache jakarta commons daemon 의 jsvc

나름 괜찮은 feature들을 가지고 있지만, 아쉬운 점들이 꽤나 있다.
jsvc의 아쉬운 부분들을 어느 분이 친절히 설명해준 페이지도 있다. 요약하자면,

  • jsvc 를 실행시킬 때, 절대 혹은 상대경로로 지정하는 것만 가능하다. PATH에만 있으면 안된다! 예를 들어 jsvc가 /usr/local/bin 에 있고 현재 디렉토리는 /home/rath/work/xxx 라면 jsvc 가 동작하지 않는다.
  • – jsvc 를 실행하려면 root 권한이 필요하다 -_-
  • – 옵션 -errfile 을 지정하지 않으면 모든 에러메시지들이 /dev/null로 날아가버린다 (이건 뭐.. 지정하면 되지 까탈스럽기는)

하지만 jsvc는 자바 프로그래머에게 sighup 과 sigterm을 처리할 수 있게 해준다!!
그래서 jsvc native c 코드를 좀 건드려서 해결했다.

첫번째 문제는 실행시킨 프로세스를 detach 하는 용도로 execve를 쓰고 있어서 생기는 문제인데 execve의 첫번째 파라미터가 pathname이다. filename이 아니라는 점. 그러니 터미널에서 PATH 에 잡아놨다고 좋아라~ 하고 jsvc -cp xxx test 하면 execve 에서 에러 -_-.
environ을 넘기려고 ve을 쓴 거 같은데, 유연성보다는 편리성을 택하기로 하고 execvp 로 교체하여 해결.

두번째 문제는 비교적 간단히 해결했다. jsvc 실행옵션 중 -user 가 있는데 문제가 -user 값이 넘어오지 않았을 때도 set_cap 을 쓴다. 그저.. user value 가 NULL 일 때는 set_cap 질하는 펑션 모두를 호출하지 않도록 바꿔버렸다.

세번째 문제는.. 사실 별 문제도 아니라고 생각하는데, -outfile -errfile -pidfile 옵션을 주지 않았을 때 디폴트로 현재디렉토리에 stdout.txt stderr.txt pid 란 이름으로 파일을 생성하도록 바꿨다.

마지막으로 jsvc 문서나 jsvc -help 에는 나와있지 않은, setproctitle!

리눅스에서만 쓸 거라면 기냥 argv[0] 건드리면 될텐데 왜 proctitle 고치는 게 없을까? 해서 소스코드를 살펴보니 -proctitle 옵션이 있다! 그런데 무슨 이유인지 옵션처리 if else 에서 골키퍼 else 부분 밑에 코딩되어있다. 뭔가 문제가 있어서 막아두었나 보다. 아무튼 가볍게 copy and paste 하여 활성화했다.

그런데 proctitle에 약간 문제가 있다. 보통 jsvc로 실행하려면

jsvc -cp commons-daemon.jar:my.jar -pidfile my.pid -proctitle MyRomanticDaemon com.xrath.romantic.Launcher

라고 입력하는데 -proctitle 옵션에 MyRomanticDaemon 이라고 입력해봐야 ps 에는

MyRomanticDaemon -cp commons-daemon.jar:my.jar -pidfile my.pid -proctitle MyRomanticDaemon com.xrath.romantic.Launcher

이렇게 나온다는 것 -_-
안이쁘잖아요 ToT

단순히 argv[1] = NULL 이 안먹히는 걸 보니 Unix C는 어려워 어려워 :'(
이 문제가 해결되면 jsvc-src/native/jsvc-unix.c 랑 jsvc-src/native/arguments.c 의 패치파일을 공개할 생각인데, 아직 argv[1] 이하가 안지워져서.. 부끄러워서 공개는 못하고 있다.

욕심같아서는 commons-daemon 자바 인터페이스에 setProcTitle 메서드가 있어서 현재 데몬 상태(proctitle)를 동적으로 바꿔서 sendmail처럼 ps 에서 확인할 수 있게 하는 것인데 JNI 브리지 새로 만들어야하니 천-천-히 해볼 생각.

Categories
merveille

Dear rath.

   아, 오늘은 이 홈페이지 주인이자, 제 사랑하는 남편의 생일입니다. 사실 공개적인 편지라는 것이 조금 창피하고 두서 없이 지난 시간을 써 놓은 일이라 부끄럽지만, 편지를 하나 올리려고 합니다. 의도치 않게 RSS로 수신하시는 분들, 방문하셔서 읽으시는 분들, 내키지 않더라도 용서하셔요. (찡긋)

Dear rath.

   기억해? 서로 메신저로 간간히 연락을 하다가 마치 어릴때 손을 호호 불면서 추운 거실에서 썼던 편지처럼 귓속말로 서로 고민을 나누고는 했었잖아. 서로 ‘서울 사는 30대 남성’, ‘서울 사는 20대 여성’이 되어서 말야. 이제 내 귓속말 페이지에 그 글들이 남아있지 않다는 것이 정말 아쉽지만 그래도 잘 모르는 서로를 위로할 수 있었던 시간들이 생생히 기억나.

   어느 날인가 집에 의자가 배달와서 조립을 하는데 너무 심심한거야, 그래서 너랑 전화를 하다가 얘가 커피를 마신다니 나도 갑자기 커피가 너무 마시고 싶은데 우리집에 커피가 떨어졌었지 뭐야. 우리집도 커피 배달 해달라고, 나 배고프니까 짬뽕이나 카츠나베도 배달해 달라고, 기왕이면 의자도 조립 할 줄 알고 옷상자도 버려 줄 사람으로 보내 줬으면 좋겠다고, 이런 시시껄렁한 농담을 하면서 너는 점심먹는 것도 잊은 채로 40분이 넘게 통화 했었는데. 그 뒤로도 니가 내 앞에서 말이 없었던 적은 없었던 것 같아. 처음에 사람들이 네가 말이 없다고 할 때 마다 나는 얼마나 이해 안됐는데! 참, 그리고 지금 내 남편은 의자 조립은 못하지만 설겆이를 잘하니까 괜찮아. 난 의자 조립 잘 하거든, 좋은 사람으로 보내줘서 배달 정말 고마워. 🙂

   그 날, 저녁에 영어과외가 끝났는데 얘가 저녁을 안 먹겠다지 뭐야, 그래서 생각난김에 전화해서 나오랬더니 바쁘다고 하고, 그럼 나오지 말던가 했더니 그말에 바로 나오겠다고 했던 너. 사실 청개구리지? 그날은 정말 계속 웃었던 기억 밖에 안나. 서로 덤앤더머라고 멍청한 짓들을 얼마나 많이 했던지. 너도 참, 방금 하품한 사람한테 왜 우냐고 물어보지를 않나-.-;;; 그리고 지금 생각해도 그때의 너의 3색 코디는 잊을 수가 없어. 또 그렇게 입으면 그 옷들 다 잘게 찢어서 베게 만들어 버릴꺼야.

   그 다음날도 사람들과 함께 만나고, 그 다음날에는 밤새 또 메신저로 이야기 했는데. 그래, 그날이야. 내 생일에 내가 좋아하는 곡 연습해서 연주해 줄꺼라고 약속했는데, 너 월요일에 안 지켜놓고 너무 당당하더라? 그거 두고두고 삐졌을 때 마다 써먹을꺼야. 😛 그때 내가 그렇게 좋아 했는데!

   그리고 또 그 다음날 밤, 습관처럼 전화를 하다가 나 잠들었잖아. 근데 잠에서 깨기 전까지 한번도 네 목소리가 좋다고 생각해 본 적 없었는데 잠깐 졸고 나니까 다른 목소리가 들리는 것 같았어. 어릴 때 좋아했던 동네 이웃집 오빠 생각이 나서 피식 웃었어.

   긴 통화와 함께 밤을 보내고 맞은 월요일. 둘 다 밤샘 대화에 지쳐서 실컷 자고 일어나서 지겹지도 않았는지 또 전화를 하다가 내 다른 사람 때문에 후다닥 전화를 끊었잖아. 그게 너무 미안해서 안절부절 못하다 메신저에서 미안하다고 하면서 마음이 정말 이상했어. 정말 우리가 친하게 연락한 것은 며칠 뿐이었는데, 서로 통화하면서 남자나 여자로 안 볼 사이라 편하다고 하면서 좋은 친구 만났다고 좋아했는데, 어느새 이 사람이 내 감정을 위협할 수 있는 위치에 와 있다는게 너무 무서웠어. 너도 그랬어?

   밤새 다 하지 못했던 말들이 마음속에서 웅웅거려서 멍하게 컴퓨터를 껐다가 켰다가 인터넷을 했어. 이게 무슨 바보짓인가 싶은데도 끝나지 않는거야. 그러다가 들어간 네 홈페이지에서 처음 네 노래를 들었어. 그리고 오후까지 멍하게 있으면서 그냥 계속 같이 놀고 싶다는 생각이 버려지지 않아서, 결국 우리는 다시 전화를 들었잖아. 막으려고 들고, 막아야 겠다는 생각이 드는 감정들은 이미 사랑일지 모른다고 나는 이제 생각해.

   그날 네가 했던 말 너는 잊었을까.
   “자고 일어나면 괜찮을 줄 알았는데, 자고 일어나도 괜찮지 않더라.”라던,
   그날 나를 찾아와 팔보다 마음에 힘줘서 나를 꼭 안았던
   그때 그 느낌은 나는 오래도록 지워지지 않을 것 같아.

   며칠이 지나서 우리가 첫 키스를 하기 전까지 우리 서로 뭘 하는지 서로 좋아하는지 무슨 감정인지 전혀 모르고 만났다는 것이 내가 이 글을 쓰면서도 정말 믿을 수 없는데, 정말 우리는 그랬어. 응, 이게 우리의 시작이었어.

   이것도 기억나? 1월 31일에, 내가 너 놀리면서 “괜찮아, 10년감이야.” 라는 말을 했는데, 너 ‘괜찮아, 신랑감이야.” 라고 들었던거? 사람이 말이 씨가 된다더니. 정말 니가 신랑이 될줄이야.-.-

   이날 이후로는 우리 거의 한시도 떨어진 날 없었어. 만나면 30시간, 집에 들어가면서 통화하고, 자고 일어나서 통화하면서 준비하고, 만나면 또 30시간. 날 춥고 오갈데 없어서 결혼하기로 했다는 말 가끔 사람들 안 믿던데, 정말 날만 좀 따뜻했어도 우리 결혼은 미뤄졌을지도 몰라.-.-

   그래도 어디든 좋았어, 함께 였으니까.
   그리고 지금도 행복해, 함께 있으니까.

   이제 우리는 결혼했고 매일을 함께 나누고 저기 문너머에 지금도 네가 있어. 이게 해피엔딩일까? 나는 아니라고 생각해, 이 이야기에 엔딩은 아직 나지 않은거니까. 현실은 ‘ 그들은 오래오래 행복하게 살았습니다. ‘ 한 줄로 요약할 수 없는거잖아. 어떻게 보면 두서없이 장황하게 우리의 시작을 이렇게 공개적으로-그러나 너 몰래- 쓰고있는 이유는 오늘은 네 생일이지만, 좀 더 뜻 깊은 선물을 우리에게 하고 싶었어.

   그저 함께 있고 싶었던 마음이 사랑이 되었고, 마음과 바램만으로 서로 같은 공간에서 숨쉬면서 살 수 있는 마법같은 현실을 만들어 냈다는 것. 믿어져? 나는 아직도 가끔 꿈 같아.

   생일이라는게 사실 그렇게 특별한 날은 아닐 수도 있지, 오늘은 그냥 금요일이고 스쳐지나가는 실낱같은 날들 중에 하나지만 그래도 태어나 줘서 고마워. 날 만나기 전까지 잘 지내줘서 고맙고, 내 옆에 있어줘서 고마워.

   그리고 사랑해.

– elle

p.s. 글로도 못다한 기억도 나누었던 말도 많지만 더 쓰다간 책한권 나올 것 같아
p.s. 정말, 사랑해..

Categories
Development

Apache Wicket 을 배워봅시다. Hello World 편

Wicket Hello World 예제 [원문: Apache Wicket – ExampleHelloWorld]

HelloWorld 를 실행하기 위해 wicket binary 및 의존성 library 들을 가져다 놓습니다.

1. Apache Wicket 1.3.3 을 다운로드 한다. 수많은 jar 들 중, wicket-1.3.3.jar 만 필요.
2. slf4j 다운로드. jar 파일이 우르르 나올텐데 그 중 slf4j-api-1.5.2jar 와 slf4j-log4j12-1.5.2.jar 만 취한다.
3. commons-logging-1.1.1.jar 다운로드
4. log4j 1.2.x 다운로드

위와 같이 총 5개의 jar 파일이 WEB-INF/lib 에 있으면 wicket application 을 구동할 준비가 다 된 것입니다. (slf4j-log4j12 대신 slf4j-simple을 받고, log4j는 받지 않으셔도 무관합니다.)

Maven을 즐겨 쓰시는 분이라면

mvn archetype:create -DarchetypeGroupId=org.apache.wicket -DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=1.3.3 -DgroupId=com.mycompany -DartifactId=myproject

로 준비작업을 마칠 수 있습니다.

자, 이제 web.xml 파일을 건드릴 차례입니다. /* 로 오는 모든 요청들을 Wicket Filter 가 받게 해줍니다.

필터 클래스 FQDN은 org.apache.wicket.protocol.http.WicketFilter 입니다.
init-param 에 applicationClassName 에는 wicket WebApplication 구현체 클래스명을 넣어주면 준비 완료입니다. 저는 가계부 어플리케이션을 만들 계획이라 rath.quicken.www.QuickenApplication 으로 했습니다.

<filter>
 <filter-name>Rath and Elle’s Quicken at Home</filter-name>
 <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
 <init-param>
  <param-name>applicationClassName</param-name>
  <param-value>rath.quicken.www.QuickenApplication</param-value>
 </init-param>
</filter>

<filter-mapping>
 <filter-name>Rath and Elle’s Quicken at Home</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>

이제 WebApplication 클래스를 만들고 해당 웹app의 HomePage 페이지를 만듭니다.
그걸로 HelloWorld는 마무리됩니다. 여기의 예제 소스코드를 참조하여 HelloWorldApplication과 HelloWorld를 작성합니다.

패키지명 적당히 주시고.. 하면 되는데, WebApplication 클래스의 getHomePage 메서드에 이 어플리케이션의 ‘홈페이지’를 처리할 WebPage의 클래스명을 적어줍니다.

package rath.quicken.www;
import org.apache.wicket.protocol.http.WebApplication;

public class QuickenApplication extends WebApplication
public class HelloWorldApplication extends WebApplication
{
public QuickenApplicationHelloWorldApplication()
{

}

public Class getHomePage()
{
return HelloWorld.class;
}
}

WebApplication 에서는 이 webapp의 첫 페이지(HomePage) 클래스를 리턴하는 것 외에 이 webapp의 여러가지 설정들을 넣을 수 있습니다. 예를 들어 newSession, newSessionStore, getApplicationSettings 등이 다 여기에 있지요. 나중에 알아볼 mount 메서드도 WebApplication 클래스의 메서드입니다. path :: webpage class map 이랄까요? 페이지를 특정 path 에 mount 한다는 의미로 생각하시면 편할 것입니다.

Wicket 이 타 웹 framework 들에 비해 초기 설정 cost 는 확실히 적은 편이지만, 이래저래 customize 할 수 있는 부분이 워낙 많아 이것들은 Wicket In Action 책이 도착하면 차근차근 알아볼 생각입니다.

아무튼 HomePage 클래스를 구현해야할 차례입니다.

import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;

public class HelloWorld extends WebPage
{
public HelloWorld()
{
add(new Label(“message”, “Hello World!”));
}
}

WebPage 클래스를 상속했음이 중요한 내용이고요, 여기서는 그저 label 에 메시지를 표시할 것이기 때문에 Label 클래스를 만들고 id가 message인 녀석의 value를 Hello World!로 표시되도록 했습니다.

Wicket 에서는 org.apache.wicket.markup 패키지랑 그 하위 패키지에서 Label 과 같은 웹개발에 필요한 여러가지 html 클래스들의 추상 클래스들을 제공하고 있습니다. Label 도 있고.. MultilineLabel 도 있고.. markup.form 패키지에서는 form, 각 type별 input element 들(버튼, 체크박스, 라디오버튼, 리스트, textarea 등)에 대한 추상 클래스들도 싸그리 제공하고 있습니다.

아무튼 HelloWorld 페이지에서는 id:message 에 HelloWorld! 를 표시하라는 label을 추가(add)하기만 했습니다. 그럼.. 이것을 렌더링할 html 페이지가 있어야겠지요?

<html>
<body>
<span wicket:id=”message”>xxx</span>
</body>
</html>

이런식입니다. Wicket 에서 자랑하는 것이 다른 웹프레임워크처럼 새로운 태그들을 배우지 않아도 된다- 는 것인데, 위 소스코드에서 볼 수 있듯이 기존 html 코드들을 그대로 쓸 수 있는 대신, WebPage 인스턴스와의 연결고리를 위해 wicket:id attribute 가 있습니다. 이정도면.. 뭐 특별히 html 렌더링을 위해 custom tag를 배우지 않아도 된다- 는 것을 인정해주기로 했습니다. 하하;

여기서 중요한 것은 이 HTML 리소스 파일의 위치입니다. HelloWorld extends WebPage 의 소스코드 어디에서도 이 웹페이지의 리소스(.html 파일)이 어디있는지 알려주지 않았습니다. 도대체 어디에 위치해야합니까! @.@

정답은-

WebPage 상속한 클래스의 클래스명과 동일한 형태로 classes/path/to/HelloWorld.html 에 위치해야합니다. 지금 이 예제에서 HelloWorld 의 패키지명이 foo.bar 였다면, classes/foo/bar/HelloWorld.html 에 위치하면 되는 것입니다.

이것이 맘에 안든다고요? HTML 파일을 어디로부터 읽어들일지 변경하는 것이 가능합니다.
Control where HTML files are loaded from 이 문서를 참조하세요.

WebApplication 클래스에서 getResourceSettings() 를 불러 addResourceFolder(“/html”) 를 불러주는 것으로 WEB-INF/classes/path/to/xxx 에 html 을 저장해야하는 것에서 /html/path/to/xxx 로 간단히 변경될 수 있습니다.

리소스 파일이 WebPage의 패키지명과 동일한 디렉토리 구조를 가져야 하는 것이 맘에 안드신다면 ResourceStreamLocator 를 재지정하여 이를 해결할 수 있습니다. Control where HTML files are loaded from 에서는 PathStripperLocator 를 만들어 패키지명을 무시하고 /html/HelloWorld.html 을 사용하도록 하고 있습니다. 이것 역시 WebApplication.ge
tResourceSettings().setResourceStreamLocator 메서드로 재정의된 ResourceStreamLocator 를 사용하도록 할 수 있습니다.

아무튼 HelloWorld.html 파일의 <span wicket:id=..>xxx</span> 의 xxx 부분에 Hello World! 가 찍히는 것을 볼 수 있을 것입니다. 이 HelloWorld 웹페이지는 HomePage 로 지정해뒀으므로 http://localhost/ 로 접근하면 됩니다.

이것으로 Wicket 을 가볍게 알아보기 위한 HelloWorld 스터디를 마치겠습니다.
spring, hibernate, ibatis 와의 연동도 제공하고 있다고 하는데, 제가 아는 게 없어서 -_- 차근차근 잘근잘근 공부해가며 스터디해볼 생각입니다.

만들려는 가계부 웹어플리케이션이 인터페이스는 별 거 없으면서도 할 건 다 해야되서 ;ㅁ; 결코 Wicket을 수박 겉핥기 식으로 스터디하게 되진 않을 듯 합니다.

다음 편도 기대해주세요! :$