2010. 1. 20.

JNpDp 4장

기본적인 파일 입출력을 하는 부분이다.

필요할 때가 있을듯하여 unless 매트로를 구성했다.

;; File Read/Write

(defmacro unless [expr form] (list 'if expr nil form))
파일을 열고 닫을 때를 대비해서 파일 기술자(file description)을 얻어본다. 원래는 read, write에 대해서 서로 다른 인스탄스를 리턴해야하지만 일단은 귀차니즘으로 한번에..

(defn file_open [s]
  (java.io.FileInputStream. s))

(defn file_wopen [s]
  (java.io.FileOutputStream. s))

(defn file_close [fd]
  (.close fd))
꽤나 사람 열받게 했던 부분.. reader를 구성해야하는데 일단 reader는 lambda 함수로 구성했다.
해당하는 fd에서 바이트를 읽어오는 형식으로 tail - recursion으로 구현

(defn file_input [fd]
  (let [reader (fn []
                 (try (.read fd)
                      (catch Exception e -1)))]
    (loop [data (reader)]
      (unless (== data -1)
              (do
                (print (str data))
                (recur (reader)))))))
읽은 놈을 다른 파일로 쓰기위한 부분.. 일단 reader를 만들고 이후에는 해당 기술자로 뿌렸다.
원칙대로라면 fd1, fd2도 인자로 계속 돌려줘야하는데.. 귀차니즘으로 포기..
(defn file_output [fd1 fd2]
  (let [reader (fn []
                 (try (.read fd1)
                      (catch Exception e -1)))]
    (loop [src (reader)]
      (unless (== src -1)
              (do
                (.write fd2 src)
                (recur (reader)))))))
이건 실행용 구문.. 별 의미는 없다. do를 써서 복수문장을 돌린 것이 좀 다른 거..
    
(defn file_run [s]
  (let [fd (file_open s)]
    (do
      (file_input fd)
      (file_close fd))))

(defn file_run2 [s1 s2]
  (let [fd1 (file_open s1)
        fd2 (file_wopen s2)]
    (do
      (file_output fd1  fd2)
      (file_close fd2)
      (file_close fd1))))
리더 테스트.. java에서도 스트림을 reader로 묶는데 꽤 애를 먹었는데 여기서도 역시나.. 일단 스트림을 스트림 리더로 묶고.. 다음에 특화된 리더로 다시 묶었다.

;; Reader Test
(defn reader_test []
  (let [bufReader (java.io.BufferedReader.
                   (java.io.InputStreamReader.
                    System/in))]
    (do   (do
      (print "Please Enter Your name :")
      (println "Please to meet you" (.readLine bufReader)))))

      (print "Please Enter Your name :")
      (println "Please to meet you" (.readLine bufReader)))))
swank버그로 인해서 slime내에서는 정상적인 동작이 불가능.. 외부에서 그냥 실행시키면 잘 돈다.









2010. 1. 15.

JNpDp 3장

Java Network Programming and Distributed Computing 3장 예제소스를 Clojure로 바꿔보고 있다.
로컬 호스트를 찾는 부분부터 걸리는데..

// Get the local host
InetAddress localAddress =
InetAddress.getLocalHost();
System.out.println ("IP address : " +
                localAddress.getHostAddress() );


이 부분이다.
Clojure에서는 다음과 같이 일단 해봤다.
(ns inetaddress
  (:import [java.net InetAddress]))

(defn localhost []
  (let [localAddress (java.net.InetAddress/getLocalHost)]
    (print (.getHostAddress localAddress))))
일단 import를 하고, java 메서드를 호출해서 localAddress라는 임시인스탄스를 만든다.
마지막으로 해당 인스탄스로부터 getHostAddress를 호출하게 했다.

그 다음 network resolver 를 쉬운 편..
(defn network_resolver [s]
  (let [addr (java.net.InetAddress/getByName s)]
    (print (str "IP Address : " (.getHostAddress addr)))
    (print (str "Hostname : " (.getHostName addr)))))
라고 해주면 된다. 일단 슬슬 clojure에 익숙해져간다.

2010. 1. 12.

노키아, 심비안, 마에모...

심비안 폐지얘기가 나와서 끄적댑니다.

2009년 한해동안 노키아는 꽤나 애를 먹었습니다.
주력사업인 핸드폰 단말기 시장에서는 후발주자와 힘겨운 싸움을 하고 있었고, 스마트폰 시장, 특히 북미에서는 Apple, RIM에 밀려 시장 점유율, 이익율 두 가지에서 무지 고전을 했더랬죠. 거기다 안드로이드 쇼크까지 터지는 바람에 개발자들의 눈에서 심비안이 밀려나는 상황까지 됐습니다.

이미 이때 심비안 2, 3, 4에 대한 이정표는 나와있었습니다. 2009년 말에 2,  2010년 2분기즈음에 3, 그리고 3와 6개월 텀을 두고 4가 나오는 식이었지요. 근데 스마트폰 시장에서 심비안에 대한 인식은 아주 안좋았습니다. 일부 매체에서는 심비안 60 5ed 를 채용한 N97에 실망했다는 내용도 나왔습니다.(전체적인 기기완성도는 좋다라고 했지만요..) 업친데 덮친격으로 하반기에는 노키아에서 안드로이드를 채용한 핸드셋을 만든다는 루머까지 돌았지요(노키아는 부정했습니다).
결국 이 와중에서 내노라하는 기업분석가/기관에서는 노키아가 심비안을 포기하고, 마에모에 집중할 가능성이 있다는(그들에게는 일종의 희망사항) 보고서를 내놨습니다. 이게 2009년 상황입니다.

하반기에 들어서면서 노키아는 마에모 5를 채용한 N900을 공개했고, 마에모 6에 대한 로드맵을 내놓게됩니다. 그러면서 OS는 2원전략으로 갈 것이라고 공표하죠.
일반 핸드셋 및 저가 스마트폰 부문에서는 심비안을, 플래그쉽 스마트폰에서는 마에모 플랫폼으로 가겠다고 한 것입니다. 문제는 아직까지도 심비안은 제대로 터치스크린(특히나 정전식)에 적응을 못하는 상태라는 점입니다. 멀티터치를 비롯한 각종 UI에 관련해서 상당한 불협화음을 내고 있는데, 이것을 올중반에 나올 새로운 심비안 OS로 대체하겠다는 것이죠.

올 상반기 노키아 스마트폰은 상당히 힘겨울 것으로 생각합니다. 불붙기 시작한 안드로이드 플랫폼이 수십종씩 쏟아지고 있고, 새로운 심비안을 공개하겠다는 중반기에는 Apple의 4G 아이폰이 기다리고 있지요. 결국 이 동안의 스마트폰 싸움을 마에모가 받아줘야하는 상황입니다.

노키아입장에서는 새로운 심비안이 나오기 전까지는 스마트 폰 시장의 시장 점유율이 현 상황을 유지했으면 할 겁니다. 그렇게만 된다면, 새로운 심비안으로 가격/성능비가 뛰어난 시장을, 마에모로는 고사양 스마트폰 시장을 동시에 공략할 수 있으니까요. Qt를 내세우면서 심비안/마에모 양쪽에 사용할 수 있을 것이라고 개발자들에게 지속적으로 홍보하고 있고(물론 그전에 양 플랫폼에 걸친 클래스 네이밍부터 정리해야하는 등 문제가 좀 많지만), 인도, 인도네시아, 러시아, 브라질, 유럽등에서는 아직도 확실한 시장을 점유하고 있습니다.

실제로 핸드셋 자체보다는 핸드셋과 연계된 각종 은행/교통/생활편의 시설서비스가 잘 되어있다보니, 다른 핸드셋이 끼어들기가 어렵웠지만 앞으로도 이 상황이 지속될지는 않을 겁니다. 소프트웨어로 해결 가능한 부분은 다른 플랫폼에서 금새 끼어들 것이고, 노키아가 자체적으로 육성중인 SNS, 지도, 정보, 앱스토어는 통신사/금융사 역시 뛰어드는 곳이니까요.

제 맘같아서는 노키아가 더 분발해서, Apple, 구글, 노키아 3파전이 제대로 불붙었으면 좋겠습니다. 그렇게만 된다면야 소비자는 저렴한 가격에 좋은 스마트폰을 사용할 수 있을 것이고, 이들이 모두 서비스 플랫폼 사업자이거나, 변신하려는 태세이기때문에 통신시장에도 신선한 충격을 줄 수 있을 것 같아서 말이지요. :)

--
새로움을 느끼기에 삶은 즐겁다..
모험가 아돌 크리스틴을 꿈꾸며..
Sia..

2009. 12. 10.

Remote에 있는 Lisp 구현에 접근해서 개발하기..

준비물

1. 로컬머신
Emacs + Slime

2. 원격머신
SSH , 리습구현

작업

1. 일단 Slime은 로컬 원격  버전을 맞추어서 모두 다운 받는다.
2. 원격 머신에서 다운 받은 Slime의 swank.asd를 적당한 위치(여기에서는 ~/systems/ )에 복사하거나 링크를 만들어 놓는다.
3. 원격머신에서 .sbclrc( SBCL을 쓴다고 가정)을 생성하고 내용을 다음과 같이 만든다.
(require :asdf)
(push "/path/to/~systems/" asdf:*central-registry*)
4. 이제 SBCL에서 다음과 같이 실행시킨다.
(require :swank)
(swank:create-server :port 4005)
5. ssh를 이용 리모트 머신과 로컬 머신의 포트를 서로 맞춘다.
ssh -L4005:127.0.0.1:4005 username@host
6. 클라이언트 머신에서 emacs의 .emacs파일에서 slime을 로딩한다.
(require 'slime)
7. 이제 M-x slime-connect를 해서 서버는 127.0.0.1 로하고 포트를 4005로 맞추면 이제부터 리모트 머신의 swank를 통해 lisp evaluation을 할 수 있다.

8. 추가로 로컬에서 lisp사용시 항상 해당 서버쪽에 맞게끔 이름을 넣고 싶다면 다음과 같은 내용을 .emacs에 넣는다.

;; remote <-> local translate
(setf slime-translate-to-lisp-filename-function
      (lambda (file-name)
        (subseq file-name (length "/ssh:siabard@192.168.10.42:")))
      slime-translate-from-lisp-filename-function
      (lambda (file-name)
        (concat "/ssh:siabard@192.168.10.42:" file-name)))



2009. 12. 2.

Clojure 사용소감

지극히 주관적인 소감입니다.

PAIP(Paradigms of Artificial Intelligence Programming)를 공부하는 중인데 On Lisp이랑 Practical Common Lisp을 clojure 로 공부하는 사람들의 기사를 보고, 하는 김에 리습이랑 클로져를 같이 해보자 하고 시작했습니다.

이 책의 모든 소스코드는 Common Lisp 기준이라서 그래도 같은 계열인데 쉽겠지하고 붙었다가 어려움을 겪고 있습니다.
아직은 극 초반이기는 한데.. Common Lisp에서 익숙한 개념을 Clojure에서는 다르게 봐야하는 부분이 조금씩 있습니다.

1. list보다는 vector
일단 함수의 인자부터 Common lisp은 list 인데 비해, clojure는 vector라는 개념을 사용합니다.
이런 이유로 몇몇 special form의 규칙도 살짝 바뀐게 있습니다.
cond, let이 대표적인데 익숙해지기전에는 혼동을 일으키기 쉽습니다.

2. assoc 대신 set
리습코드를 많이 보면 리스트에서 특정 키값으로 찾는 assoc이 있습니다. 이런 방식 대신 clojure에서는 set이라는 데이터구조를 직접다루게 합니다. 그러다보니 구현상에서 ((..) (..) .. ) 식으로 구현했던 많은 부분을 clojure에서는 { key val ... } 식으로 풀어쓰는 경우가 많게 됩니다. 대신 rassoc 를 대신할 만한 것을 찾기가 어렵습니다.

3. 데이터 값을 함부로 바꾸기 어렵게 되었습니다.
기본적으로 clojure 함수는 java의 Runnable 인터페이스를 구현했고, 각 데이터는 이런 스레드상에서 변경이 된다고 보는 것 같습니다. 그렇기때문에 어느 정도 synchronized 같은 방법을 동원하는 것 같습니다.  dosync 같은 것을 사용해서 값을 변경할 수는 있습니다만.. 어떤 데이터 형인지에 따라서 그 값을 바꿀 수 있는 방법도 다릅니다. ref, atom, agent같은 개념을 사용해서 스레드에 안전한 데이터를 사용하도록 합니다.

4. 재귀가 그리 만만하지 않습니다.
기본적으로 재귀호출은 같습니다만 lazy evaluation이나 tail call optimization같은 것을 사용하려면 여러 면에서 신경써야합니다. 사실 Common Lisp은 tail call optimization이 그닥 많이 구현되지도 않았고, lazy evaluation같은 것은 기본 내용에 포함되지 않는 경우가 많았는데.. clojure는 lazy evalution을 가급적 잘 활용하도록 강조하고 있고, tail call optimization을 지원하기위해 recur나 trampoline 같은 독특한 구조도 지원합니다. (사실 JVM이 tail call optimization을 지원안하는게 가장 큰 이유겠지요)

이런 식입니다. 앞으로 조금씩 더 파나가다보면 더 많은 것이 나오겠지요.. 어쩌면 어색했던 것이 더 편할지도 모르겠습니다.
아무튼 재미있는 Lisp구현임에는 틀림없는 것 같네요..

--
새로움을 느끼기에 삶은 즐겁다..
모험가 아돌 크리스틴을 꿈꾸며..
Sia..



Clojure 의외로 불편하다..

일단 예전에는 List 하나로만 확인했던 작업이 vector, seq, set 으로 나눠지다보니 상당히 혼란스럽다. =.=
특히나 append 같이 명령어가 바뀐 것은 정말 헤메기 딱좋다. (concat 으로 바뀌었다.)

cond, let의 문법 변화는 좋은지 나쁜지는 모르겠지만... 데이터/코드적 순결성에서는 안좋은 느낌.. 나름 vector 로 처리했다고 자부하는 것 같긴한데.. 글쎄??

PAIP 1장 시작이 어느 정도 진행되기는 하니까 계속 지켜볼 생각임..


2009. 11. 23.

Tomcat 웹어플리케이션의 구조

톰캣으로 개발을 진행하려할 때 가장 처음에 막히는 부분은 웹어플리케이션의 구조이다. 일반적으로 파일을 올려서 동작시키기만하면 되던 PHP와는 달리, 자바 서블릿&JSP에서는 웹어플리케이션이라는 하나의 단위로서 해당하는 파일들의 관리를 해줘야한다.

일반적으로 Tomcat에 웹어플리케이션을 개발할 때에는 서블릿 컨테이너의 SERVER_ROOT에서 생성시켜야한다. Tomcat이 /usr/local/apache-tomcat 에 설치되어있다면 SERVER_ROOT는 /usr/local/apache-tomcat/webapps 가 된다.

해당하는 루트에 웹어플리케이션을 개발하자. 이름을 firstapp 이라고 한다면 다음과 같은 디렉토리를 가져야한다.
  • /firstapp : 웹어플리케이션의 루트 디렉토리. JSP나 HTML을 보관한다.
  • /firstapp/WEB-INF : 웹어플리케이션 루트에 포함되지않을 모든 애플리케이션 및 자원이 포함된다. 또한 배치지시자(DD)가 저장되는 곳이다.
  • /firstapp/WEB-INF/classes: 서블릿 및 기타 유틸리티 클래스를 넣어두는 곳
  • /firstapp/WEB-INF/lib: 의존하는 각종 자바 압축파일을 넣어둔다. 예를 들면 JDBC 드라이버등을 들 수 있다.