2009년 5월 31일 일요일

2008년 구글 창업자의 편지

구글의 창업자는 래리 페이지와 세르게이 브린이라는 것은 대부분의 사람들이 잘 알고 있다.
그리고 이 둘은 해마다 구글러들에게 편지를 쓰고 있는데
해마다 한 사람씩 써 오고 있다.

구글의 서비스에 대한 간략한 이해와 구글의 미래, 시장의 앞을 나름대로 예측해 볼 수 있을 듯 하다.

2009년 5월 26일 화요일

촛불들지 마시요

나라가 점점 얼룩져가고 있다.
상식과 기본이 통하지 않는...
아이보다 못한 잣대로 얼룩져 가고 있다...
이렇게 동영상을 퍼 오는 것도 민망하다...

나중에 내 아이들에게 이런 걸 보여줘야 하나...ㅜㅜ
그리고
아빠의 목마를 타고 촛불을 들고 있던 저 아이가
나중에 당시를 기억한다면 어떻게 말을 할까?...




노무현 전 대통령이 서거한 지난 23일 밤, 덕수궁 앞 분향소 근처 인도에서 경찰과 추모객 사이에 벌어진 실랑이를 담은 동영상이 인터넷상에서 화제다.

동영상 사이트 유튜브에 ‘촛불 들지 마시오’라는 제목으로 올라온 이 동영상에는 “촛불을 들면 통과하지 못한다”며 5살 난 꼬마 아이가 든 촛불까지 “불법”으로 규정, 경찰이 시민의 통행을 막는 현장을 담고 있다.

아이 부모와 시민들은 “떼로 지나가는 것도 아니고, 아이 하나가 달랑 초 하나 들고 가는데 이게 불법이냐. 이게 시위냐”며 따졌다. 하지만 한 경찰 관계자는 “그것은 지금 제가 법률적으로 설명하지 못한다”면서 무조건 막아 선다.

어른들의 실랑이를 보다못한 아이가 손에 든 촛불을 입으로 불어 끄고 나서야 소동은 끝이 났다.

이 영상을 본 네티즌들은 “이번 추모 행렬에 대한 경찰의 인식을 단적으로 보여준다”, “어이없다”는 반응을 보이고 있다.

주상용 서울경찰청장은 25일 경찰의 과잉통제 논란에 대해 “분향소를 버스가 둘러싸고 있으니까 분향하는 데 오히려 아늑하다는 사람도 있다”고 말해 파문을 일으켰다.

<경항닷컴>

2009년 5월 24일 일요일

노무현 전 대통령 유서[전문]

사용자 삽입 이미지

[언론에서 보도하지 않은 유서 뒷 부분]
사는 것이 힘들고 감옥같다.나름대로 국정을 위해 열정을 다했는데 국정이 잘못됐다고 비판 받아 정말 괴로웠다. 지금 나를 마치 국정을 잘못 운영한 것처럼 비판하고 지인들에게 돈을 갈취하고, 부정부패를 한것처럼 비쳐지고, 가족 동료, 지인들까지 감옥에서 외로운 생활을 하게 하고 있어 외롭고 답답하다.
아들 딸과 지지자들에게도 정말 미안하다. 퇴임후 농촌 마을에 돌아와 여생을 보내려고 했는데 잘 되지 않아 참으로 유감이다.돈 문제에 대한 비판이 나오지만 이 부분은 깨끗했다. 나름대로 깨끗한 대통령이라고 자부 했는데 나에 대한 평가는 멋 훗날 역사가 밝혀줄 것이다.



2009년 5월 22일 금요일

[링크]에뮬레이터에서 외장 메모리 사용하기

안드로이드 에뮬레이터를 이용한 sdcard 의 사용에 대한 정리는 많이 해 두었다.
나 역시 해 두었던 적이 있었는데, 자료를 날리고 말았다...ㅡㅡ;;
잠시 찾아보던 중에 잘 정리해 둔 블로그가 있어 소개한다^^

2009년 5월 21일 목요일

org.apache.http.client.ClientProtocolException on Android

Android 개발시 apache http client 모듈을 이용할 경우 HttpClient 클래스를 이용하여 다음과 같이 GET/POST 메소드로 전송할 수 있다. 즉, HTTP로 요청할 수 있다.
일단 간단한 소스 코드를 살펴보자.

HttpClient client = new DefaultHttpClient();
HttpGet method = new HttpGet("http://www.daum.net");

method.setHeader("User-Agent", "Android emulator");

HttpResponse res = null;
try {
res = client.execute(method);
StatusLine status = res.getStatusLine();
if (status.getStatusCode() == HttpStatus.SC_OK) {
System.out.println("Method completed");
} else {
System.err.println("Method failed: " + status.getReasonPhrase());
}
}  catch ( ClientProtocolException e ) {
        // TODO Auto-generated catch block
        e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
}

일단, 위의 소스는 에러가 발생하지 않는다. 왜냐하면 HttpGet 클래스를 이용한 GET 메소드로 요청하는 것이기 때문이다.
따라서 별도의 Content-Length를 명시하지 않아도 된다.

그런데, 만약 POST 메소드로 요청시에는 Http body 가 첨부됨으로 Content-Length 를 http header 에 명시해 준다. 안드로이드 상에서는 다음과 같이 해 주면 된다.

method.setHeader("Content-Length", "" + httpBody.length);

여기서 이 코딩이 화근이다. 실제로 안드로이드 버전이 아닌 자바 버전의 아파치 HttpComponents를 이용할 경우에는 POST로의 요청일 경우에도 위의 코드를 넣어줄 경우에는 에러가 발생하지 않는다.
하지만, 안드로이드 애플리케이션에서 다음과 같이 http body 를 넣어줄 수 있는데, 여기서 위의 코드와 같이 Content-Length 를 명시할 경우 ClientProtocolException 이 발생한다.

byte[] httpBody = "Android http body".getByte();
HttpEntity entity = new ByteArrayEntity(httpBody);

HttpGet method = new HttpGet("http://test.wiseant.net/debugger");
method.setHeader("Content-Length", "" + httpBody.length);


05-22 06:40:56.533: WARN/System.err(1030): org.apache.http.client.ClientProtocolException

따라서 실제코드 상에서는 Content-Length 를 명시하는 setHeader 메소드를 사용하지 않아야 한다.
자바 버전의 HttpComponents 를 사용하는 것과 안드로이드의 Http client 컴포넌트를 사용하는 것은 상당 부분 차이가 난다.
흠... 이 버그 찾는데 오후 내도록 찾은 것이니 아깝진 하다... 쩝...^^;;

구글, '크롬2.0' 일반용으로 공개…30% 속도 향상

구글 브라우저 '크롬2.0'이 발표되었다는 소식이다.
곧바로 설치해서 크롬상에서 이번 포스트를 작성해 본다^^

야후, 다음에 접속해 보았는데 많이 빨라진 느낌이다.
수치상으로 기재를 못하지만 기존의 크롬1.x 의 느낌보단 휠씬 빠른 느낌이다.

구글, '크롬2.0' 일반용으로 공개…30% 속도 향상
http://www.zdnet.co.kr/ArticleView.asp?artice_id=20090522084431

다운로드는 다음의 주소에서 받을 수 있다.


썬, '자바 앱스토어' 오픈한다.

'앱 스토어' 시장은 애플 앱 스토어를 시작으로 현재 대부분의 스마트폰, 모바일 디바이스 영역에서는 당연히 되어가고 있다.
하긴 애플 앱 스토어의 기가 막힌 선순환 구조의 수익성을 경쟁회사들이 그냥 두고 있을리는 없다.

그리고 오늘 특이한 기사 하나를 접하게 되었다.
바로 전세계에서 가장 많은 개발자를 확보하고 있는 프로그래밍 언어 - 자바 - 바로 이 '자바 앱 스토어'를 자바를 창시한 회사인 Sun Microsystems 에서 오픈한다고 한다.

흠... 단연 앱 스토어 시장은 소프트웨어 시장에서의 새로운 생태계를 이루고 있다.
그리고 썬 마이크로시스템즈의 앱 스토어 시장으로의 진출은 가장 많은 개발자를 확보하고 있다는 강한 매력을 지니고 있기도 하다.
하지만, 자바를 기반으로 하는 대부분의 시장은 엔터프라이즈 또는 모바일 환경이다.
썬 마이크로서시스템즈가 어느 영역에 중점을 두는 건지는 정확히 모르지만 아마도 모바일 환경일 터... 그리고 최근엔 JavaFX 를 통한 RIA 시장도 크게 보고 있을 것이다.
이제 개발자와 사용자들이 자바를 선택할 것인가?

'자바 앱 스토어'가 오픈되고 성공여부를 지켜보는 것도 하나의 재미가 될 듯 하다.
그리고 내가 나아갈 방향도 역시 재미있어 질 거 같다.


2009년 5월 20일 수요일

[링크]Android API를 이용한 Apache http client 예제

안드로이드 API 에는 org.apache.http 라는 패키지로 Apache 에서 공식 지원하는 HTTP Client를 implements 한 API 들을 지원한다.

하지만 apache http client API가 현재 Apache 공식 홈페이지에 올라와 있는 commons, HttpComponents 와는 버전도 다르고 코드 사용법도 조금은 다른 듯 하다.
(사실, 급한 마음에 일일히 비교해 보질 않아서 정확하게 어디 어디가 다른지는 모른다. 하지만 Java app 용 apache의 버전을 이용한 코드를 실행할 때 안드로이드에서는 되질 않는다. 나중에 좀 더 자세한 내용을 알게되면 포스팅하도록 하겠다. 지금은 워낙 급하게 진행하는 프로젝트라...^^;;)

이 중에 Http Post 형태를 지원하는 것을 찾아보는 중에 해당 자료에 해당하는 자료를 정리해 둔다.
HttpGet, HttpPost 는 비슷한 형태로 제공되고, Post 인 경우 Entity에 해당하는 데이터를 넣어줄 수 있다.

* anddev.org 로 유명을 얻은 블로그에 예제가 있다.

* 블로그인 듯 한데 간결하게 잘 설명해 주고 있다.

* 참고로 HttpGet 으로 요청할 때의 예제라고 할 수 있다. 실제로는 RESTful client 예제이다.

2009년 5월 19일 화요일

[JSTL Tip]fmt:formatDate를 이용한 날짜 출력

JSTL에는 많은 기능들이 있으나, 대체로 일일히 기억한 상태로 사용하기에는 부담이 많다. 그래서 하나씩 정리해 두어야 하는데 오늘은 날짜를 출력하기 위한 fmt:formatDate를 사용해 본다.

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt" %>


JSP 코드에는 당연히 위의 선언문이 필요하다. 다음은 fmt:formatDate 태그를 이용하여 날짜를 출력해보자.

<c-rt:set var="now" value="<%=new java.util.Date()%>" />

<fmt:formatDate value="${now}" pattern="yyyy-MM-dd hh:mm:ss" />


위와 같은 형태로 formatDate를 사용하면 다음과 같은 형태로 우리가 알기 쉬운 형태로 보이게 된다.

2008-01-28 11:20:49

여기서 한 가지 주의할 점은 보통 자바에서 날짜를 long 타입으로 정의해 놓은 스팩이 많다. 파일의 lastModified 메소드도 리턴형이 long으로 되어 있다. 따라서 만약에 파일의 최종 수정일을 위와 같은 날짜의 형태로 보여주기 위해서는 해당 lastModified 메소드로 리턴되는 long을 아래와 같이 임시 변수에 set 한 후에, 출력해야 한다.

<c-rt:set var="tempDate" value="<%= new java.util.Date(file.lastModified()) %>">




이와 관련된 스팩과 많은 예제를 인터넷에서 찾아볼 수 있다. 대략 정리해 보면 다음과 같다.

JSTL 기초, Part 1: Expression Language (한글) :  http://www.ibm.com/developerworks/kr/library/j-jstl0211.html
JSTL 기초, Part 2: core 분석 (한글) : http://www.ibm.com/developerworks/kr/library/j-jstl0318/
JSTL 기초, Part 4: SQL과 XML 콘텐트에 액세스 하기 (한글) : http://www.ibm.com/developerworks/kr/library/j-jstl0520/

[JSTL Tip] <c:if>, <c:choose>, <c:out>를 사용한 조건예제

JSTL을 사용하면서 가장 많이 애용되는 태그는 <c:if>와 <c:choose> 인거 같다. 하지만 JSTL의 특성상 쉽게 외워지지 않게 된다. 나한테 약간은 고질적인 면이당^^;; 자주 사용하는게 아니니 할 때마다 찾아보게 된다. 그래서 내 스스로 정리하기로 마음을 먹었다.

일단 <c:if> 태그에 대해서 알아보자.

<%@ taglib uri="/WEB-INF/tld/c.tld" prefix="c" %>

<%-- Simple if conditions --%>
<c:if test='${param.p == "someValue"}'>
객체 param.p 와 someValue의 값이 같으면 이 부분이 출력된다.
</c:if>
<c:if test='${param.p}'>
param.p의 값이 'true'이면 이 부분이 출력된다.
</c:if>
<c:if test='${empty param.p}'>
param.p의 값이 null이면 이 부분이 출력된다.
</c:if> 
<c:if test='${!empty param.p}'>
param.p의 값이 null이 아니면 이 부분이 출력된다.
</c:if>


자바 코드에서 if/else 문의 사용은 누구나 알 수 있다. 하지만 JSTL에서는 if/else의 구문을 <c:choose> 태그를 사용해야 구현이 가능하다. 다음은 그 예제이다.

<%-- A simple if/else condition --%>
<c:choose>
<c:when test='${param.p == "someValue"}'>
param.p와 'someValue'의 값이 같으면 이 부분이 출력된다.
</c:when>
<c:otherwise>
if/else문에서 else에 해당하는 즉, param.p와 'someValue'의 값이 다르면 이 부분이 출력된다.
</c:otherwise>
</c:choose>


다음은 이 보다 조금더 복잡한 다중조건을 이용한 <c:chosse> 태그의 예제이다.

<c:choose>
<c:when test='${param.p == "0"}'>
param.p의 값이 '0'이면 이 부분이 출력된다.
</c:when>
<c:when test='${param.p == "1"}'>
param.p의 값이 '1'이면 이 부분이 출력된다.
</c:when>
<c:otherwise>
param.p이 값이 '0', '1'이 아니면 이 부분이 출력된다. 즉, else의 마지막 구문이다.
</c:otherwise>
</c:choose>


이 뿐만 아니라, <c:out> 태그도 조건에 의한 템플릿 텍스트를 생성하여 출력할 수 있다. 만약 속성값이 null이면, 디폴트 값이 생성된다. 다음은 이에 해당하는 예제이다.

<%-- Default value in an attribute --%>
<c:out value='${param.p}' default="p의 값이 null이면 default로 지정된 이 값이 출력된다." />

<%-- Default value in the body content --%>
<c:out value='${param.p}'>
p의 값이 null이면 이 부분이 출력된다.
</c:out>

휴유증...

지난 토요일 친지분 상을 당해서 부랴부랴 부산/진해로 내려갔다.
서울에서 출발한 시간이 토요일 PM 9:30 쯤...
서울에서 진해로 가는 동안 내내~~ 비가 왔다. 덕분에 진해에 도착하니 다음날 AM 3:00 ㅡㅡ;;

장례를 모두 마치고, 서울로 출발한 시간이 PM 8:30
중간에 도저히 잠이 와서 잠시 휴게실에서 졸다가 서울에 우여곡절 끝에 도착하니 AM 3:30

결국 오늘 4시에 잠을 청해서 7시에 일어나 하루 종일 회사에 앉아있다.
집중이 잘 되질 않으니 일에 효율성도 찾아볼 수 없다.
그냥 멍~만 때리고 있는 듯 하다.

생각보단 휴유증이 크네... 그래도 내일부터는 또 다시 회복이 되겠지...ㅎㅎ

2009년 5월 14일 목요일

[기사]내달 일본서 첫 안드로이드폰 출시

사용자 삽입 이미지

일본 최대 이동통신사 NTT도코모가 구글 모바일 운영체제(OS)를 탑재한 안드로이드폰을 출시한다. 

일본 IT전문지 아이티미디어는 도코모가 대만 HTC 스마트 폰인 'HTC 매직'을 다음달 출시할 계획이라고 지난 14일 보도했다.  

일본에서 안드로이드폰이 출시되는 것은 이번이 처음이며 대만에 이어 아시아 두번째다.  

대만 HTC의 두번째 구글폰인 '매직'은 유럽 최대 이동통신사 보다폰을 통해 이달 초 영국과 독일 등에서 출시됐다. HTC가 지난해 10월 미국에서 출시한 첫번째 구글폰 'G1'은 지난달 말 누적 판매량 100만대를 돌파하는 등 높은 인기를 누리고 있다. 

한경닷컴 서희연 기자 shyremon@hankyung.com

[원본기사]

2009년 5월 13일 수요일

from String to InpuStream

부제 : 자바 문자열로부터 InputStream 얻어오기

String text = "자바";
InputStream inputStream = new ByteArrayInputStream(text.getBytes());

또는

InputStream inputStream = new ByteArrayInputStream(text.getBytes("utf-8"));

text.getBytes() 인자로는 Charset, CharsetName(String) 을 넣어 적절한 형태로 사용가능.


[참고]
이렇게 간단하지만 검색의 내용이 된다.


2009년 5월 12일 화요일

Java2Html plugin 기본설정 바꾸기

이전에 Java2Html plugin 설치를 통하여 기본적으로 JSPWiki에 플러그인 설치에 대해서 알아보았다. 이번에는 Java2Htmll plugin 의 기본적인 설정을 수정하는 방법에 대해서 알아보자. JSPWiki를 설치하여 운영중이거나 이미 사용해본 사람이라면 쉽게 알 수 있지만 언제나 초보는 있으니깐^^

이에 해당하는 설명은 실제로는 여기 JSPWiki 웹 사이트에 나왔있다. 여기서는 아래와 같이 간략하게 설치해 보기로 하자.

1. java2html.properties 파일을 다운로드 받는다.
2. java2html.properties 파일을 "%TOMCAT_HOME%/webapps/jspwiki/WEB-INF/classes" 디렉토리에 위치시킨다.
3. java2html.properties 파일을 살펴보면 다음과 같다.

#Sun Jul 23 14:28:11 CEST 2006
defaultStyleName=Eclipse
showFileName=false
showTableBorder=false
showLineNumbers=false
showJava2HtmlLink=false
horizontalAlignment=left
TAB_SIZE=2
Background_COLOR=255,255,255
Background_BOLD=false
Background_ITALIC=false
Line\ numbers_COLOR=128,128,128
Line\ numbers_BOLD=false
Line\ numbers_ITALIC=false
Multi-line\ comments_COLOR=63,127,95
Multi-line\ comments_BOLD=false
Multi-line\ comments_ITALIC=false
Single-line\ comments_COLOR=63,127,95
Single-line\ comments_BOLD=false
Single-line\ comments_ITALIC=false
Keywords_COLOR=127,0,85
Keywords_BOLD=true
Keywords_ITALIC=false
Strings_COLOR=42,0,255
Strings_BOLD=false
Strings_ITALIC=false
Character\ constants_COLOR=153,0,0
Character\ constants_BOLD=false
Character\ constants_ITALIC=false
Numeric\ constants_COLOR=153,0,0
Numeric\ constants_BOLD=false
Numeric\ constants_ITALIC=false
Parenthesis_COLOR=0,0,0
Parenthesis_BOLD=false
Parenthesis_ITALIC=false
Primitive\ Types_COLOR=127,0,85
Primitive\ Types_BOLD=true
Primitive\ Types_ITALIC=false
Others_COLOR=0,0,0
Others_BOLD=false
Others_ITALIC=false
Javadoc\ keywords_COLOR=127,159,191
Javadoc\ keywords_BOLD=false
Javadoc\ keywords_ITALIC=false
Javadoc\ HTML\ tags_COLOR=127,127,159
Javadoc\ HTML\ tags_BOLD=false
Javadoc\ HTML\ tags_ITALIC=false
Javadoc\ links_COLOR=63,63,191
Javadoc\ links_BOLD=false
Javadoc\ links_ITALIC=false
Javadoc\ others_COLOR=63,95,191
Javadoc\ others_BOLD=false
Javadoc\ others_ITALIC=false
Undefined_COLOR=255,97,0
Undefined_BOLD=false
Undefined_ITALIC=false
Annotation_COLOR=100,100,100
Annotation_BOLD=false
Annotation_ITALIC=false


4. 예를들어, 다음과 같이 수정해 보자. 처음엔 백그라운드 컬러가 "Background_COLOR=255,255,255" 이렇게 되어 있기 때문에 소스인 것을 쉽게 알아보기 힘들다. 그래서 간단하게 "Background_COLOR=255,255,176" 으로 수정해 보자.
5. 잊지 말아야 하는 것은 항상 WAS를 재가동 해 주어야 한다는 것이다.
6. 이제 각자의 구미에 맞게 properties를 수정하면 된다.

JSPWiki plugin 설치하기 - Java2HtmlPlugin

JSPWiki의 장점중에 하나는 이클립스와 비슷하게 다양한 플러그인을 제공한다는 것이다. 오픈소스의 장점이라고 할 수 있겠다. 다양한 플러그인을 이용해서 다양한 기능을 제공할 수 있다.
여기서는 Java2HtmlPlugin을 기준으로 JSPWiki 플러그인을 설치하는 것을 알아보자.

방법은 의외로 간단한다. 사용방법은 각 플러그인의 타아틀과 옵션에 따라서 약간의 차이는 있지만 대부분은 동일한다. 그러면 먼저 Java2HtmlPlugin을 설치해 보자.

1. Java2HtmlPlugin 사이트에 가서 릴리즈 버전을 다운로드 받는다.
2. 현재(2008.01.16) 버전은 java2html_50.zip 이다.
3. zip 파일을 압축해제하면 "java2html.jar" 파일을 찾을 수가 있는데, 이 파일을 %TOMCAT_HOME%/webapps/JSPWiki/WEB-INF/lib 디렉토리에 복사한다.
4. "%TOMCAT_HOME%/webapps/JSPWiki/WEB-INF" 디렉토리의 "jspwiki.properties" 파일을 열어 "jspwiki.plugin.searchPath = java2html.plugin.jspwiki"를 추가해 준다.
5. Tomcat을 재가동하면 Java2HtmlPlugin을 사용할 수 있다.

사용방법은 다음과 같다.
[{Java2HtmlPlugin border='true'

public class HelloWorld {  
  public static void main(String args[]) {
    System.out.println("Hello World!");
  }
}

}]

위의 JSPWiki 플러그인 설치방법은 대부분의 플러그인 설치방법과 동일하다. 즉, JSPWiki 디렉토리의 "WEB-INF/lib" 디렉토리에 해당 플러그인의 jar 파일을 위치시키고, 해당 플러그인의 path 를 "WEB-INF/" 디렉토리에 있는 "jspwiki.properties" 파일의 "jspwiki.plugin.searchPath"에 클래스 패스를 추가해 준다. 구분자는 ',' 이다.

점점 JSPWiki에 매력에 빠져드는 기분이다. 흠.. 블러그를 시작한지 얼마되지 않았는데, Wiki로 전환하는 게 아닌지 걱정이당...^^;;

간단한 JSPWiki 설치

JSPWiki는 오픈소스로된 대표적인 Wiki 웹 애플리케이션이다. 간단하게 설치에 대해서 알아본다.

1. http://www.jspwiki.org 에서 소스를 다운로드 받는다.
2. 압축된 소스를 해제하고, "JSPWiki-2.4.104-src/JSPWiki" 디렉토리 전체를 이클립스에 import 시켜준다.
[2009.05.13 현재]
현재 버전은 2.8.2

3. 한글을 지원하기 위해서 "JSPWiki-2.4.104-src/JSPWiki/etc" 디렉토리에 있는 "jspwiki.properties" 파일에 "jspwiki.encoding = UTF-8" 라고 셋팅해 준다.
4. "JSPWiki-2.4.104-src/JSPWiki" 디렉토리에 있는 build.xml를 이용하여 이클립스에서 ant를 실행시킨다.

이렇게 하면 지정된 디렉토리에 JSPWiki.war 파일이 생성되는 것을 볼 수 있다. Tomcat을 이용한다면 %TOMCAT_HOME%/webapps 디렉토리에 JSPWiki.war 파일을 복사해 놓고 Tomcat을 가동한다.

5. http://yourdomain/JSPWiki/Install.jsp 를 먼저 실행하여 기본적인 설치를 해 준다.

그러면, http://yourdomain/JSPWiki 주소를 통해서 JSPWiki를 실행할 수 있다.

FilenameFilter를 이용한 지정된 파일이름만 가져오기

java.io 패키지에 FileFilter와 FilenameFilter 인터페이스가 존재한다. 이 둘은 각각 인터페이스를 implements하여 구현한 코드를 File.listFiles(FileFilter filter) 를 이용할 때 사용하게 된다. 일단 여기서는 FilenameFilter를 이용하여 일정한 확장자를 가진 파일만 file list로 얻어오는 예제를 살펴보자.

먼저, FilenameFilter를 이용한 JPEGFileFilter.java 클래스를 만들어본다.

package net.wiseant.io.util;

import java.io.File;
import java.io.FilenameFilter;

/**
 * @author SangHyup Lee
 * @version 1.0
 *
 */
public class JPEGFileFilter implements FilenameFilter {

    /* (non-Javadoc)
     * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
     */
    public boolean accept(File dir, String name) {
        // TODO Auto-generated method stub
        return name.endsWith(".jpg");
    }

}


JPEG파일의 확장자가 jpg인 파일에 대해서 true를 리턴해 준다고 생각하면 된다. 다음은 이를 이용한 간단한 파일 리스트를 얻어오는 테스트 프로그램을 작성해 보자. '.JPG' 파일은 자바에서는 대소문자를 구분함으로 제외된다.

이제 해당 디렉토리의 파일 리스트를 얻어올 때 JPEGFileFilter를 이용하여 확장자가 jpg 인 파일만 얻어오자.

package net.wiseant.junit.io;

import java.io.File;

import net.wiseant.io.util.JPEGFileFilter;

import junit.framework.TestCase;

/**
 * @author Sang Hyup Lee
 * @version 1.0
 *
 */
public class FilenameFilterTest extends TestCase {

    private String workDirectory = "";
    
    /* (non-Javadoc)
     * @see junit.framework.TestCase#setUp()
     */
    protected void setUp() throws Exception {
        super.setUp();
        workDirectory = "D:\\Photos";
    }

    public void testJPEGFileFilter() {
        File currentDirectory = new File(workDirectory);
        File[] fileList = null;
        JPEGFileFilter jpegFileFilter = new JPEGFileFilter();
        
        if ( currentDirectory.exists() && currentDirectory.isDirectory() ) {
            fileList = currentDirectory.listFiles(jpegFileFilter);
        }
        
        assertEquals(7, fileList.length);
    }
    
}


FilenameFilter를 implements 하여 구현한 코드는 반드시 public boolean accept(File dir, String name) 메소드를 구현해야 하는데 이를 잘 이용하면 이 외에도 다양한 방법으로 파일 리스트를 얻어올 수 있다.

이데아고라 사례정리 - 좋은 글 소개

웹2.0는 하나의 트랜드를 이미 넘어섰다고 생각한다. 처음 국내에 소개될 때만해도 마케팅 거품일 수도 있다는 등 여러가지 비판적인 시각도 있었고, 웹이 지향해야 할 청사진을 제시하고 있다는 등의 긍정적인 말들도 많이 오갔다.
그러는 가운데 시간이 흐러면서 '참여', '공유', '개방' 이라는 키워드 안에서 웹2.0은 새로운 시대를 맞이하게 되고, IT, 정보통신 분야를 넘어 문화, 사회, 심지어 정치에 이르기까지 새로운 트랜드를 심어주고 있다. 그리고 이미 웹을 중심으로 한 인터넷 환경에서는 보편화가 되어 이슈를 만들기도 힘들 정도로 보편화되었다.

다만 2007년 부터 보여지기 시작한 특이한 점은 국내에서는 'UCC-동영상 2.0'이란 키워드로 거의 굳혀가고 있었고, 미국을 중심으로 한 선진국에서는 '비지니스 2.0'이란 키워드로 중심이 이동한 듯 했다. '비지니스 2.0'이란 키워드는 약간의 개인적인 의견을 담고 있기도 하고 간간히 업계에서 쓰이고 있기도 한 거 같다.

간략하게 소개한다고 하는 것이 내용이 조금 많아진 듯 한 면은 있는데, '비지니스 2.0'을 소개하면서는 이전에 "위키노믹스(Wikinomics)" 라는 책의 리뷰를 작성하면서 간략하게마나 소개한 듯 해서 다시 링크를 통해서 언급하는 것으로 한다.


그리고 오늘 끝으로 소개하려는 글은 블로그 서핑 중에 읽어본 괜찮은 글이다. 앞에서 잠시 언급한 웹2.0과 비지니스 2.0, 그리고 위키노믹스를 포함하여 이 책에서 소개하는 '이데아고라'라는 신조어에 대한 사례로 '델의 아이디어스톰'을 소개하는 글이다. 좋은 글이다.

Singleton pattern 예제 - Head First Design Pattern 중에서

다음은 Singleton pattern 예제 코드이다.

/**
 * Singleton.java
 * 
 * Singleton pattern의 예제
 */
package net.wiseant.designpattern.singleton;

/**
 * @author Sang Hyup Lee
 * @version 1.0
 *
 */
public class Singleton {

    private volatile static Singleton uniqueInstance;
    
    private Singleton() {
        
    }
    
    public static Singleton getInstance() {
        if ( uniqueInstance == null ) {
            synchronized (Singleton.class) {
                if ( uniqueInstance == null ) {
                    uniqueInstance = new Singleton();
                }
            }
        }
        
        return uniqueInstance;
    }
    
}

FileReader.java - 파일의 내용을 한 줄씩 읽는다

자바 IO를 이용한 FileReader 예제 소스이다. 파일이 .txt 파일이면 정상적으로 파일의 내용을 한 줄씩 읽어들여 화면에 디스플레이해 준다(사실은 표준출력한다).

import java.io.*;

public class FileReader {
    public static void main (String[] args) {
        System.out.println ("Program to demonstrate reading from a file");
        
        BufferedReader br = null;
        String fileName = args[0];
        
        // If an error occurs, go to the "catch" block
        try {
            // FileInputStream fis = new FileInputStream (fileName);
            FileReader fis = new FileReader (fileName);
            br = new BufferedReader (fis);
        
            // continue to read lines while there are still some left to read
            while ( br.ready() ) {
                System.out.println (br.readLine());
            }
        
            // Close the input stream
            br.close();
        } catch (Exception e) {
            // Handle any error in opening the file
            System.err.println("File input error");
        }
    } // End of main method
    
} // End of the class FileReader

넷북 시대를 맞이한 새로운 SW 시장보기

제목은 거창하지만 ZDNet에 올려져 있는 몇 개의 기사를 보고 간단하게 느낀 점을 적어두는 것이다.
하지만 PC 시장을 이미 넘어선 넷북 시장에 대한 연구가 많이 이루어지진 않은 듯 하다.
이젠 하드웨어만으로 성공할 수 있는 시대는 지나갔다.
애플이 그것을 극명하게 증명하였고, 구글은 이미 소프트웨어를 전세계에 무료를 배포하는 거장과 같은 기업이 되었다.


이것은 곧 소프트웨어 시장이 더욱 발전을 거듭할 것이란 이야기인데, 전체 SW 시장에서 규모가 점점 커지게 될 것으로 예상되는 분야가 스마트폰과 넷북 시장이다.

이미 그 전초전으로 마이크로소프트와 구글이 OS 시장을 놓고 격돌중이다.


예상치 못한 시장이 어느새 사람들 사이에서는 자리를 잡은 것이 넷북이다.
스마트폰에 대한 시장의 예상은 너도나도 떠들고 다니는 중이라 '이제.. 곧...'이란 생각이 들었던 반면, 이미 넷북은 PC 시장을 능가할 정도로 커진 상태이다.

하지만, 언제나 늦지 않은 것이 해당 사실을 알았을 때이다.
즉, 넷북 시장에서 모자란 것이 킬러 애플리케이션 또는 SW 이다. OS 시장에서의 승자가 누가 되든지 간에 SOA, WOA(Web Oriented Architecture) 시장에서 선두 기업이 될 수 있다면?
좋은 기회이지 않을까?

보안 계정으로 설정된(아이디/패스워드가 있는) SMTP 서버를 이용한 자바메일발송

JavaMail API를 이용하여 메일을 발송하는 예제의 대부분은 SMTP 서버를 통해서 단순하게 메일을 보내는 것이다.
하지만 사내에서 SMTP를 사용하여 메일을 전송하거나, 별도의 서비스를 위해서 SMTP 서버를 사용하는 경우에는 SMTP 서버에 계정을 이용하여 발송하기 때문에 계정에 대한 패스워드가 존재한다. 또한 SMTP 서버를 패스워드 없이 오픈해 놓으면 스팸 메일을 발송하는 원인이 될 수 있다.

그래서 SMTP 서버로 메일을 발송할 때 보안설정이 되어 있는 형태로의 자바메일 발송예제가 필요한 것이다.
다음 두 개의 소스 코드가 존재한다.


[MyAuthenticator.java]
package net.wiseant.mail;

import javax.mail.Authenticator;

/**
 * @author SangHyup LEE
 *
 */
public class MyAuthenticator extends Authenticator {

    private String id;
    private String pw;

    public MyAuthenticator(String id, String pw) {
        this.id = id;
        this.pw = pw;
    }

    protected javax.mail.PasswordAuthentication getPasswordAuthentication() {
        return new javax.mail.PasswordAuthentication(id, pw);
    }

}

소스 코드에서 보는 바와 같이 java mail API의 Authenticator 클래스를 extends 하여 구현한 예제이다. 간략하게 생성자의 인자로 id와 password를 받는다. 그러면 해당 서버의 아이디와 패스워드로 인증된 객체를 생성하는 것이다.

[SMTPTest.java]
/**
 * 
 */
package net.wiseant.mail;

import java.util.Properties;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

/**
 * @author SangHyup LEE
 *
 */
public class SMTPTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String host = "mail.wiseant.net";//smtp 서버
        String subject = "메일제목";
        String content = "메일내용";
        String from = "wiseant@wiseant.net"; //보내는 사람
        String to = "korcslewis@gmail.com";
        
        try{
            // 프로퍼티 값 인스턴스 생성과 기본세션(SMTP 서버 호스트 지정)
            Properties props = new Properties();
            
            props.put("mail.smtp.host", host);
            props.put("mail.smtp.auth", "true");
            
            MyAuthenticator auth = new MyAuthenticator("wiseant@wiseant.net", "password");
            
            Session mailSession = Session.getDefaultInstance(props, auth);
            // sess.getPasswordAuthentication(host);
            
            Message msg = new MimeMessage(mailSession);
            msg.setFrom(new InternetAddress(from));//보내는 사람 설정
            InternetAddress[] address = {new InternetAddress(to)};
            
            msg.setRecipients(Message.RecipientType.TO, address);//받는 사람설정
            
            msg.setSubject(subject);// 제목 설정
            msg.setSentDate(new java.util.Date());// 보내는 날짜 설정
            msg.setContent(content,"text/html;charset=euc-kr"); // 내영 설정 (HTML 형식)
            
            Transport.send(msg); // 메일 보내기
            
            System.out.println("메일 발송을 완료하였습니다.");
        } catch ( MessagingException ex ) {
            System.out.println("mail send error : " + ex.getMessage());
        } catch ( Exception e ) {
            System.out.println("error : " + e.getMessage());
        }
    }

}


SMTPTest.java 코드는 SMTP 서버의 인증후, 실제 메일을 발송하는 예제이다. Java Mail API를 사용하여 보내는 예제와 거의 동일하다. 다만 MyAuthenticator 클래스의 인스턴스를 생성하여 보내고자 하는 SMTP 서버로부터 보안 설정을 확인 후, 수행하는 것이 다를 뿐이다.

이진검색 알고리즘을 재귀적 함수를 사용한 자바소스

설명은 소스 주석에 포함하고 있다. 디버깅을 위해서 간단한 메시지도 출력하고 있다.


/**
 * n개의 방으로 구성된 1차원 배열에 값이 정렬되어 있을 때 임의의 값 x를 검색하는
 * binary search 알고리즘을 재귀적 함수로 구현한다.
 */
package net.wiseant.test.algorithm.search;
/**
 * @author Sang-Hyup Lee
 * @version 1.0
 *
 */
public class BinarySearchRecursive {

 static int arraySize = 1000;
 static int array[] = new int[arraySize];
 static int loopCount = 1;
 
 static void init() {
  for ( int i=0; i < arraySize; i++ ) {
   array[i] = i;
  }
 }
 
 static void binarySearch(int findNumber, int left, int right) {
  System.out.print("Loop count[" + loopCount + "], ");
  loopCount++;
  
  System.out.print("left : " + left + ", right : " + right + ", ");
  
  int center = (left + right) / 2;
  System.out.println("center : " + center);
  
  if ( array[center] == findNumber ) {
   System.out.println("Found it " + center + ", array[" + center + "]");
  } else if ( array[center] > findNumber ) {
   binarySearch(findNumber, left, center - 1);
  } else if ( array[center] < findNumber ) {
   binarySearch(findNumber, center + 1, right);
  }
 }
 
 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  init();
  
  int findNumber = 629;
  binarySearch(findNumber, 0, 999);
 }

}

소개 - [UPnP]CyberLink for Java

UPnP stack을 구현한 많은 구현체, 오픈 소스들이 존재한다.
그 중에 몇 가지를 살펴보았는데, UPnP 구현과 stack을 잘 구현해 놓은 것은 Intel에서 제공하는 툴이 있다. C/C++ 코드 뿐만 아니라, Java 코드도 제공하는 것으로 되어 있는데, 예제 구현도 C/C++ 로 되어 있는 것으로 봐서는 Java 코드는 전체 오픈소스로 제공하지 않는다.
더군다나 생성되는 코드가 Intel.jar 라이브러리에 대해서는 공개되어 있지 않다. 아니면 내가 찾질 못했거나...

그래서 Java로 구현된 UPnP 오픈소스 중에 보게 된 것이다. CyberLink for Java 이다.
많은 곳에서 소개도 하고 있고, 실제 코드를 받아서 실행해보니 Stack과 Contrl Point는 잘 동작한다.

UPnP Java 버전을 고려하는 사람이면 참고할 만한 곳이다.

Singleton pattern의 응용 샘플

얼마전까지 Head First Design Pattern 책을 통해서 디자인 패턴에 대한 공부하는 중이었다. 지금도 언제나 공부는 해야 하지만 시간이 있을 때 보아두는 게 좋을 거란 생각이 들었다.

이미 읽은지는 오래되었지만 Singleton pattern을 응용할 만한 기능이 있어 구현해 보았는데 실제로 유용하였다. 해당 소스는 실제 업무에서 사용하는 중이서 소스 코드에 대한 전체 설명은 하지 못하겠지만 개념적인 것을 한 번 살펴보고자 한다.

예를 들어, 카테고리와 같이 시스템 내에서 업데이트가 자주 발생하지 않는 테이블의 레코드일 경우 해당 테이블의 내용을 자주 디스플레이해야 하는 경우를 생각해 보자. 이럴 때 일반적으로는 해당 트랜잭션이 발생할 때마다 데이터베이스에 쿼리를 날린 후 리스트를 처리하게 된다. 이러한 일을 자주 업데이트되지 않는 정보를 매번 데이터베이스에 접속한 후 처리해서 가져오는 것은 전체적인 시스템의 성능상 낭비에 해당하는다. 이러한 트랜잭션이 많이 발생하지 않는 경우에는 별다른 문제를 발생시키지 않지만 그렇치 않은 경우에는 제법 많은 영향을 성능상에 문제를 발생시킨다.

따라서 이러한 경우에 싱클턴 패턴을 다음과 같이 사용해 보자. 해당 코드는 간단하게 실제로 사용해 본 소스를 여기에 맞게 재구성한 것이다. sudo code 형태로 재구성하였기 때문에 테스트를 직접해 보기에는 어려움이 있을수도 있을 것이다. sudo code 형태이긴 하지만 컴파일시에 에러를 발생시키지 않는다. 알고리즘에 해당하는 부분을 주석으로 설명하고 있기 때문인데 각자 업무에서 적용할만한 부분을 찾으면 된다.

/**
 * 
 */
package net.wiseant.designpattern.singleton;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author Sang Hyup Lee
 * @version 1.0
 *
 */
public class InformationSingleton {

    private volatile static InformationSingleton singletonInstance;
    private List informationList;
    
    public InformationSingleton() {
        // initinalize
        initinalize();
    }

    public static InformationSingleton getInstance() {
        if ( singletonInstance == null ) {
            synchronized ( InformationSingleton.class ) {
                if ( singletonInstance == null ) {
                    singletonInstance = new InformationSingleton();
                }
            }
        }
        
        return singletonInstance;
    }

    /**
     * initinalize() 메소드에서는 InformationSingleton 인스턴스가 처음으로 생성될 때
     * 수행할 초기화를 구동시킨다.
     * 여기서는 해당 데이터베이스의 테이블 레코드를 리스트 형태로 얻어와서 List 객체에 대입해 둔다.
     */
    public void initinalize() {
        // TODO Auto-generated method stub

        // 1. 데이터베이스 커넥션
        // 2. informationList에 대입할 레코드의 리스트를 얻어온다.
    }
    
    /**
     * update() 메소드에서는 해당 테이블에 추가 또는 업데이트 트랜잭션이 발생시
     * 해당 추가/업데이트를 수행한 코드에서 호출하여 List 객체를 갱신해 준다.
     */
    public void update() {
        // 해당 레코드의 추가 또는 업데이트가 발생시 작동한다.
        // informationList에 대입할 레코드의 리스트를 갱신한다.
    }

    /**
     * @return the informationList
     */
    public List getInformationList() {
        return informationList;
    }
    
    public List getInformationListByType(int type) {
        ArrayList resultList = new ArrayList();
        
        Iterator informationIter = this.informationList.iterator();
        while ( informationIter.hasNext() ) {
            informationIter.next();
            
            // 해당 Information 중에 type이 동일한 객체만 resultList에 add 한다.
        }
        return resultList;
    }
}


위의 코드 중에서 설명이 필요한 부분은 대부분 주석에서 하고 있다. 다만 한가지 짚고 넘어갈 코드가 있다. 싱글턴 패턴을 구현하기 위해서 가장 중요한 부분으로 getInstance() 메소드 부분이다.
싱글턴 패턴으로 구현된 클래스를 클라이언트에서 호출하기 위해서는 객체네임.getInstance() 형태로 호출한게 되는데, 여기서는 InformationSingleton.getInstance() 가 된다.
이 메소드의 내용을 살펴보면 별다른 것은 없지만 생성된 인스턴스가 없을 경우에는 동기화 처리를 통하여 인스턴스를 생성한다.

이렇게 심플하게 생성되는 인스턴스는 별다른 문제를 발생시키지 않는다. 하지만 멀티스레딩이나 갑작스런 인스턴스의 잘못된 생성이 발생할 경우 인스턴스 생성에 문제가 발생하게 되는데, 이를 Java 1.4 이후 버전에서는 DCL(Dobule-Checking Locking)을 지원한다. 이렇게 지원하는 코드는 인스턴스명을 private으로 선언하는 부분에 있다.

private volatile static InformationSingleton singletonInstance;

volatile 키워를 Java 1.4 이후의 버전에서만 정상적으로 작동함으로 주의할 부분이라고 하겠다. 그러면 최종 코드는 완성된 것이다.

이와 같이 싱글턴 패턴을 사용할 경우 얻을 수 있는 장점은 해당 Information List를 얻어오는 부분이 하나의 인스턴스에서 처리됨으로 데이터베이스에 각 트랜잭션마다 쿼리로 처리하지 않고도 해당 리스트를 원하는 형태로 얻어갈 수 있다. 원하는 리스트의 형태는 각 메소드를 언제든지 생성하여 제공할 수 있다.
이로서 불필요한 데이터베이스로의 접근을 막음으로 서버 사이드 시스템내에서는 성능을 높일 수 있는 방안이라고 할 수 있다. 간혹 DBMS에서는 이러한 일을 메모리 DB 형태로 제공하기도 한다고 한다. 이 내용은 필자도 연구해 보아야 할 필요가 있을 듯 하다.

최종적으로 디자인 패턴의 가장 큰 장점은 이미 많은 경험을 통한 하나의 패턴 속에 넣어둠으로서 문제를 작게 발생시키거나 보다 효율적이 코드를 구현하기 위함에 있다. 싱글턴 패턴도 간단한 개념이고 구현도 간단하지만 적절하게 적용할 부분을 애플리케이션에서 찾는다면 위와 같은 문제들을 잘 해결할 수 있으리라 본다.

EnumerationIterator - Enumeration을 Iterator 형태의 Adapter로서 제공하는 클래스

몇 일동안 Head First Design Pattern을 다시 보고 있는 중이다. 이전에 놓친 부분도 많은 거 같고, 항상 중요한 것을 잊어버릴 수 밖에 없기에 다시한 번 다짐을 해 보고자 읽기 시작했는데, 도움이 많이 된다.

이번에 소개할 패턴은 Adapter Pattern 인데 실제 설명과 내용은 책을 참조하면 된다. Head First Design Patten은 워낙 유명한만큼 좋은 책이니 한 번 씩 읽어보길 바란다.
이 책의 Adapter Pattern에서 제공하는 예제 중에 Enumeation Collection 객체를 Iterator Collection 객체 형태로의 adapter로서 작동할 수 있는 EnumerationIterator 클래스를 제공한다. 이 클래스의 소스 코드와 테스트 할 수 있는 코드를 여기서 제공한다.

실제 업무 상에 Enumeration 객체를 통해서 각각의 Object를 가져오는 경우가 많은데 이를 Iterator를 사용하는 형태로 EnumerationIterator 클래스를 사용하면 가져올 수 있다.

[EnumerationIterator.java]
/**
 * 
 */
package net.wiseant.designpattern.adaptor;

import java.util.Enumeration;
import java.util.Iterator;

/**
 * @author Sang Hyup Lee
 * @version 1.0
 *
 */
public class EnumerationIterator implements Iterator {

    Enumeration enumeration;
    
    public EnumerationIterator(Enumeration enumeration) {
        this.enumeration = enumeration;
    }
    
    /* (non-Javadoc)
     * @see java.util.Iterator#hasNext()
     */
    public boolean hasNext() {
        // TODO Auto-generated method stub
        return this.enumeration.hasMoreElements();
    }

    /* (non-Javadoc)
     * @see java.util.Iterator#next()
     */
    public Object next() {
        // TODO Auto-generated method stub
        return this.enumeration.nextElement();
    }

    /* (non-Javadoc)
     * @see java.util.Iterator#remove()
     */
    public void remove() {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException();
    }

}


다음은 위의 코드를 테스트해 볼 수 있는 간단한 Test 코드이다.

/**
 * IteratorAdapterTest.java
 */
package net.wiseant.designpattern.adaptor;

import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;

/**
 * @author Sang Hyup Lee
 * @version 1.0
 *
 */
public class IteratorAdapterTest {
    
    /**
     * @param args
     */
    public static void main(String[] args) {
        Vector v = new Vector();
          
        v.addElement(new String("Java"));
        v.addElement(new String("Eclipse"));
        v.addElement(new String("Spring"));
          
        Enumeration enu = v.elements();
        
        /*
        Iterator iter = v.iterator();
        while ( iter.hasNext() ) {
            String temp = ""+iter.next();
            System.out.println(temp);
        }
        */
        
        EnumerationIterator iteratorAdapter = new EnumerationIterator(enu);
        
        while ( iteratorAdapter.hasNext() ) {
            String temp = ""+iteratorAdapter.next();
            System.out.println(temp);
        }
    }
    
}


테스트 코드의 주석부분은 Vector가 Iterator 형태로도 제공해 준다는 것을 명시하고 있다. 하지만 실제 코드의 에제는 Enumeration 형태로 엘리먼트 또는 각 객체를 EnumerationIterator Adapter 클래스를 이용하는 방법을 보여주고 있다.

Head First Desgin Patterns

사용자 삽입 이미지
이미 출간한 지 오랜된 책이다. 그리고 워낙 유명한 책이어서 리뷰를 쓰는게 적당할까? 라는 생각이 들 정도이다. 그래도 좋은 책은 언제나 소개하고픈 마음이 든다.

디자인 패턴이란 분야 자체가 소프트웨어 개발에 국한되어있다. 그리고 초급자에겐 웬지 부담이 될만한 분야이다. 실제로 초보자에게 권하기에는 어려움이 있는 책이다. 몇 년의 개발 겨험이 있는 사람들이 읽어보면 좋은 책이다. 그리고 경험이 있는 개발자들에겐 필수적인 책이라 할 수 있다.

실제 업무에서 디자인 패턴을 적용할 만한 파트를 찾기도 쉬운 일은 아니다. 하지만 디자인 패턴을 알지도 못한 상태에선 이러한 것을 찾기도 적용해 보기도 힘들 것이다.

Head First 시리즈이기에 이해하기 쉽고 재밌게 읽어보면서 적용해 볼 수 있다. Head First Java와 함께 읽으면 더 좋은 성과를 낼 수도 있을 것이다.

실제 이 책을 통해서 적용해 본 사례를 들면 더 좋을 것이란 생각이 드는데, 실제로 적용해 본 패턴은 factory pattern, strategy pattern, singleton pattern, proxy pattern 정도인데 모두 다 좋은 성과와 성능을 낼 수 있었다. 무엇보다 이 책에서 소개하는 여러 가지 원칙들 - OCP, 인터페이스 기반의 설계 및 코딩 등 - 은 실제 업무에서 항상 적용 가능하다. 그래야만 더 나은 개발자로서 성장할 수 있으며 잘 짜여진 소프트웨어로 본인의 역량도 더 발휘할 수 있으리란 생각이 든다.

끝으로 평점을 한다면 별 다섯개를 충분히 받을 수 있음으로 디자인 패턴에 대한 공부가 필요한 분들은 반드시 이 책으로 통해서 하길 바란다

Spring MVC에서 XML로 응답하는 방법

일반적으로 Ajax와 함께 웹 애플리케이션을 개발하게 될 경우 XML을 응답으로 주어야 할 경우가 많다.
또한, Spring framework을 애플리케이션 서버에서 사용할 경우 대부분 Spring MVC를 사용하게 되어 있다.

그렇다면 이 둘의 조합인 Spring MVC에서 XML로 응답하는 방법은 어떨까? 일반적인 Spring MVC의 사이클은 다음의 그림과 같다.

사용자 삽입 이미지

위의 그림에서 살펴보는대로 ViewResolver를 통해서 View 객체(또는 String)을 결정하게 되어 최종 View를 처리해 주어야 한다.

보통은 다음과 같이 InternalResourceViewResolver를 사용하여 jsp 파일을 view를 담당하게 된다.

 <bean id="viewResolver"
  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass"
   value="org.springframework.web.servlet.view.JstlView" />
  <property name="prefix" value="/WEB-INF/jsp/" />
  <property name="suffix" value=".jsp" />
 </bean>


문제는 이러한 일반적인 상황이 아닌, Spring MVC를 사용하여 XML로 응답하고 싶은 경우이다. Spring MVC를 사용하지 않고, 기존의 방식을 따라서 Servlet에서 처리해 주면 되는데 Servlet을 사용할 경우 매번 web.xml에 Servlet 관련 셋팅을 해 주어야 하고, Spring DAO, Interface 같은 Content Loader를 항상 해 주어야 하는 번거러움이 있다.

그리고, Spring MVC를 사용하는 것이 Request의 처리나 비지니스 로직에 집중하기가 쉬움으로 XML을 응답으로 주어야 할 다른 경우에도 Spring MVC 내에서 XML을 응답해 주는 방법이 필요하다.

방법은 이미 Spring framework 에서 ViewResolver 중에 결정해 두었다. 다음의 XmlViewResolver 셋팅을 보자.

 <!-- XML View Resolver -->
 <bean id="xmlViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
     <property name="order" value="1"/>
     <property name="location" value="/WEB-INF/config/xml-views.xml"/>
   </bean>

xmlViewResolver id명으로 "org.springframework.web.servlet.view.XmlViewResolver" 클래스를 사용하고 있다. 그리고 location property의 값으로 다른 XML 설정 파일을 지정하고 있다. 그러면 xml-views.xml을 살펴보자.


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
    "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
 <!--
 ajax view a single xml rendering 
 -->
 <bean name="ajaxResponseXMLView"  class="net.wiseant.web.xml.AjaxResponseXMLView">
     <property name="contentType">
        <value>text/xml;charset=utf-8</value>
        </property>
    </bean>

</beans>

 간단하게 하나의 클래스만 ajaxResponseXMLView라는 id명으로 정의하고 있다. XML 응답을 최종 AjaxResponseXMLView 클래스를 통해서 해 준다는 말이다. 간단하게 이 클래스를 살펴보자.


public class AjaxResponseXMLView extends AbstractView {

 private final Logger logger = Logger.getLogger(getClass());
 
 /* (non-Javadoc)
  * @see org.springframework.web.servlet.view.AbstractView#renderMergedOutputModel(java.util.Map, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
  */
 @Override
 protected void renderMergedOutputModel(Map map, HttpServletRequest request,
   HttpServletResponse response) throws Exception {
  // TODO Auto-generated method stub
  String xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"

  StringBuffer xmlSb = new StringBuffer();

  sb.append(xmlHeader);
  sb.append(/*XML 내용 */);
    
  response.setContentType("application/xml");
  response.setCharacterEncoding("utf-8");
  response.setHeader("Cache-Control", "no-cache");
  response.setContentLength(xmlSb.toString().getBytes("utf-8").length);
  
  response.getWriter().print(xmlSb.toString());
 }

}

AbstractView 추상 클래스를 extends하여 구현한 클래스이다. 위의 예제에서는 XML 내용이 포함되어 있지 않다. 프로젝트에 필요한 XML을 넣어주면 된다.
이렇게 하면 AjaxResponseXMLView 클래스를 통해서 XML을 응답으로 처리해 줄 수 있다. 그렇다면 요청은?
요청시에는 Spring framework 버전에 따라서 다를 수가 있는데 이번 예제에서는 Spring2.5 기준으로 한 Annotation 기반의 예제를 사용한다.


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author Sang Hyup Lee
 * @version 1.0
 *
 */
@Controller
public class AjaxRequestController {

 private final Logger logger = Logger.getLogger(getClass());
 
 private String xmlView = "ajaxResponseXMLView";
 
 /**
  * @param categoryService the categoryService to set
  */
 @Autowired
 public void setCategoryService(CategoryService categoryService) {
  this.categoryService = categoryService;
 }
 
 /**
  * @param xmlView the xmlView to set
  */
 /*
 @Autowired
 public void setAjaxResponseXMLView(AjaxResponseXMLView ajaxResponseXMLView) {
  this.ajaxResponseXMLView = ajaxResponseXMLView;
 }
 */
 
 @RequestMapping(value="/ajax/contentDirectory")
 public ModelAndView contentDirectory(HttpServletRequest request,
     HttpServletResponse response, ModelMap model) {
  logger.debug("/ajax/contentDirectory.do Request process");
  
  // Request process
  
  return new ModelAndView(xmlView);
 }
 
}

살펴볼 부분은 리턴 타입이 ModelAndView인데 보통 Spring MVC Controller를 확장하여 사용할 경우와 동일하다. 이 때 간단하게 String 타입의 id 명을 그러니깐 이전에 셋팅해 준 ajaxResponseXMLView 클래스를 지정한 ID를 명시해 주었다.
그러면 최종 리턴 객체를 AjaxResponseXMLView 클래스를 사용하여 XML를 리턴하게 된다.

하드 백업하는 데 무려 이틀을 소요하다...

4~5년 가량을 사용한 하드 디스크인거 같다.
최근 쿼드코어 CPU로 새로 PC를 회사에서 구입한 후 그동안 미루어 두었던 옛 하드 디스크를 백업하였는데, 무려 이틀이란 시간이 소요되었다.

그러니깐 어제부터 거의 아무것도 하지 않고 자료 정리하고, 압축할 것들은 압축하고, 지울 것은 지우고, FTP로 연결해서 백업할 것들을 백업한 것이다.

휴... 그래도 그동안 미루어 두었던 일을 처리하니 속이 시원하다.
백업한 자료를 가지고 2차로 정리해야 하지만 한 동안은 작업하는데 있어 별다른 문제는 없을 듯 하다^^

2009년 5월 11일 월요일

자바 프로그램으로 윈도우 레지스트리 다루기

언젠가 필요할지도 모를거 같아서 모아둔 자료이다.

자바 프로그램으로 원도우 레지스트리 다루기


문자열에 대한 techtips, '=='과 'equals'의 차이점은?

문자열의 오브젝트의 길이는?
문자열 오브젝트 비교법
 
 
특히, "문자열 오브젝트 비교법"에 대한 글은 꼭 읽어보면 좋다.
다른 질문으로 기억하면 좋겠다...
 
'=='과 'equals'의 차이점은?
 
'=='는 두 개의 변수가 동일한 메모리를 참조하고 있는지를 비교한다.
'equals' 메소드는 두 개의 변수의 실제 char를 비교한다.

[이전 링크]

String과 StringBuffer 성능 차이

이전에 찾은 자료를 올려 놓습니다. 작성자 : 최종명(jmchoi@it.soongsil.ac.kr)

String과 StringBuffer 성능 차이
글: 최종명(jmchoi@it.soongsil.ac.kr)

String은 내용을 변경할 수 없기 때문에 String에서 + 연산자를 사용하면 내부적으로StringBuffer를 생성해서 append() 메소드를 이용해서 문자열을 결합한다는 것은 대부분의 자바 프로그래머가 알고 있을 것입니다.
따라서 String을 많이 사용하는 서블릿이나 기타 프로그램에서는 되도록이면 StringBuffer나 char[]를 사용하시는 것이 효과적이라는 것도 다 알고 있는 사실입니다. 그런데 프로그램하다보면 귀찮아서라도 String을 많이 사용하는 것이 현실입니다.

그래서 잠시 10여분을 할애하여 String과 StringBuffer의 성능 차이를 테스트 해보았습니다.
테스트는 제가 새로 얻은(?) 펜티엄에 윈도우 2000이 설치된 컴퓨터 에서 했습니다. 테스트할 프로그램은 다음과 같습니다. 각 프로그램은 모두 "a" 문자열을 30,000번 씩 결합하도록 했습니다.
 
예제 :  StringTime.java
     1  public class StringTime {
     2
     3      public static void main(String args[]) {
     4          Runtime rt = Runtime.getRuntime();
     5          System.out.print(rt.freeMemory());
     6          System.out.println("/" + rt.totalMemory());
     7          long start = System.currentTimeMillis();
     8          String a = "a";
     9          for(int i=0; i < 30000; i++) {
    10              a += "a";
    11          }
    12          long stop = System.currentTimeMillis();
    13          System.out.println(stop - start);
    14          System.out.print(rt.freeMemory());
    15          System.out.println("/" + rt.totalMemory());
    16      }
    17
    18  }
 
 
 
예제 :  StringBuffer.java
     1  public class StringBufferTime {
     2
     3      public static void main(String args[]) {
     4          Runtime rt = Runtime.getRuntime();
     5          System.out.print(rt.freeMemory());
     6          System.out.println("/" + rt.totalMemory());
     7          long start = System.currentTimeMillis();
     8          StringBuffer a = new StringBuffer("a");
     9          for(int i=0; i < 30000; i++) {
    10              a.append("a");
    11          }
    12          long stop = System.currentTimeMillis();
    13          System.out.println(stop - start);
    14          System.out.print(rt.freeMemory());
    15          System.out.println("/" + rt.totalMemory());
    16      }
    17
18       }
 
테스트 결과
 
String
1830448/2031616
41800            -> 총 소요시간(단위: ms)
967576/2031616
 
StringBuffer
1830336/2031616
30               -> 총 소요시간(단위: ms)
1673200/2031616
 
시간 차이도 많이 났지만, 메모리 사용량도 상당한 차이가 있었습니다. 이와 함께 더 큰 문제는 이 작업이 많아질 수로 가비지 콜렉션에 의해 String을 사용하는 경우에 시간에 휠씬 큰 차이로 많이 소요된다는 것입니다.
 
 
String클래스와 StringBuffer클래스의 차이점
 
* String은 문자열의 내용이 조금이라도 바뀌거나 스트링 컨케트네이션되면 새로운
  객체를 만든다.
  레퍼런스를 잃어버린 객체는 가비지 컬렉션의 대상이 되며 새로운 객체에  새 주소를
  주므로 해쉬코드도 변한다. Immutable한 특징도 가지고 있다.
 
* StringBuffer는 원래 있던 객체의 내용만 바뀌는 Mutable한 특징이 있다.
 
  Mutable : 변덕스러운.
  Immutable : 불변의.
 
StringBuffer 안의 모든 문자열을 지우고 싶을때
 
StringBuffer sb = new StringBuffer();
sb.append("안녕하세요.abc");
sb.delete(0, sb.length());
 
 
무심코 쓰고 있는것들, 하지만 왜~ 쓰냐 ? 를 알아가는것이 중요..!