블로그 이미지
좋은느낌/원철
이것저것 필요한 것을 모아보렵니다.. 방문해 주셔서 감사합니다..

calendar

1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31

Notice

    2010. 9. 16. 11:15 개발/XML
    <xsd:complexType name="Dcd-1-Connection-Profile-Type">
       <sequence>
          <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="1"/>
       </sequence>
    </xsd:complexType>

    <xsd:any>는 포함하는 sequence나 choice 요소에 지정한 네임스페이스에 있는 모든 요소를 표시한다.
    namespace속성 뒤의 값이 "##any"인 경우 모든 네임스페이스 요소를 사용할 수 있다.
    "##other"인 경우에는 이 요소를 포함하는 부모요소(위의 예제에서는 <sequence>가 부모요소가 되겠다)를 제외한 모든 네임스페이스를 사용할수 있다. 그러니까 
    <sequnce> 
       <sequnece>
    이런식으로만 사용하지 말라는 의미가 되는것이다.
    "##local"은 네임스페이스로 정규화되지 않은 요소를 사용할 수 있다.(이건 잘 모르겠네)
    "##targetNamespace"는 이 요소를 포함하는 부모요소의 대상 네임스페이스에 있는 요소를 사용할 수 있다.

    ProcessContents는 응용 프로그램이나 XML프로세서가 any 요소에 의해 지정된 요소에 대해 XML문서의 유효성 검사를 처리하는 방법을 표시한다. 기본값은 strict이다.
    strict(엄격한)는 XML프로세서에서 필요한 네임스페이스의 스키마를 가져와서 해당 네임스페이스에 있는 요든 요소의 유효성을 검사해야 한다.
    lax(관대한)은 네임스페이스를 가져와서 해당 네임스페이스의 모든 요소의 유효성을 검사하되 스키마를 가져오지 못해도 오류가 발생하지는 않는다.
    skip(넘어가기)는 네임스페이스에 있는 요소의 유효성을 검사하지 않는다.

    minOccurs는 해당 태그의 최소 출현 횟수를 나타내고
    maxOccurs는 이 태그의 최대 출현 횟수를 의미한다.
    minOccurs=0 maxOccurs=1 이면 option의 의미로 있거나 없다는 것이고,
    minOccurs=0 만 있으면 maxOccurs는 기본으로 1값이 주어진다.
    maxCoours=unbound 이면 이 태그의 max값은 무한으로 적용해도 된다는 것을 의미한다.
    posted by 좋은느낌/원철
    2009. 12. 16. 20:38 개발/컴퓨터/일반

    인터넷의 등장은 인류문명을 그 어느 때보다 풍요롭게 만들었다. 과거에는 특권층만이 지식을 독점적으로 향유했으나, 이제는 누구라도 마음만 먹으면 웹에 접속해 필요로 하는 정보를 손쉽게 얻을 수 있게 됐다. 또 굳이 다리품을 팔지 않고도 온라인상에서 자신이 원하는 상품을 구매할 수도 있다. 트위터에 접속하면 전세계인들이 지금 현재 무엇에 관심이 있는지를 실시간으로 확인하는 것도 가능하다.
    인터넷이 처음으로 인류에게 모습을 드러냈을때 오늘날처럼 화려하게 꽃을 피우리라고는 상상도 하지 못했을 것이다. 이처럼 인터넷이 화려하게 꽃을 피우게 된 것은 웹을 보다 풍요롭게 만든 IT기술이 있었기때문에 가능했다. 소셜미디어 전문 정보사이트인 `마셔블`은 지난 20여년 동안 인터넷을 풍요롭게 만든 혁신적 IT기술 10가지를 선정했다. 그 내용을 간단히 소개한다.


    (1)웹브라우저

    웹브라우저의 등장은 인터넷의 역사에서 가장 중요한 부분이다. 웹브라우저가 없었다면 우리들이 매일 접속하는 인터넷은 보다 지루하고 회색빛에 가까웠을 것이다. 웹으로 정보를 쉽게 검색할 수 있는 웹브라우저는 지난 1991년 세상에 처음으로 나왔다. CERN에 근무하던 팀 버너스-리가 처음으로 월드와이드웹을 `넥스트스텝`이라는 플랫폼상에서 운영했다. 나중에 월드와이드웹은 ‘넥서스’라는 이름으로 명명되었다.1993년 ‘모자이크’라는 브라우저가 나오면서 웹브라우저가 일반에 빠른 속도로 확산되기 시작했으며 이어 94년에는 `넷스케이프 네비게이터`가 나왔다. 95년에는 MS의 `인터넷 익스플로러`가 등장,90년대의 웹브라우전 전쟁을 촉발시켰다.
    최근 웹브라우저 시장은 또 다른 전쟁의 소용돌이 속에 있다.MS의 `인터넷 익스플로러`, 그리고 MS의 `인터넷 익스플로러` 시장을 잠식하고 있는 모질라의 `파이어 폭스`, 애플의 `사파리`, 최근에 브로우저 시장에 진출한 구글의 `크롬` 등이 치열한 4파전을 벌이고 있는 양상이다. 만일 이런 웹브라우저들이 없었다면 우리들의 인터넷 라이프는 지금 보다 훨씬 삭막해졌을 것이다.

    (2)검색엔진
    검색엔진이 없었다면 웹을 검색하고 인터넷 공간에서 상호작용하는 데 문제가 많았을 것이다. 대부분 사람들은 `Archie` `베로니카` `주그 헤드`와 같은 초창기 검색엔진을 기억하지 못할 것이다. 90년대 중반에 들어서야 `웹크롤러`,`인포시크`,`라이코스`,`알타비스타`,`마젤란`,`야후`,`익사이트`,`잉크토미`,`애스크 지브스` 등 귀에 익은 검색엔진들이 등장해 초창기 웹사용자들의 정보 검색을 수월하게 만들어주었다. 검색엔진의 황제 구글이 모습을 드러낸 것은 지난 98년.구글 검색엔진은 다른 어떤 엔진보다 많은 웹정보를 찾아보기 편하도록 인덱싱하고 배열했다.구글이 다른 검색엔진 보다 특별한 점은 검색결과를 상품화하고,웹검색이 막대한 부를 창출할 수 있는 사업이라는 점을 각인시켰다는 데 있다. 현재 검색엔진시장은 구글,야후,MS의 빙이 치열하게 경합중이다.


    (3)VOIP
    VoIP는 IP네트워크(인터넷)를 통해 음성을 전송하는 기술이다. 사실 VoIP는 새로운 기술은 아니었다. 이미 지난 70년대에 IEEE에서 발표된 논문에 VoIP에 관한 기본적인 아이디어들이 소개되었다. VoIP가 주류 테크놀로지로 부상한 것은 순전히 `스카이프` 덕분이다. 스카이프는 5억2천만 사용자들이 공짜로 또는 저렴하게 인터넷 전화를 할 수 있도록 했다. 또한 호(呼)대기,화상전화,콜러ID(발신자번호표기)등 고가의 전화서비스가 아주 저렴한 가격에 제공되었다.


    (4)RSS
    RSS(Really Simple Syndication)는 웹콘텐츠를 소비하는 방식을 획기적으로 변화시켰다. RSS는 새로운 블로그 포스팅이나 뉴스 등 웹업데이트 정보를 푸쉬하는 기술이다. RSS피드 리더기를 통해 수시로 업데이트되는 웹정보를 읽을 수 있다. RSS의 도입으로 네티즌들은 엄청난 양의 정보 가운데 자신이 필요한 정보를 요청해 받아볼수 있게 됐다. 한발 더 나아가 RSS는 뉴스 커버리지에 큰 변화를 가져왔다. `Regator.com`이나 `Techmeme.com`과 같은 인터넷사이트들은 RSS피드 기술을 도입해 우리가 뉴스를 찾고 소비하는 방식을 바꾸었다.
    (5)실시간 스트림
    ‘실시간’ 개념은 2009년 최대 화두 중 하나다.`실시간` 기반의 기술은 우리가 다른 사람과 정보를 공유하는 방식에 근본적인 변화를 가져왔다. 이른바 `패러다임 쉬프트`다. 트위터,페이스북 등 실시간 기반의 플랫폼은 다른 사람과 의견을 교환하는 유용한 도구로 자리잡았다. 실시간 플랫폼의 등장은 우리가 정보를 검색하는 방법에도 변화를 가져왔다. 콘텐츠를 별견하는 방식이 기존의 `검색` 중심에서 `실시간` 기반의 상호작용으로 바뀌었다. 급기야 검색엔진들은 기존의 검색결과에 `실시간` 정보를 통합해 제공하기 시작했다. `실시간` 검색은 기계적인 알고리즘에 기반을 둔 기존의 검색과 소셜미디어나 블로그들에 의해 수시로 생성되는 정보가 한쌍을 이루도록 했다. 실시간 스트림은 우리가 다른 사람과 커뮤니케이션하고 뉴스를 퍼뜨리는 방식을 더욱더 고도화하고 있다.


    (6)P2P
    `Peer-to-Peer(P2P)` 테크놀로지는 중앙노드 없이 컴퓨터와 컴퓨터간에 데이터를 전파하는 분산 네트워크 아키텍처다. 지난 99년에 탄생한 MP3 파일 교환 사이트인 냅스터`의 등장으로 P2P는 주류 기술로 떠올랐다. 비록 음반회사들에 의해 소송을 당하기도 했지만 냅스터는 음악의 배포방식을 바꿨다. 이런 배포방식은 나중에 영화 등 다른 콘텐츠에까지 확산되기에 이르렀다. 또한 P2P 기술은 `아이튠스` 같은 서비스들이 성장하는 토대를 만들었다. 오늘날 P2P 트래픽은 지역에 따라 다르지만 인터넷 트래픽의 25~55%를 차지한다. `비트 토런트`와 같은 P2P프로토콜은 음악과 영화의 배포방식에서부터 네트워크 아키텍처,관련 법률에 이르기까지 총체적인 영향을 미치고 있다.


    (7)AJAX
    AJAX는 `Asynchronous JavaScript`와 `XML`을 지칭하는 용어다. 웹 애플리케이션이 특정 페이지를 재로딩하지 않고도 새로운 정보를 서버에 요청할 수 있도록 해준다. AJAX는 웹의 새로운 세대를 열었으며, 개발자들이 웹에서도 데스크톱과 같은 환경을 구현할 수 있도록 했다.
    AJAX는 `구글 닥스`,`Meebo`,`구글 맵스`,`피크닉` 등 애플리케이션을 가능하도록 했다. 이들 웹애플리케이션들은 웹페이지 정보를 업데이트하기 위해 AJAX 기술을 사용한다. 새로운 메시지,지도,텍스트 등을 굳이 재로딩하지않고도 바로 업데이트할 수 있다.


    (8)Software as SERVICE(SAAS)
    `SaaS`의 기원은 90년대로 거슬러 올라간다. 하지만 풍부한 AJAX 인터넷 애플리케이션 덕분에 최근 몇년새 빠른 속도로 SaaS가 확산되고 있다. SaaS의 기본 개념은 `온디맨드` 방식으로 웹을 통해 소프트웨어를 제공하는 것이다. 데이터는 외부의 ‘클라우드’에 저장한다. 사용자 데이터가 사용자 컴퓨터가 아니라 컴퓨팅 인프라스트럭처(클라우드)에 저장되는 것이다. SaaS 애플리케이션의 장점은 컴퓨터가 웹에 접속만 되면 소프트웨어 접근이 가능하다는 점이다. 자신의 컴퓨터가 아니라 다른 곳에 중요한 정보를 보관한다는 게 다소 불안할 수도 있지만 SaaS와 클라우드 컴퓨팅은 소비자와 기업 사용자 모두에게 매력적으로 다가오고 있다.


    (9)e커머스
    월드와이드웹이 처음 등장했을 때 누가 e커머스를 상상이나 했겠는가. e커머스의 역사는 지난 95년 시작됐다. 아마존닷컴과 이베이가 혜성처럼 나타나 e커머스를 주도했다. 이제 온라인상에서 제품을 구매하는게 자연스러운 일이 됐다. e커머스 특히 빛을 발한 분야중 하나가 여행업계다. 항공사,호텔,자동차 렌탈 예약 등이 온라인을 통해 일사천리로 이뤄진다.가격비교도 가능하다.
    온라인 예약시스템과 가격비교는 예약프로세스를 단순화했다.중간 매개자나 대행사 없이도 마우스 클릭만으로 항공기 호텔 예약 등이 가능해졌다.


    (10)와이 파이(Wi-Fi)
    Wi-Fi는 랩톱과 웹에 접속된 디바이스를 보다 유용한 단말기로 만들었다. Wi-Fi 접속점만 있으면 어디에서든지 인터넷에 접속할 수 있게 됐다. 인터넷에 접속하기 위해 모뎀을 연결하던 시절에는 전혀 상상도 할수 없는 일이 벌어지고 있는 것이다. 도시에 광범위하게 설치된 Wi-Fi무선 네트워크와 `와이맥스` `셀룰러 네트워크`덕분에 이제는 웹에 접속하기 위해 굳이 선을 연결할 필요가 없다.
    이상 언급한 10대 웹기술이 있었기때문에 우리의 인터넷 라이프는 훨씬 풍요로워지고 점점 우리를 웹의 세계로 빠져들게 만든다. 하지만 앞으로 또 어떤 혁신적인 기술이 등장해 우리의 삶을 바꿔놓을지 쉽사리 예측하기는 힘들다. 다만 분명한 것은 기술은 끊임없이 진화하고 있다는 점이다.
    전자신문인터넷 장길수기자 ksjang@etnews.co.kr

    posted by 좋은느낌/원철
    2009. 11. 12. 20:59 개발/Oracle
    1. . SQL에 XML 문자(<, > 같은)가 들어가는 경우 해결책은?
    2. . SQL이 너무 많아 statement의 id 만으로는 구분이 어렵다면?
    3. . 실제 수행되는 쿼리 정보를 콘솔 및 로그에 찍고 싶은데?
    4. . one-to-many 관계 구성중에 복합키를 넘겨야 할때

    1. SQL에 XML 문자(<, > 같은)가 들어가는 경우 해결책은?

    >> 두가지 방법이 있다. (1) XML의 CDATA 섹션 사용하거나

       <statement id="getPersonsByAge" resultClass="examples.domain.Person">
       <![CDATA[
          SELECT *
          FROM PERSON
          WHERE AGE > #value#
        ]]>
       </statement>

    (2) XML문자를 특수 엔터티 문자로 변환(AnyEdit 플러그인 사용하면 편함)

       <statement id="getPersonsByAge" resultClass="examples.domain.Person">
          SELECT *
          FROM PERSON
          WHERE AGE &gt; #value#
       </statement>

    2. SQL이 너무 많아 statement의 id 만으로는 구분이 어렵다면?

    >> iBatis는 namespace 개념을 지원한다. sql-map-config.xml 에서 useStatementNamespaces 값을 true로 준다. 이제 SQL 정의 xml 파일을 여러개로 나누고 각 파일별로 적당한 namespace를 지정한다.

    • sql-map-config.xml
      <sqlMapConfig xmlns:fo="http://www.w3.org/1999/XSL/Format">
        <settings 
          cacheModelsEnabled="true" 
          enhancementEnabled="true" 
          useStatementNamespaces="true" 
          lazyLoadingEnabled="true" 
          maxRequests="512" 
          maxSessions="128" 
          maxTransactions="32" />
    • SQL 파일에서 이렇게.
    <sqlMap namespace="Sample">

      <select id="getPersonsByAge" ...>
    • DAO 코딩 예("namespace.statement_id" 형식)

    return getSqlMapClientTemplate().queryForList("Sample.getPersonsByAge", "30");

    3. 실제 수행되는 쿼리 정보를 콘솔 및 로그에 찍고 싶은데?

    >> log4j.properties 파일에 아래처럼 설정한다.

    (log4j.logger.java.sql.Connection=DEBUG 는 반드시 있어야한다.) 

    <pre> log4j.logger.java.sql.Connection=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG log4j.logger.java.sql.ResultSet=DEBUG </pre> 아래 처럼 찍힌다. <pre> <DEBUG> sql.Connection : {conn-100003} Connection <DEBUG> sql.PreparedStatement : {pstm-100004} PreparedStatement: select user_id, password, name, user_type, user_group, regist_date, status from ws_user where user_id = ? <DEBUG> sql.PreparedStatement : {pstm-100004} Parameters: test1 <DEBUG> sql.PreparedStatement : {pstm-100004} Types: java.lang.String <DEBUG> sql.ResultSet : {rset-100005} ResultSet <DEBUG> sql.ResultSet : {rset-100005} Header: user_id, password, name, user_type, user_group, regist_date, status <DEBUG> sql.ResultSet : {rset-100005} Result: test1, test1, 테스트유저, U, 01, 20041204, A </pre> 4. one-to-many 관계 구성중에 복합키를 넘겨야 할때

    예를 들면 다음처럼 1:M관계를 연결하는 부분이 있다.

    <result property="comments" column="id" select="getCommentList" /> 
    이는 조회된 결과의 id값을 getCommentList에 인자로 넘기는 것이다. 이는 getCommentList에서 수행되는 SQL문의 조건문이 한개일때는 가능하나 2개 이상일때는 다소 적용에 무리가 있다. 즉 2개 이상의 키값을 넘겨야 할 경우에는 다음처럼 설정하면 된다.

    <result property="comments" column="{id=id,user.id=user_id}" select="getCommentList" />

    여기서 {id=id,user.id=user_id} 값은

    {넘겨받는 객체의 변수명=칼럼명,넘겨받는 객체의 변수명=칼럼명}

    의 형식을 취하면 된다. 즉 , (comma)를 구분자로 사용하면 된다. 그럼 다음처럼 사용이 가능하다.

    <statement id="getCommentList" parameterClass="comment" resultMap="get-comment-result">
        select 

            .... 

        from comment
        where seq=#id#
        and user_id=#user.id#
    </statement>
    posted by 좋은느낌/원철
    2009. 11. 5. 00:19 개발/컴퓨터/일반
    posted by 좋은느낌/원철
    2009. 11. 3. 10:48 개발/컴퓨터/일반
    원문 : http://www.bloter.net/wp-content/bloter_html/2009/11/2/18604.html

    ms_media_center

    이르면 내년부터 마이크로소프트 윈도우7 이용자들은 PC에서 지상파나 홈쇼핑 방송을 곧바로 볼 수 있게 될 전망이다.

    한국마이크로소프트(이하 한국MS)는 11월2일 삼성동 그랜드 인터콘티넨털 호텔에서 CJ오쇼핑, EBS, iMBC, 중앙일보 등 4개 미디어 회사와 윈도우7 미디어센터를 통한 컨텐트 서비스 양해각서를 맺었다.

    제휴 뼈대는 윈도우 미디어센터 플랫폼을 활용해 다양한 미디어 컨텐트를 윈도우7 이용자들에게 공급하겠다는 것이다. 윈도우 미디어센터는 PC에 저장된 동영상이나 음악, 사진 등을 쉽고 편리하게 즐기고 공유할 수 있게 해주는 작은 미디어 플랫폼이다. 윈도우7 홈프리미엄·프로페셔널·얼티미트 등 대부분 윈도우7 버전에 내장돼 있다.

    컨텐트가 저장된 PC에서만 감상하는 데 그치지 않는다. 윈도우 미디어센터를 활용하면 다른 윈도우7 PC나 윈도우 모바일과 연동해 컨텐트를 손쉽게 공유할 수 있다. 예컨대 집 PC에서 윈도우 라이브 ID로 로그인한 뒤 외부 PC에서 다시 윈도우 라이브 ID로 접속하면, 두 PC끼리 컨텐트를 손쉽게 공유하거나 교환하는 식이다. 집에서 스포츠 방송을 녹화해 저장해뒀다 외부 출장지에서 라이브ID로 로그인해 집 PC에 저장된 스포츠 방송을 시청하는 일도 가능하다. 윈도우 모바일 기반 스마트폰에서 불러들여 감상할 수도 있다.

    이번 제휴로 윈도우7 이용자들은 2010년부터는 이들 4개 미디어사가 제공하는 동영상 컨텐트를 별도의 장치 없이도 주문형 비디오 방식 등으로 즐길 수 있게 된다. iMBC의 고화질 스포츠 방송이나 게임 동영상, EBS의 다큐멘터리나 교육용 방송, CJ홈쇼핑의 쇼핑 방송과 중앙일보의 종합 방송 프로그램을 윈도우 미디어센터가 장착된 PC에서 손쉽게 즐길 수 있게 된 것이다. 지금까지는 이들 방송을 보려면 해당 웹사이트를 일일이 방문해 인터넷 방송을 보거나 PC용 TV 수신카드를 따로 달아야 했다.

    이날 양해각서 체결식에는 MS 스티브 발머 CEO를 비롯해 한국MS 김 제임스 우 사장, CJ오쇼핑 이해선 대표, EBS 곽덕훈 대표, iMBC 홍은주 대표, 중앙일보 김수길 부발행인 등이 참석했다.스티브 발머 MS CEO는 “이번 제휴는 마이크로소프트가 미디어센터 기반으로 전세계 컨텐트 파트너와 맺은 첫 번째 제휴라는 점에서 기대가 크다”며 “인터넷 컨텐트 미디어 분야에서 새로운 미래를 여는 선구자 입장인 한국에서 제휴를 맺게 돼 기쁘다”고 소감을 밝혔다.

    또한 “윈도우7은 이용자들이 원하는 속도로, 원하는 배터리 수명으로, 신뢰성 높은 방식으로 이용하게 해주는 새 방식이자 SW 에코시스템에서도 혁신이 가능해지는 플랫폼”이라며 “이번 제휴가 컨텐트 업계엔 새 비즈니스 가능성을 열어주는 동시에, 앞으로 미디어센터가 장착된 PC에서 새로운 컨텐트가 더 많이 나올 것으로 기대한다”고 덧붙였다.

     파이핑하기   ShareThis
    posted by 좋은느낌/원철
    2009. 10. 29. 18:09 개발/FLEX
    원문 : http://www.adoberia.co.kr/iwt/blog/blog.php?tn=flex&id=348


    “새로운 걸 원해? 집에서 QOOK해!”
    이 광고 카피는 누구나 한번쯤 들어보았을 것이다. 나는 요즘 한창 광고를 하고 있는 QOOK의 개발을 담당하고 있다. QOOK은 인터넷, TV, 집 전화, 인터넷 전화의 4개 분야로 구분되는데, 그 중 QOOK 집 전화 개발에서 PM을 맡고 있다.
    현재 Java 기반 Web Application 개발자로써, 웹 프로젝트, 이벤트 개발 및 프로젝트 관리를 수행하는 업무에서 개발 못지 않게 중요한 것이 개발 산출물의 관리, 프로젝트 참여 인력들과의 커뮤니케이션이다.
    기획 단계부터 개발까지의 프로젝트 전체 공정에서 개발자는 기획에 대한 의견을 제시하고, 특정 서비스에 대해 기술적으로 검토해야 하며, 프로젝트 일정을 관리해야 한다. 또한 프로토타입의 개발, 기술문서 작성 등 전반에 걸쳐 관여해야 하며 이 과정에서 오고 가는 검토 문서, 업무 협의, 일정 조율 부분을 모두 소화하자면 하루 24시간도 너무나도 부족하다. 그래서 ‘개발자’하면 ‘야근’을 떠올리게 된다.
    여기에 업무 특성상 메신저로 날아오는 업무 요청 쪽지와 쪽지에 첨부된 오피스 문서를 읽고 처리하는 일, Application 개발 업무, 개발 부분에 문제가 없는지 확인하는 등 수많은 로그 페이지가 더해져 PC는 한 대로는 업무 처리가 안 될 정도였다.

    Acrobat 9와의 첫 만남, “협업의 새로운 세상”
    이 문제의 해결책으로 PC 2대를 놓고 한 대는 개발용으로, 다른 한 대는 산출물 관리 업무를 위해 문서 및 쪽지 처리용으로 나누어 사용한지도 벌써 5년이 넘었다. 그런데 문제는 PC간(심지어는 내가 쓰는 PC에서도), 그리고 업무 관련자들간의 문서 공유였다.
    이를 해결하고자 처음에는 오피스로 작성된 문서를 일일이 프린트해서 연필로 메모를 해 전달하거나 문서를 다시 PDF로 변환하여 오피스 프로그램이 없는 개발자들에게 배포하는 방법 등 원활한 공유를 위해 온갖 수단과 방법을 동원했지만 그다지 나아지는 기색이 없었다. 더욱이 번거롭게 이중 작업을 해야 해서 처리할 일은 오히려 늘어났다. 그러던 중 지인의 추천을 통해 Acrobat 9를 접하게 되었고, 그 중 특히 Acrobat 9를 통한 상대방과의 업무 협업(Collaboration) 기능에 매력을 느끼기 시작했다.

    개발 문서의 업무 프로세스 개선이 시급
    ‘개발자들은 개발만 하고 문서를 생산하지 않는다’는 것은 정말 거짓말이다. 기획자나 마케터가 작성하는 것만큼, 혹은 그 이상으로 많은 양의 회의자료, 기획 검토자료, 설계자료, 프레젠테이션 자료를 만든다. 또한 이렇게 생산된 문서들을 항상 최신 버전으로 유지하는 것 역시 개발자가 시간을 소비하는 요인 중 하나다.
    개인적으로 이 부분의 업무 프로세스를 개선하는 일이 시급했다. 그래서 사용법이 익숙하지는 않지만 만들어진 문서를 PDF로 변환하고, 최신 버전의 문서 관리를 위해 업무 관련자들과 협업하는 기능을 사용해 보기 시작했다. 이를 통해, 최소한 문서 출력물이 줄거나 같은 문서를 다른 버전으로 몇 번씩 변환하는 수고를 덜고, 크게는 어떤 운영체제(매킨토시, 윈도우, 리눅스)가 설치되어 있든 설계문서를 한번만 만들어서 배포하면 별다른 수고 없이 모두들 볼 수 있을 환경을 기대하면서 말이다.
    내 몸에 익숙하지 않다 보니 Acrobat 9를 설치한 후 사용하는데 있어 처음 며칠 동안은 불편함도 느껴졌다. 매번 PDF만 변환하고 Adobe Reader에서 PDF 문서 읽는 정도였다가, 새로운 기능을 배우는데 있어 당연한 과정이라 생각이라 생각했다. Acrobat 9을 추천해준 지인을 정말 많이 괴롭혔다.

    파일 관리의 번거로움을 단번에 해결한 ‘문서 공유(Share Documents)’
    결과는 놀라웠다. 프로젝트를 수행하는 과정에서 수많은 문서가 오가고, 의견을 기다리며 수정되는데, 이 과정이 개선되었다.
    한 가지 예를 들면, 서비스 기획자는 100장이 넘는 파워포인트 문서를 내게 건네며 기획의도를 설명한 후 전반적인 기술 검토를 요청한다. 기술적으로 무리가 있는 부분이 있는지, 일반적인 흐름을 벗어나게 기획된 부분은 없는지를 확인하기 위해 Acrobat에서 해당 파워포인트 파일을 연다. 자동으로 PDF 문서로 변환되는 것은 물론이다.
    예전 같으면 100장이 넘는 문서를 하나하나 프린트해 거기에 빨간 볼펜으로 메모를 하거나 오피스 프로그램을 열어 텍스트 상자를 하나씩 집어 넣어 정성스레 주석을 달았겠지만 이제는 그럴 필요가 없다. PDF로 자동 변환된 문서를 Acrobat.com에 ‘문서 공유(Share Documents)’ 기능을 이용해 이 문서를 함께 검토해야 할 사람들의 메일 주소만 입력하는 것만으로 문서 공유가 이루어진다.
    해당 메일을 수신한 사람들은 메일 내의 링크를 클릭하여 공유 문서를 다운로드 받고, 페이지 별로 자신의 의견을 입력한 뒤 ‘Publish’를 클릭하면 실시간으로 의견을 정리할 수 있다. 동시에 작업을 진행할 수 있으니 문서가 오가는 시간이 확연히 줄어든 셈이고, 파일의 버전까지 관리가 되니 의견을 첨부할 때마다 파일 이름 뒤에 ‘_날짜’를 다는 번거로움까지 없어진 셈이다.



    <그림 1> Acrobat.com을 통해 문서를 공유할 사람의 메일 주소를 입력해 발송하면, 그림(위)과 같은 메일이 도착하고, 해당 링크를 클릭하면 공유할 문서(아래)를 확인할 수 있다. 이후 문서 내에서 피드백 할 내용을 주석을 사용해 달고 ‘Publish’를 클릭하면 메일을 보내온 사람에게 자동으로 전달이 된다.

    빠른 의견 검토와 검수를 가능하게 하는 ‘주석’
    기획서 검토와 대략적인 설계가 끝나면 스토리보드가 완성되고 개발자들은 이 스토리 보드를 토대로 실제 개발을 진행하게 된다. 그런데 프로젝트 규모가 커지면 하나의 프로젝트 룸에 모든 개발자들이 다 모여서 일하지 못하는 상황이 자주 발생한다. 이런 경우 전화나 메신저의 쪽지 기능, 메일을 통해 많은 업무를 진행한다. 하지만 적지 않은 누수가 발행하고 시간 소요도 많은데, Acrobat의 실시간 협업을 써 보니 쪽지나 메신저와는 비교할 수 없을 정도로 최적의 협업이 가능했다.
    Acrobat은 주석으로 파일을 첨부할 수 있는 기능이 있는데, 개발자에게는 활용도가 아주 높았다. 프로젝트를 진행하면서 개발자들이 특정 기능을 어떤 방식으로 개발해야 할지 고민할 때, 또 PM에게 도움을 받고자 할 때 PM은 테스트 코드를 만든다. 그리고 이 테스트 코드를 이미지 혹은 원본 파일 그대로 Acrobat에 첨부하기만 하면 개발자가 어떤 다른 공간에 있더라도 바로 확인하고 적용할 수 있었다. 게다가 해당 개발자뿐만 아니라 다른 관련자들도 확인할 수 있으니 동료 검토나 검수 관점에서 이보다 빠르게 진행되는 방식이 또 어디에 있을까 싶다.


    <그림 2> 주석의 파일 첨부 기능
    주석에서는 텍스트 수정뿐 아니라 연관된 파일까지도 첨부가 가능해 직관적인 피드백 전달을 할 수 있다.

    개발자에게 추천하는 기능 ‘내 스크린 공유’
    마지막으로 ‘내 스크린 공유(Share My Screen)’ 기능은 개인적으로 Acrobat의 가장 강력한 협업 기능 중 하나로 생각되는데, 이 기능은 개발자들을 위한 기능이라는 착각마저 들 정도였다. 빠른 공유와 의사결정이 필요할 때, 즉 원격회의를 해야 하거나 동시에 자료를 보여주고 바로 의견을 들어야 할 경우 아주 유용하다.
    PM이 자신의 PC 스크린을 공유하게 되면 초대받은 개발자들은 브라우저에서 URL을 입력하고 들어오는 것만으로 PM의 PC 화면을 볼 수 있다. 관리자는 음성/영상/화면/채팅을 통해 신속하게 내용을 설명하게 되고, 연결된 개발자들은 설명에 대한 피드백을 채팅창을 통해서 실시간으로 바로 전달할 수 있다. 이것은 웹 개발자로서 정말 감탄한 기능이다.


    <그림 3> 애크로뱃을 통해 내 스크린 공유 기능을 사용할 수 있다. 내 화면을 지정된 사용자와 함께 공유하면서 업무를 진행할 수 있어 거리가 떨어진 사용자와의 업무 협업시 유용한 기능이다.

    “Acrobat 업무에 집중할 수 있도록 돕는 도구다”
    개발자는 일과 중 많은 시간을 업무 협의에 소비한다. 개발자마다 다르겠지만 집중해야 하는 업무 중에는 사람과의 대화 등 주변이 산만해지는 행동 자체를 하지 않으려 한다. 화장실을 다녀오는 것만으로도 집중이 흐트러질 수 있고, 다시 집중하기 위해서는 많은 노력과 시간이 필요하기
    때문이다.
    이런 개발자들이 회의실에서 업무 협의를 2~3번쯤 하고 나면 그날은 집중이 필요한 개발 업무와는 안녕일 수밖에 없다. 그래서 개발자도, PM도 프로젝트 수행 중에는 가급적 업무 협의에 많은 시간을 들이거나 자주 움직이는 것을 꺼리는 경향이 있는데, 이런 측면에서 Acrobat은 개발자들이 핵심 업무에 집중할 수 있는 계기를 제공해 주었다. Acrobat을 활용함으로써 문서가 오가는 시간이 최소화되어 좀더 개발에 집중할 수 있는 여유가 생겼으며, 협업 기능을 통해 굳이 얼굴을 맞대고 회의실에서 업무 협의를 해야 할 일이 줄어들었다. 그리고 빠른 검토가 가능해져 개발자들 간 의사소통이 좀 더 원활해졌다.
    처음에는 협업이라는 강한 매력에 끌려 Acrobat을 접했고, 지금은 협업 간에 사용되는 문서의 보안 및 양식 배포, Acrobat을 이용한 문서 작성 기능을 찬찬히 훑어보면서 개발자에게 필요한 부분은 무엇인지를 확인해 가고 있다. 아직까지 능숙하지는 않지만 웹 페이지 변환 기능은 화면 디버깅이나 화면 검증시 활용한 만한 아주 유용한 기능이다. Acrobat이야 말로 개발자들의 협업을 위한 대표적인 소프트웨어가 아닐까 생각된다.
    마지막으로 한마디 덧붙이자면 “새로운 걸 원해? 사무실에서 Acrobat 해!”

    posted by 좋은느낌/원철
    2009. 9. 30. 17:25 개발/Java

    객체

     

    메인이 인스턴스를 생성하기 전에는 
    클래스는 다만 
    코드에 지나지 않았다

     

    메인이 인스턴스를 생성했을 때 
    클래스는 메모리에 올라가서 
    객체가 되었다  

     

    메인이 인스턴스를 생성한 것처럼
    클래스의 이 변수와 메소드에 알맞는 
    누가 인스턴스를 생성해다오 
    메모리에 올라가서 
    객체가 되고 싶다

     

    클래스는 모두 
    객체가 되고 싶다 
    클래스는 컴퓨터에 컴퓨터는 클래스에 
    지워지지 않는 
    하나의 프로그램이 되고 싶다

     

     

    ==========================================

    김춘수 님의 꽃을 패러디해보았습니다..

    한 번 웃어 보아요~~

    posted by 좋은느낌/원철
    2009. 8. 28. 11:36 개발/JavaScript
    출처 : http://kwon37xi.egloos.com/2558053

    * A Simpler Ajax Path가 Ajax 입문에 좋은 글.

    Ajax의 개발 순서

    1. XMLHttpRequest 객체 생성
    2. HTTP 요청을 발생시킴(open(), send())
    3. 서버측에서 XMLHttpRequest를 통해 보낸 요청을 받아서 파라미터를 분석하고, 작업을 한 뒤에 결과를 XML이나 문자열로 리턴한다.
    4. XMLHttpRequest로 서버가 리턴한 데이터를 받아서 처리(onreadystatechange, responseText, responseXML)

    XMLHttpRequest에 의한 송수신 상세 예

    JavaScript에서 XMLHttpRequest Object 생성하기

    // XMLHttpRequest 오브젝트 생성 함수
    // @sample oj = createHttpRequest();
    // @return XMLHttpRequest 오브젝트
    function createHttpRequest()
    {
        if (window.ActiveXObject) {
            try {
                // IE6
                return new ActiveXObject("Msxml2.XMLHTTP");
            } catch (e) {
                try {
                    // IE4, IE5
                    return new ActiveXObject("Microsoft.XMLHTTP");
                } catch (e2) {
                    return null;
                }
            }
        } else if (window.XMLHttpRequest) {
            // Mozilla, FireFox, Opera, Safari, Konqueror3
            return new XMLHttpRequest();
        } else {
            return null;
        }
    }


    HTTP 요청 발생

     1. open() 메소드 실행 (POST/GET, 요청URL, 동기/비동기지정)
    var request = createHttpRequest();
    request.open("GET", "/test.xml");
     
    // param 1 : GET/POST
    // param 2 : URL
    // param 3 : 생략가능. 동기/비동기 여부. 기본 비동기.

     2. send() 메소드(데이터 송신)
     request.send(""); // 데이터 없이 전송할때 혹은
     request.send(null); // Konqueror에서는 오류 발생함. Konqueror를 제외하고 데이터 없이 전송할 때 사용가능

    위 a,b가 기본적인 모양새이지만, 실제로 GET과 POST 방식에 따라 차이가 많이난다.

      * GET 방식 : GET 방식은 URL에 파라미터를 직접 붙여 보내지만, 한글 등의 문제로 인코딩이 필요하고, RequestHeader 설정도 필요하다. 일반적으로 다음과 같은 모양이 된다.
    var paramName = encodeURIComponent("파라미터명"); // 파라미터이름을 UTF-8로 인코딩
    var paramValue = encodedURIComponent("파라미터값"); // 파라미터 값을 UTF-8로 인코딩

    // 파라미터 구분에 사용되는 ?와 &는 인코딩 되면 안된다. 그래서 따로 붙인다.
    var fullParameter = '?' + paramName + '=' + paramValue; // URL에 사용할 파라미터 구성

    request.open("GET", "/test.cgi" + data);

    // setRequestHeader()는 open()보다 이후에 나와야만 한다.
    // 아래는 파라미터 값을 UTF-8로 인코딩해서 보내겠다는 의미.
    // GET방식에서는 필요 없고, POST방식에서는 필수이다.
    request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');

    request.send(null);


      * POST 방식 : send() 메소드에 인수를 데이터로 넘긴다.
    request.open("POST", "/test.cgi");
    request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
    // POST 방식에서도 파라미터를 인코딩하여 send()메소드의 인자로 넘겨주면 된다.
    request.send("name=test&data=123");

    A Simpler Ajax Path에 보면 HTML폼에 입력된 값을 자동으로 파라미터 문자열로 변경해주는 메소드 예가 있다.

    착신과 데이터 처리

     * onreadystatechange 이벤트(송수신 상태 변할때 기동) - IE 이외 부라우저에서는 콜백 스타일의 onload 이벤트 사용가능
     * readyState 프라퍼티 (송수신 상태를 나타내는 값. "4"가 송신 완료) - onload의 경우에는 불필요
    onreadystatechange는 요청 처리 상태를 나타내는 readyState 프라퍼티의 값이 바뀔 때 발생한다.
     * 착신을 처리할 함수 지정은 request.open() 함수를 호출하기 전에 선언해야 정상 작동했다. 항상 요청을 보내기 전에 요청을 처리할 함수 지정을 해둔다.
    request.onreadystatechange = callbackFunction; // callbackFunction() 함수가 호출된다.

    function callbackFunction() {
        // readyState == 4는 착신 완료를 의미한다.
        if (request.readyState == 4) {
            // 착신시의 처리
        }
    }

    다른 방법으로, callback 함수를 인라인으로 정의하고, HTTP 상태 코드가 200일때만 작업하도록 할 수도 있다. 두가지를 한꺼번에 보면,
    request.onreadystatechange = funcation() {
        if (request.readyState == 4 &&
                request.status == 200) {
            // 착신시의 처리
        }
    }

    onreadystatechange 대신 onload를 사용할 수 있다. Opera 8은 버그때문에 onload만 사용한다. (IE를 제외한 다른 브라우저에서 다 된다) 
    request.onload = function() {
        // 착신시의 처리
    }

    onload와 onreadystatechange를 동시에 이용하기 위해서 다음과 같이한다.
    if (window.opera) {
        request.onload = function() { callback(request); }
    } else {
        request.onreadystatechange = function() {
            if (request.readyState == 4) {
                callback(request);
            }
        }
    }

    function callback(request) {
        // 실제 착신시의 처리를 구현하는 부분
    }

     * responseText 또는 responseXML (데이터를 텍스트 혹은 DOMDocument로 수신)
       * responseText : 텍스트로 받기
       * responseXml : XML로 받기
       * 여러줄의 CSV 텍스트를 받았을 때의 일반적 처리
    var res = request.responseText;
    var rows = res.split(" "); // 여러 줄을 한 줄씩 배열로 만든다.
    var cols = rows[0].split(","); // 첫번째 줄을 쉼표 단위로 분리하여 배열로 만든다.

       * JSON 처리
    eval("res = " + request.responseText)
    //... 기타 처리

       * XML 처리
    <?xml version="1.0"?>
    <lists>
      <name>Toshiro Takahashi</name>
      <msg>hello</msg>
    </lists>

    var res = request.responseXML;
    var msgs = res.getElementsByTagName("msg"); // DOM 객체 사용

    alert(msg[0].firstChild.nodeValue);


    서버측 스크립트

    XMLHttpRequest.send() 에 의해 요청을 받아 처리하게 되는 서버측 스크립트(JSP, Servlet, ASP, PHP 등)은 요청 파라미터를 분석하여 작업을 처리한 뒤에 결과를 Text나 XML로 리턴하면 된다. 
     * 리턴시 문자 인코딩은 기본적으로 UTF-8로 한다.
     * 텍스트로 리턴할 경우, Opera 8, Konqueror 3, Safari 등은 UTF-8을 인식하지 못한다. 서버는 응답 문자열을 UTF-8기준으로 URI 인코딩을 해서(Java의 경우 java.net.URLEncoder.encode() 메소드 사용) 리턴하고, 받는 측(웹 브라우져)는 다음과 같이 해석하면 정상적인 문자열을 받게 된다.(실제로는 작동하지 않으므로 URLEncoder를 사용하지말고 받는 자바 스크립트 측에서도 아래와 같이 받지 말고 그냥 request.responseText를 받을 것)
    // Mozilla FireFox와 IE에서는 Encode/Decode할 경우
    //공백이 +로 바뀌는 현상이 발생했다. 그래서 안쓴다.
    // JavaScript측에서 decodeURIComponent를 안하면 서버측에서도 URLEncoding을 하면 안된다.
    var res = decodeURIComponent(request.responseText);


    JSP/Servlet 에서 Ajax와 한글 인코딩 문제

    Ajax는 기본적으로 UTF-8 만으로 통신을 한다고 보면된다. 그 이외의 Encoding을 지원하는 인코딩 함수가 없기 때문에 EUC-KR로 데이터를 전송하려는 꿈은 접어야만 한다.
    헌데, 아직 우리나라는 EUC-KR 인코딩으로 된 웹 어플리케이션이 압도적으로 많은 상황이다(어서 빨리 UTF-8로 옮겨가길 바라마지 않는다).
    거기다가 보통 JSP/Servlet 웹 어플리케이션은 Servlet 스펙 2.3이후부터 문자 인코딩 서블릿 필터를 사용해 모든 요청에 대해 일관된 문자 인코딩을 사용하는 것이 보편적인 방법으로 자리잡았다.

    서블릿 필터는 일관성있게 모든 요청을 EUC-KR로 받아들이게 했는데, 몇몇 Ajax관련 요청만 UTF-8로 받아들여야만 하는 것이다.
    필터를 적용할 URL-Pattern을 따로 줘보려 했으나, 너무 복잡해졌다.
    그래서 HTTP 요청의 헤더를 이용해서 해결 했다.

    아.. 한가지 더. 현재 한글 문제는 "XMLHttpRequest 요청 -> JSP/Servlet" 이 상황에서만 발생하는 것이다.
    "JSP/Servlet -> XMLHttpRequest"의 상황(서버에서 클라이언트로 값을 리턴)에서는 이 문제가 발생하지 않는다.
    서버가 리턴하는 문자열은 간단하게 다음처럼 하면 WAS가 자동으로 UTF-8로 값을 변경해서 전달하기 때문이다.
    <%@ page contentType="text/plain; charset=utf-8" pageEncoding="EUC-KR"%>

    contentType에서 text/plain은 텍스트나 JSON으로 값을 리턴할 때이다. XML로 리턴할 때는 text/xml.

    아래는 Ajax 요청을 처리하기 위해서 만들어본 간단한 Encoding Filter 이다.
    package ajax.filter;

    import java.io.IOException;

    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;

    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;

    /**
     * 어플리케이션 전체에 적용되는 필터이다.
     * 
     * <ul>
     * <li>encoding 파라미터 : encoding 파라미터를 설정하면 request 객체에
     * setCharacterEncoding(encoding)을 실행한다.</li>
     * <li>ajaxFlag 파라미터 : Ajax요청임을 나타내는 HTTP 파라미터 이름이다. ajaxFilter로 지정한 HTTP 파라미터의
     * 값이 true 로 설정되면 인코딩을 무조건 UTF-8로 설정한다.</li>
     * </ul>
     * 
     * @author 손권남(kwon37xi@yahoo.co.kr)
     * 
     */
    public class EncodingFilter implements Filter {

        private Log log = LogFactory.getLog(this.getClass());

        /** HTTP 요청 문자 인코딩 */
        private String encoding = null;

        /** Ajax 요청임을 나타내는 플래그 파라미터 이름 */
        private String ajaxFlag = null;

        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {

            if (ajaxFlag != null
                    && "true".equals(((HttpServletRequest) request)
                            .getHeader(ajaxFlag))) {
                // Ajax 처리 요청일 경우 무조건 UTF-8 지정.
                request.setCharacterEncoding("UTF-8");
                if (log.isDebugEnabled()) {
                    log.debug("요청 헤더에 " + ajaxFlag + "가 "
                            + ((HttpServletRequest) request).getHeader(ajaxFlag)
                            + "로 설정되어 있어 문자 인코딩에  UTF-8을 사용합니다.");
                }
            } else if (encoding != null) {
                // Ajax 플래그가 true가 아니면, 기본적인 인코딩을 적용한다.
                request.setCharacterEncoding(encoding);
                if (log.isDebugEnabled()) {
                    log.debug("문자 인코딩에 " + encoding + "을 사용합니다.");
                }
            }

            chain.doFilter(request, response);
        }

        public void init(FilterConfig config) throws ServletException {
            encoding = config.getInitParameter("encoding");

            ajaxFlag = config.getInitParameter("ajaxFlag");

            if (log.isDebugEnabled()) {
                log.info("encoding : " + encoding + ", ajaxFlag : " + ajaxFlag);
            }
        }

        public void destroy() {
        }
    }

    이 필터를 적용하고서, web.xml에 다음 내용을 추가하면 필터가 작동한다.
    <filter>
        <description>이중 인코딩 필터</description>
        <filter-name>EncodingFilter</filter-name>
        <filter-class>ajax.filter.EncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>euc-kr</param-value>
        </init-param>
        <init-param>
            <param-name>ajaxFlag</param-name>
            <param-value>Ajax</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    여기 내용을 보면, 기본적인 인코딩은 EUC-KR이고, 요청 헤더에 "Ajax" 헤더의 값이 "true"일 경우에는 강제로 UTF-8을 지정하라고 한 것이다. "ajaxFlag"의 값을 변경하면 헤더의 키을 "Ajax"가 아닌 다른 값으로도 지정할 수 있다. 하지만 아무튼 해당 헤더의 값을 "true"로 지정하면 Ajax로 인식하게 되는 것이다.

    이를 위해서는 XMLHttpRequest에도 한가지 처리를 더 보태야 한다.
        request.open("GET", "AjaxProcessor.jsp" + fullParameter);
        request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
        request.setRequestHeader('Ajax', 'true');

    당연히 헤더에 값 Ajax요청임을 명시하는 값을 설정하는 것이다.

    그리고 다음 문제가 또 있는데, Tomcat 버전별로 문자 인코딩 설정이 달라질 수 있다는 것이다.
    위 내용은 Tomcat 4.x에서는 정상 작동하지만, Tomcat 5.x 에서는 제대로 작동하지 않는다.
    Tomcat 5.x에서는 server.xml 에 GET 방식의 요청에 대한 인코딩을 지정하기 때문이다.
    여기서 URIEncoding="euc-kr" 을 사용하지 않고, useBodyEncodingForURI="true"을 사용하면 Tomcat 4.x 처럼 request.setCharacterEncoding()의 값을 따라가게 할 수 있다.
    Tomcat과 한글에 대해서는 Tomcat/JSP와 한글문서를 참조한다.

    또하나 Ajax임을 나타내는 플래그를 HTTP 요청 헤더에 설정하도록 했는데, 그러지 않고 요청 파라미터(request.getParameter()로 값을 얻어올 수 있는 것)으로 설정하면 안된다.
    request.getParameter()가 실행되어 Ajax 플래그의 값을 감지하는 그 순간, 그 이후 호출되는 request.setCharacterEncoding()는 완전히 무시되어 버리기 때문이다.

    예제

    급조한 예제이다.
    * AjaxCaller.jsp - Ajax 호출부(클라이언트) : 수식을 만들어서 서버측에 계산을 요청한다.
    <%@ page language="java" contentType="text/html; charset=EUC-KR"
        pageEncoding="EUC-KR"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
    <title>Insert title here</title>
    <script type="text/javascript">
    // XMLHttpRequest 오브젝트 생성 함수
    // @sample oj = createHttpRequest();
    // @return XMLHttpRequest 오브젝트
    function createHttpRequest()
    {
        if (window.ActiveXObject) {
            try {
                // IE6
                return new ActiveXObject("Msxml2.XMLHTTP");
            } catch (e) {
                try {
                    // IE4, IE5
                    return new ActiveXObject("Microsoft.XMLHTTP");
                } catch (e2) {
                    return null;
                }
            }
        } else if (window.XMLHttpRequest) {
            // Mozilla, FireFox, Opera, Safari, Konqueror3
            return new XMLHttpRequest();
        } else {
            return null;
        }
    }

    // 계산을 수행한다.
    function calc() {
        var request = createHttpRequest();
        var nameParam = encodeURIComponent("name");
        var nameValue = encodeURIComponent(document.getElementById("name").value);
        
        var oper1Param = encodeURIComponent("oper1");
        var oper1Value = encodeURIComponent(document.getElementById("oper1").value);
        
        var oper2Param = encodeURIComponent("oper2");
        var oper2Value = encodeURIComponent(document.getElementById("oper2").value);
        
        var operatorParam = encodeURIComponent("operator");
        var operatorValue = encodeURIComponent(document.getElementById("operator").value);
        
        var fullParameter =
            "?" + nameParam + "=" + nameValue
            + "&" + oper1Param + "=" + oper1Value
            + "&" + oper2Param + "=" + oper2Value
            + "&" + operatorParam + "=" + operatorValue;
        
        request.onreadystatechange = function() {
            if (request.readyState == 4) {
                alert("Response : " + request.responseText);
                eval("var result = " + request.responseText);
                alert(result.name + "님 계산결과는 " + result.value + "입니다.");
            }
        }
        
        request.open("GET", "AjaxProcessor.jsp" + fullParameter);
        request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
        request.setRequestHeader('Ajax', 'true');
        request.send("");

    } // end of calc()
    </script>
    </head>
    <body>
    이름 : <input type="text" id="name" /> <br />
    <input type="text" id="oper1" />
    <select id="operator">
        <option value="+">+</option>
        <option value="-">-</option>
        <option value="*">*</option>
        <option value="/">/</option>
    </select>
    <input type="text" id="oper2" />
    <input type="button" value="계산하기" onclick="calc()" />
    </body>
    </html>

    * AjaxProcessor.jsp - Ajax 처리부(서버) : 수식을 계산한 결과를 JSON 형태로 리턴한다
    <%@ page contentType="text; charset=utf-8" pageEncoding="EUC-KR"%>
    <%
    System.out.println("AjaxProcessor.jsp 시작");

    String result = null;

    String name = request.getParameter("name");
    String oper1 = request.getParameter("oper1");
    String oper2 = request.getParameter("oper2");
    String operator = request.getParameter("operator");

    double oper1Value = Double.parseDouble(oper1);
    double oper2Value = Double.parseDouble(oper2);

    double calcResult = 0;

    if ("+".equals(operator)) {
        calcResult = oper1Value + oper2Value;
    } else if ("-".equals(operator)) {
        calcResult = oper1Value - oper2Value;
    } else if ("*".equals(operator)) {
        calcResult = oper1Value * oper2Value;
    } else {
        calcResult = oper1Value / oper2Value;
    }

    result = "{  " +
        ""name" : "" + name + "", " +
        ""value" : "" + calcResult + "" " +
        "} ";
    System.out.println("Result : " + result);

    %><%= result%><%
    System.out.println("AjaxProcessor.jsp 끝");
    %>

    이름 입력 부분에 한글을 입력하여 문제없이 처리되는지 확인해보기 바란다.

    JSON

    Ajax(JavaScript)는 데이터를 리턴 받는 방법으로 XML/Text/JSON을 지원한다. JSON은 텍스트 형태로 객체를 정의하는 방식이다. 이것은 XML과 1:1 매칭을 할 수도 있다. XML보다 훨씬 만들기 쉽고 사용법도 자바 객체를 사용하는 것과 유사하다. 그래서 이걸 사용해서 프로그램을 작성했다.
    {
      "test1": "hello",
      "test2": "hello2"
    }

    위와 같은 메시지를 서버에서 응답으로 내보냈다고 할 때
    // JSON 형태의 텍스트를 JavaScript 객체화 한다.
    eval("res = " + request.responseText);

    // 객체를 사용한다.
    alert(res.test2); // 이 명령은 "hello2"를 출력한다.

    배열은 다음과 같이 생성한다.
    [
      ["test1", "test2"],
      ["test3", "test4"]
    ]

    아래와 같이 사용한다.
    eval("res = " + request.responseText);

    // test4를 출력한다.
    alert(res[1][1])

     * JSON 홈페이지 : http://www.json.org/
     * Java 객체를 이용해서 JSON 객체를 위한 텍스트 생성하기 : http://www.json.org/java/simple.txt 매우 단순한 방법으로 핵심 기능만 가지고 있다. 이것을 사용하길 권장한다. 라이브러리 다운로드는 http://www.JSON.org/java/json_simple.zip 에서 한다. 
     * XML과 JSON간의 변환
    posted by 좋은느낌/원철
    2009. 7. 16. 16:44 개발/Linux 계열

    일반적으로 웹로그 분석은 Webalizer를 많이 사용하나, 여기서는 보다 괜찮은 인터페이스 및 한글화된 awstats를 설치하는 방법을 알아보도록 한다.





    우선, 필자가 테스트한 배포판은 김정균씨의 안녕리눅스를 devel로 설치하였고, Apache 1.3.29 버전이다. RedHat 7.3 및 9 버전에서도 설치하는데 문제는 없었다.





        관련사이트 : http://awstats.sourceforge.net


        데모사이트 : http://awstats.sourceforge.net/cgi-bin/awstats.pl





    1. 다운로드





      다음 주소에서 awstats 6.2 버전을 다운받아 설치하려는 서버로 옮겨 놓는다.





        http://lec.pe.kr/files/awstats-6.2.tgz








    2. 압축 풀기, 기본 디렉토리 생성





        # tar xvfz awstats-6.2.tgz


        # mv awstats-6.2 /usr/local/awstats


        # chmod 755 /usr/local/awstats/


        # chown -R root.root /usr/local/awstats/


        # mkdir /etc/awstats


        # mkdir /var/lib/awstats








    3. 설치 스크립트 실행





        # cd /usr/local/awstats/tools


        # ./awstats_configure.pl





      설치 중에 3번 정도 물어보는데, 아파치 환경설정파일의 절대경로 위치와, 처음 설치시 설정파일 생성 여부('y'로 답하면 된다), 그리고 임의의 이름을 정하면 된다. 필자는 nfo.pe.kr 사이트에 로그분석기를 설치하므로 세 번째의 이름을 nfo.pe.kr로 적었다.








    4. 설정파일의 수정





      이제 /etc/awstats/ 디렉토리 밑에 awstats.[자신이 정한 이름].conf 파일이 생성된 것을 볼 수 있다. 필자의 경우 파일명은 다음과 같다.





        /etc/awstats/awstats.nfo.conf





      이 파일을 열어서 51번째 라인의 LogFile의 지정 값을 로그 분석하고자 하는 파일명으로 수정한다. 일반적으로 아파치 로그파일은 /var/log/httpd/ 디렉토리에 위치할 것이다. 다음은 필자의 경우 수정한 예제이다.





        # cat /etc/awstats/awstats.nfo.conf | grep ^LogFile


        LogFile="/var/log/httpd/nfo.pe.kr-access_log"








    5. httpd.conf 파일의 수정





      필자의 경우 안녕 배포판에 rpm으로 Apache를 설치하였으므로 Apache 환경설정파일의 위치는 /etc/httpd/conf/httpd.conf 파일이다. 


      위에서 /usr/local/awstats/tools 디렉토리에 있는 awstats_configure.pl 파일을 실행하여 제대로 설치하였다면 httpd.conf 파일의 마지막 부분에 다음과 같은 내용이 추가되어 있을 것이다.





        #


        # Directives to allow use of AWStats as a CGI


        #


        Alias /awstatsclasses "/usr/local/awstats/wwwroot/classes/"


        Alias /awstatscss "/usr/local/awstats/wwwroot/css/"


        Alias /awstatsicons "/usr/local/awstats/wwwroot/icon/"


        ScriptAlias /awstats/ "/usr/local/awstats/wwwroot/cgi-bin/"


        


        #


        # This is to permit URL access to scripts/files in AWStats directory.


        #


        <Directory "/usr/local/awstats/wwwroot">


            Options None


            AllowOverride None


            Order allow,deny


            Allow from all


        </Directory>





      혹시 httpd.conf 파일에 위의 내용이 추가되어 있지 않다면 /usr/local/awstats/tools/httpd_conf 파일의 내용을 그대로 복사하여 httpd.conf 파일에 넣어주면 된다.





      또한 httpd.conf 파일에서 로그 파일의 포맷을 combined 로 변경해 주어야 한다. 일반적으로 로그파일의 포맷은 common으로 되어 있는 경우가 대부분이다. 필자 역시 다음과 같이 common 포맷으로 되어 있었다.





        CustomLog /var/log/httpd/nfo.pe.kr-access_log common env=!img-nosave,!CodeRedNimda





      이것을 다음과 같이 combined로 수정하여 준다.





        CustomLog /var/log/httpd/nfo.pe.kr-access_log combined env=!img-nosave,!CodeRedNimda








    6. 기존 로그파일의 내용 삭제, Apache 재시작





      기존의 로그파일인 /var/log/httpd/nfo.pe.kr-access_log 파일의 포맷이 common에서 combined로 변경되었으므로 로그파일에 쌓인 로그를 모두 지운 후에 Apache를 재실행한다.








    7. 로그분석 실행 밑 웹페이지에서 확인





      여기까지 마친 후, awstats 로그분석기를 실행하려면 다음과 같이 한다( -config 옵션의 값은 [자신이 정한 이름]을 적으면 된다).





        # /usr/local/awstats/wwwroot/cgi-bin/awstats.pl -update -config=nfo.pe.kr





      웹브라우저에서 다음 주소로 확인할 수 있다.





        http://도메인주소/awstats/awstats.pl?config=[자신이 정한 이름]





      필자의 경우, 도메인 주소는 nfo.pe.kr 이고 [자신이 정한 이름]은 nfo.pe.kr 이므로, 다음과 같이 브라우저에서 찾아가면 웹로그분석 사이트가 보일 것이다.





        http://nfo.pe.kr/awstats/awstats.pl?config=nfo.pe.kr








    8. Cron 등록





      awstats 로그분석기를 일정 간격으로 자동 실행하기 위하여 /etc/crontab 파일에 다음을 추가한다.





        30 1-24/12 * * root /usr/local/awstats/wwwroot/cgi-bin/awstats.pl -update -config=nfo.pe.kr





      하루 두 번씩 cron 데몬이 정기적으로 업데이트를 하고 있다. 업데이트 주기는, 사이트의 방문자가 많을 수록 짧게 하면 된다.



    posted by 좋은느낌/원철
    2009. 7. 2. 09:47 개발/JSP/Servlet

    Tomcat + SSL

    Authenticating Clients (with SSL)

    디지털 커머스의 증가와 중요한 데이터간의 이동이 필요함에 따라서 보안은 모든 어플리케이션에서 중요한 자리를 차자하고 있습니다. 일반적으로 client 와 서버간에 사용자를 확인하기 위한 방법으로 username 과 password 를 체크합니다. 이를 사용하는 보안 처리 기법으로 Secure Sockets Layer (SSL) 과 Java Authentication and Authorization Service (JAAS)를 사용할 수가 있습니다. 먼저 SSL로 보안인증을 거치는 방법을 보고 java 에서 지원하는 다른 사용자 인증서비스인 JAAS을 jsp와 서블릿에서 사용하는 법을 보겠습니다.

    1. 톰켓에서 사용자 인증 처리하기

    톰켓으로 사용자 인증처리를 하기전에 먼저 username, password, role 을 등록해야 합니다. 등록하는 방법은 아주 쉽습니다. 톰켓이 설치된 폴더에서 /conf 에 보면 tomcat-user.xml 파일이 있습니다. 없으면 에디터 창에서 새로 만들어도 됩니다. 

    <?xml version='1.0' encoding='utf-8'?><?xml version='1.0' encoding='utf-8'?> 
    <tomcat-users> 
        <role rolename="dbadmin"/> 
        <role rolename="manager"/> 
        <user username="hans" password="hansworld" roles="dbadmin,manager"/> 
        <user username="jojo" password="33dsk3" roles="manager"/> 
    </tomcat-users> 

    위 소스에서 hans는 dbadmin과 manager의 권한을 갖고 jojo는 manager의 권한을 갖습니다. 

    다음으로 톰켓서버에서 SSL을 셋팅해야 합니다. 이는 username이나 password 가 http상에서 이동할 때 암호화 되어 이동하기 때문에 중간에 악의적인 의도로 가로채거나 훔쳐내는 것을 방지해 줍니다. SSL을 셋팅하기 위해선 2가지 절차를 거쳐야 합니다.

    1. java sdk에서 지원해주는 keytool로 keystore 파일을 만듭니다. 이 파일은 보안 접속을 하는 서버가 디지털 인증을 암호화 해서 사용하는데 쓰여집니다. 
    2. 톰켓의 conf/server.xml 파일에 SSL Connector에 있는 주석을 제거합니다.

    keytool은 java가 설치된 in 에서 찾을 수 있습니다. 

    %JAVA_HOME%inkeytool -genkey -alias tomcat -keyalg RSA 


    위의 명령을 실해하면 keystore 파일이 생성되는데 몇가지 질문을 합니다. 처음으로 패스워드를 물어보는데 톰켓에서 기본적으로 "changeit" 란 패스워드로 셋팅되어 있습니다. 나머지는 원하지 않으면 그냥 엔터키만 치면 됩니다. 

    Enter keystore password: changeit 
    What is your first and last name? 
    [Unknown]: Bruce Perry 
    What is the name of your organizational unit? 
    [Unknown]: 
    What is the name of your organization? 
    [Unknown]: 
    What is the name of your City or Locality? 
    [Unknown]: 
    What is the name of your State or Province? 
    [Unknown]: 
    What is the two-letter country code for this unit? 
    [Unknown]: 
    Is CN=Bruce Perry, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct? [no]: yes 
    Enter key password for <tomcat>
    (RETURN if same as keystore password):

    다음에 conf/server.xml 에 있는 SSL Connector 요소에 있는 주석을 제거합니다.

    <!-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
    <connector disableuploadtimeout="true" useurivalidationhack="false" secure="true" scheme="https" debug="0" acceptcount="100" enablelookups="true" maxprocessors="75" minprocessors="5" port="8443" classname="org.apache.coyote.tomcat4.CoyoteConnector">
    <factory classname="org.apache.coyote.tomcat4.CoyoteServerSocketFactory" protocol="TLS" clientauth="false" />
    </connector>

    SSL은 일반 http 가 아닌 https 를 사용합니다. 또한 포트도 웹에서 80, 톰켓에서 8080 처럼 8443의 번호를 사용합니다.

    https://localhost:8443/myhome/default.jsp



    2. BASIC authentication BASIC Authentication


    Basic 인증은 웹자원과 함께 사용되어온 보안 방법이고 거의 모든 브라우져가 이를 지원합니다. 일반적으로 사용자 이름과 비밀번호를 전송할 때 네트워크 상에서 Base64 인코딩 방식을 사용하는데 이는 디코딩하기 아주 쉽기때문에 보안적이라고 할 수 없습니다. 따라서 Basic Authentication 과 SSL 을 사용한 보안 방식을 사용합니다.

    1. 먼저 처음에 설명했지만 username, password, role을 conf/tomcat-users.xml 에서 설정합니다.
    2. security-constraint element 로 인증에 필요한 자원을 web.xml 파일에 기술합니다.
    3. "BASIC"이라고 auth-method요소 사이에 적습니다. 이 auth-method 요소는 login-config요소에 들어갑니다.

    <!-- Beginning of web.xml deployment descriptor -->
    <security-CONSTRAINT>
    <web-RESOURCE-COLLECTION>
    <web-RESOURCE-NAME>JSP database component</web-RESOURCE-NAME> 
    <url-PATTERN>/myhome.jsp</url-PATTERN> 
    <http-METHOD>GET</http-METHOD> 
    <http-METHOD>POST</http-METHOD> 
    </web-RESOURCE-COLLECTION>
    <auth-CONSTRAINT>
    <role-NAME>dbadmin</role-NAME> 
    </auth-CONSTRAINT>
    <user-DATA-CONSTRAINT>
    <transport-GUARANTEE>CONFIDENTIAL</transport-GUARANTEE> 
    </user-DATA-CONSTRAINT>
    </security-CONSTRAINT>
    <login-CONFIG>
    <auth-METHOD>BASIC</auth-METHOD> 
    </login-CONFIG>
    <security-ROLE>
    <role-NAME>dbadmin</role-NAME> 
    </security-ROLE>
    <!-- Rest of web.xml deployment descriptor -->

    web.xml 을 이렇게 편집한 후에 https://localhost:8443/myhome.jsp 로 들어가보면 아이디와 비밀번호를 입력하라는 창이 뜹니다. 여기서 만일 role 이 dbadmin 이 아니라면 아이디와 비밀번호가 맞아도 인증에 실패하게 됩니다. 반드시 해당 사용자가 인증에 필요한 role을 가지고 있어야 합니다.



    3. Form-Based Authentication 의 사용 

    서블릿은 일반 BASIC authentication 말고도 사용자 기반 인증인 Form-Based Authentication 제공합니다. 이는 톰켓에서 보여주는 BASIC authentication 의 단순화를 덜어주며 일반적으로 사용하는 form 방식을 사용하기 때문에 이용하기도 편합니다. 이역시 SSL 과 HTTPS를 사용하여 네트워크상에서 이동하는 데이터들을 보호합니다.

    먼저 web.xml 셋팅을 보겠습니다. 파일의 맨 처음부분에 보안 관련 element를 기술하게 됩니다. security-constraint 부분은 BASIC authentication 과 같습니다. login-config 셋팅부분이 약간 다르긴 하지만 그렇게 크게 다르지는 않습니다.

    <login-CONFIG>
    <auth-METHOD>FORM</auth-METHOD>
    <form-LOGIN-CONFIG>
    <form-LOGIN-PAGE>/login.html</form-LOGIN-PAGE>
    <form-ERROR-PAGE>/loginError.jsp</form-ERROR-PAGE>
    </form-LOGIN-CONFIG>
    </login-CONFIG>

    실제 jsp에서 
    <form>테그를 사용하여 사용자 정보를 전송하는데 이때 주의할 점은 form 태그의 action 요소의 값을 'j_security_ckeck' 로 하고 사용자 이름과 비밀번호의 이름을 'j_username' 과 'j_password'로 해야합니다. 로그아웃 시에는 HttpSession 객체의 invalidate() 메소드를 호출하면 됩니다.</form>
    posted by 좋은느낌/원철