꿈꾸는자의 생각의 파편들... :: 'Dev.../플밍 관련 자료' 카테고리의 글 목록 (3 Page)

달력

10

« 2018/10 »

  •  
  • 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
  •  
  •  
  •  
예산이 빠듯한 업체들 사이에서 인기가 높아지고 있는 오픈소스 소프트웨어가 새로운 영역으로 세를 확산하고 있다. 바로 MS와 같은 대기업이 지배하고 있는, 수익성이 높은 인프라스트럭처 소프트웨어다.

이미 오픈소스 데이터베이스와 몇몇 애플리케이션들은 높은 인기를 구가하고 있다. 또한 별도로 MS, IBM, 오라클, BEA 시스템즈와 같은 업체들의 상용 소프트웨어와 동일한 오픈소스 대안을 구축하기 위해 두개의 오픈소스 프로젝트가 진행 중에 있다. 이 프로젝트들은 소프트웨어 애플리케이션의 ‘계층’을 구축한다는 목표를 세우고 있다.

지난 주 글루코드(Gluecode)라는 업체가 아파치 재단의 인프라스트럭처 툴 패키지에 대한 기술 지원·유지 보수 서비스를 판매하기 시작했다. 아파치 재단은 현재 가장 인기가 높은 오픈소스 소프트웨어인 아파치 웹서버를 감독·개발하고 있다. 이 패키지에는 포털·데이터베이스 소프트웨어와 애플리케이션 서버가 포함돼 있다.

그리고 6년전 프랑스 업체들과 연구기관이 설립한 비영리 컨소시엄인 오브젝트웹(ObjectWeb)이 최근 엑소(eXo) 플랫폼을 공개할 것이라고 밝혔다. 여기에는 이미 컨소시엄에서 제공하고 있는 연결성, 그리드 컴퓨팅, 기업용 인스턴트 메신저 이외에 기업용 웹 포탈·CMS 애플리케이션 등이 포함돼 있다.

비록 이 새로운 소프트웨어들이 수십억달러 규모의 백엔드 소프트웨어 시장을 어떻게 뒤흔들 수 있을지 논하기는 이르지만 상용 소프트웨어 업체들에게 있어 가장 수익성이 높은 분야에 있어 오픈소스 대안이 늘어나고 있다는 것은 엄연한 사실이다.

이런 추세는 갈수록 더 강해질 것이다. 아파치 재단과 오브젝트웹은 증가세에 있는 자바 서버 소프트웨어 컴포넌트를 결합해 사유 애플리케이션들과 경쟁 구도를 형성하게 될 것으로 보인다.

버튼 그룹의 애널리스트 앤 토마스 메인즈에 따르면 좋은 소식은 데이터베이스에서 비즈니스 애플리케이션에 이르기까지 이제 오픈소스 대안이 존재하게 됐다는 것이다. 그럼 나쁜 소식은? 이에 따라 많은 일들을 스스로 해결해야 한다는 것이다.

메인즈는 “오픈소스 기술에 기반해 똑같이 구축하는 것도 가능하다. 그러나 시스템 통합을 스스로 진행해야 한다는 것이 난제다. 통합 환경을 구축하려면 상당한 작업이 필요하기 때문”이라고 말했다.

오픈소스의 장점으로는 비용절감이 있다. 구매자들은 기술 지원 요금만 부담하고 소프트웨어 가격은 지불하지 않는다. 또한 MS를 비롯한 상용 소프트웨어 업체들과 장기 라이선스 정책이나 업그레이드 권한에 대해 마찰도 거의 없다. 회사의 성장에 따라 애플리케이션을 추가하기도 쉬우며 필요한 경우 소스코드를 즉시 이용할 수 있다.

물론 상용 서버 소프트웨어 패키지가 상당기간동안 지속적으로 가장 진보된 기능을 제공한다는 것에는 모든 사람들이 동의하고 있다. 그러나 이 오픈소스 미들웨어 프로젝트를 후원하고 있는 소프트웨어 프로그래머와 기업가들은 이미 자리를 잡고 있는 기존 상용 업체들과 정면 대결할 것이라고 공공연히 말하고 있다.

오브젝트웹의 실무 담당 부장 크리스토프 네이는 “오브젝트웹의 기반 코드에 포털을 추가함으로써 결함을 메웠기 때문에 상용 제품에 대한 진정한 대안으로 자리잡을 수 있게 됐다. 회원사들은 이미 애플리케이션 서버 이상을 구현할 수 있다는 것에 관심을 보이고 있다”라고 말했다.

네이는 오브젝트웹이 BPEL(Business Process Execution Language) 표준에 기반한 통합이나 비즈니스 절차 자동화와 같이 고가의 소프트웨어와 연동되는 제품을 개발하고 있다고 덧붙였다.

아직 어떤 대형 업체도 오브젝트웹의 서버 컴포넌트 패키지를 지원하는 서비스를 제공한다고 밝히지 않고 있다. 그러나 레드햇은 올 연초부터 자사의 요나(Jonas) 애플리케이션 서버용 서비스를 제공하기 시작했다.

기술 지원 서비스 ‘잘팔린다’
IBM, BEA 시스템즈, 오라클은 자바 애플리케이션 서버와 웹 포털, 통합 소프트웨어, 애플리케이션 개발 툴 등이 포함된 상용 자바 소프트웨어 패키지를 판매하고 있다. 또한 MS는 닷넷 개발 모델에 기반을 두고 있는, 이와 유사한 윈도우 서버 소프트웨어 패키지를 제공한다. 비즈니스 애플리케이션에 있어 기술적인 기반을 구성하는 이 인프라스트럭처 소프트웨어와 관련 툴들은 라이선스 비용만 해도 최대 수십만 달러에 달한다.

대규모 상용 기술 업체들은 최근 몇 년간 오픈소스 대안 소프트웨어의 수요가 늘어나고 있다는 현상을 인지하고 있다. IBM은 이미 리눅스, 그리드 컴퓨팅, 더비라고 불리는 전문 자바 데이터베이스 프로젝트 등 오픈소스 프로젝트의 주요 참여업체가 됐다. 그러나 웹스피어 자바 서버 패키지와 DB2 데이터베이스 등 수십억 달러의 매출을 거두고 있는 IBM의 미들웨어 제품들은 아직 사유 소프트웨어를 사용한다.

BEA 또한 개발자들에게 호감을 사기 위해 일부 제품을 오픈소스 형태로 배포하고 있다. 그러나 여전히 매출 실적은 사유 소프트웨어에 의존하고 있다.

HP의 리눅스 담당 부사장인 마틴 핑크는 “소프트웨어 자체에서 컴포넌트 통합으로 가치가 이전되고 있다”라고 설명했다. 이 회사는 최근 HP의 하드웨어에서 작동되는 JBoss, MySQL, 리눅스 소프트웨어를 대상으로 하는 컨설팅 서비스를 확대했다.

오브젝트웹, 아파치와 상용 소프트웨어 업체인 J보스의 오픈소스 컴포넌트들은 이미 많은 프로그래머들의 지원을 받고 있다. 그러나 업계 애널리스트와 중역들은 이 제품들에 적절한 상용 기술지원이 제공되느냐에 수용도가 결정된다고 지적한다.

글루코드와 신생업체인 스파이크소스(SpikeSource), 소스랩스(SourceLabs)는 이 점을 파고들고 있다. 이 업체들은 인증받고 통합된 오픈소스 소프트웨어 패키지의 가입자 기반 지원 서비스를 판매한다는 개념에 근거한 사업을 진행하고 있다.

글루코드는 아파치 오픈소스 라이선스 하에 구할 수 있는 다수의 오픈소스 제품에 대해 기술 지원·유지 보수 서비스를 제공한다. 이 업체는 조(Joe)라는 패키지를 이용해 자바 애플리케이션 서버인 제로니모(Geronimo), 포탈 소프트웨어 플루토(Pluto), 데이터베이스 더비, 워크플로우 소프트웨어인 아질라(Agila)에 대한 서비스를 판매하고 있다.

글루코드는 자사 패키지가 인텔의 IA64 프로세서에서 수행되며 하드웨어 업체들과 협력해 조 패키지를 번들 배포할 계획이라고 밝혔다. 이 회사의 CEO 윈스턴 다마릴로는 기술 지원과 정기적인 소프트웨어 업데이트에 드는 비용은 매월 3500달러이며 조 패키지가 기반을 잡은 자바 업체는 물론이고 MS와 같은 업체보다도 저렴한 가격에 제공된다고 강조했다.

다마릴로는 “서버 분야의 소프트웨어 비용에 시장은 질려 있는 상태다. 우리는 바로 이 비용을 0으로 만들려 한다”라고 말했다.

뒤이어 다마릴로는 제로니모가 모듈 형태로 설계돼 있기 때문에 포털이나 통합 소프웨어와 같은 애드온 제품이 필요할 경우 쉽게 추가할 수 있다고 전했다. 글루코드는 또한 설치와 관리를 용이하게 진행할 수 있는 관리 소프트웨어도 판매하고 있다.

스파이크소스와 소스랩스는 램프(LAMP)라고 불리는 오픈소스 소프트웨어 묶음을 중심으로 서비스를 제공하려 한다. 여기에는 리눅스 운영체제, 아파치 웹서버, MySQL 데이터베이스, 그리고 PHP 개발 툴 등이 포함돼 있다.

JBoss는 무료 소프트웨어를 중심으로 컨설팅·지원 서비스를 판매하고 있다. 자바 프로그래머들로부터 인기를 끌고 있는 애플리케이션 서버를 보유한 이 회사는 자체 개발·지원하는 워크플로우 서버 등으로 제품군을 확대하고 있다.

아파치, 오브젝트웹, JBoss는 자바 애플리케이션 서버에 기반한 미들웨어 제품을 각각 개발하고 있으며 별도의 오픈소스 라이선스를 제공하고 있다. JBoss는 최근 자사 소프트웨어가 J2EE 표준을 따른다는 인증을 받았다. 제로니모와 요나도 J2EE 인증을 받을 예정이다.

사유 SW 업체 “오픈소스 영향? 없어!”
아직까지 대형 상용 소프트웨어 업체들은 오픈소스 대안 제품들이 시장 점유율이나 수익을 잠식하고 있다는 것을 부인한다. 썬 마이크로시스템즈의 경우 자바 애플리케이션 서버 패키지를 오픈소스 형태로 제공할 것을 고려한 적도 있다고 전했다.

비록 오픈소스 미들웨어가 아직 전체시장에서 극히 일부분만을 차지하고 있지만 오픈소스 애플리케이션과 리눅스의 전체 사용도는 지속적으로 증가하고 있다. 시장조사기관 가트너는 조사대상 대기업의 80% 이상이 일부 영역에서라도 리눅스를 사용하고 있는 것으로 답했다고 전했다.

게다가 오픈소스를 받아들이는 데 있어 이미 잘 확립된 수용 패턴이 존재하고 있다. 리눅스를 예로 들어 보자. 1990년대 일반적인 서버에서 웹 또는 파일 서버로 처음 사용된 리눅스는 이제 각 부서의 서버부터 시작해 고성능 컴퓨팅·데스크톱 소프트웨어에 이르기까지 유닉스나 윈도우에 대한 저가의 대안 제품 역할을 수행하고 있다.

오픈소스 자바 애플리케이션 서버, 데이터베이스, 개발 툴들도 빠르게 두각을 나타내고 있다. 사명과 같은 이름의 애플리케이션 서버용 지원 서비스를 판매하는 JBoss와 오픈소스 데이터베이스 업체 MySQL은 지난해 많은 사람들에게 인기를 끌었다.

리눅스와 오픈소스 애플리케이션이 광범위하게 수용되는 데 있어 장애물은 바로 대기업들이 얼마나 큰 위험을 감수할 의지가 있느냐라고 지난달 발행된 가트너 보고서는 지적한다. 여기에는 출처가 다양한 각양각색의 애플리케이션을 지원해야 한다는 것도 포함된다. 바로 이런 부분을 글루코드 등 몇몇 업체들이 떠맡으려 하고 있다.

가트너는 지적재산권과 법적 문제에 대한 위험 부담이 오픈소스 소프트웨어의 수용에 있어 또다른 문제로 작용한다고 전했다. 이 문제들은 리눅스와 오픈소스의 광범위한 성장에 있어 향후 5년간 도전 사항이 될 것이다. 레드햇, 노벨 등 몇몇 업체들은 리눅스 고객을 대상으로 법적 보호장치를 제공하기 시작했다.

BEA의 CEO 알프레드 추앙은 오픈소스 자바 애플리케이션 서버, 특히 JBoss 현재로서 BEA의 사업에 전혀 침해를 주고 있지 않다고 이달 초 밝힌 바 있다. 그는 JBoss가 “기업에서 사용되고 있는 것을 본 적이 없다. 우리에게 전혀 위협적인 존재가 아니다”라고 말했다.

MS의 플랫폼 전략 총괄 마틴 테일러는 오픈소스 미들웨어 컴포넌트가 한번 조립되고 나면 “마치 우리 것인 것처럼 보인다”라고 말했다. 그러나 그는 대다수 고객들이 낮은 수준의 소프트웨어 통합에 시간과 노력을 투자하길 원하지 않는다고 지적했다. 테일러는 또한 패키지 애플리케이션이 오픈소스 소프트웨어에서 수행될 수 있도록 인증받았는지 고려해야 한다고 전했다.

테일러는 “오픈소스에 특정 애플리케이션이 존재하는지 안하는지 문제가 아니다. 바로 각 소프트웨어 묶음에 걸친 통합의 정도로 상위와 하위의 통합 정도, 그리고 튜닝에 걸리는 작업의 정도”라고 말했다.

오픈소스 인기, 부인할 수 없는 사실
그러나 품질이 좋은 오픈소스 소프트웨어들은 기업들에게 받아들여지고 있다는 것은 분명하다. 또한 상용 소프트웨어와 오픈소스 방식이 한 기업 내에 공존할 수도 있다. 포레스터 리서치의 애널리스트 헨리 페이렛은 오픈소스 미들웨어 프로젝트가 대부분 저가 시장 쪽에 치중하고 있으며 상용 업체들처럼 가장 진보된 기능을 좇지는 않는다고 설명했다. 따라서 오픈소스 소프트웨어가 항상 이미 완성된 제품들과 직접적으로 경쟁하는 것은 아니라고 그는 덧붙였다.

페이렛은 “일부 고객은 자신들이 충분히 좋은 제품을 선택한다는 것을 확실하게 자각하고 있다. 비록 모든 기능을 제공하진 않는대도 말이다. 특정 기능을 원한다면 그 분야에만 상용 소프트웨어를 적용하면 된다. 기업 전체에 적용할 필요는 없다”라고 말했다.

반면 메인지는 오픈소스 미들웨어 제품을 수용하는 것이 위험을 감수할 수 있는 준비와 자체적인 기술 지원 능력을 필요로 한다고 전했다. 오픈소스 프로젝트들은 중단될 수도 있으며 상용 기술 지원이 항상 명쾌하게 맞아 떨어지는 것은 아니기 때문이다.

메인지는 “사실 IBM의 소프트웨어를 사용하느냐, 아니면 기술 지원 분야에 투자하고 오픈소스 사용에 따른 위험을 감수하느냐 하는 것은 완전히 기술적인 문제는 아니다. 여기에는 문화적인 이슈도 분명히 존재한다”라고 전했다
Posted by 꿈꾸는자의 생각의파편들
2005.02.13 17:26

[펌] Ant란? Dev.../플밍 관련 자료2005.02.13 17:26

Ant의 소개 Ant 는 Java 기반의 Build 툴로써 Unix 의 make 와 같은 툴이라고 보면 된다.

왜 Ant 를 사용해야 하나?
make.gnumake,nmake,jam 과 같은 다른 Build 툴은 놔두고 왜 Ant 를 써야하는가에 대한 질문이다. Java 기반으로 프로그램을 짜고 컴파일 및 배포용 쉘 프로그램을 짜봤는가? 해봤다면 그것의 어려움을 잘 알것이다. 각 OS 마다 쉘 스크립트가 다르고 일반적으로 사용하고 있는 Unix 에는 또 각종 쉘들이 존재한다. 윈도우 쉘 또한 복잡하긴 매한가지이고 프로그램을 모두 작성하고 컴파일 및 배포 쉘 스크립트를 작성하기 위해서 이것들을 모두 작성하는것 자체가 프로그래머에게 또 하나의 고난이 아닐까 생각한다.(즉, 쉘 프로그램을 배워야 한다는 의미이다.)


게다가, 팀 단위 작업을 한다고 할때, 작업하는 컴퓨터와 IDE 들이 각각 다른 경우, IDE 에 따라서 classpath, 배포디렉토리 경로들도 다를 것이다.

Ant 는 OS Indepenent 하게 프로그램을 Build 할 수 있는 환경을 제공해준다. build.xml 이란 Build 파일을 작성해서 그 내용에 따라 Build 를 진행해 나갈 수 있다. Ant 는 Java 에서 거의 표준으로 굳혀져가고 있으며, 거의 모든 IDE들이 Ant 를 지원한다.



Install 현재 Ant 는 Binary 와 Source 두가지를 배포하고 있습니다.


Ant 얻기 - IDE 에 따라서 Ant 가 기본내장되어있는 경우가 많다.

http://jakarta.apache.org/ant/index.html 에서 최신버전의 binary, source 를 얻을 수 있다. CVS 를 이용, source 를 얻을 수도 있다.


시스템 요구사항

Ant 를 사용하여 Build 하기 위해서는 JAXP 호환 XML파서가 있어야 합니다. 그런데 Ant 를 다운받으면 그 패키지 안에 포함되어 있으므로 따로 다운받으실 필요는 없습니다. JAXP 에 대해서는 http://java.sun.com/xml/ 정보를 얻을 수 있습니다.
Build 툴이기 때문에 당연히 JDK 가 필요합니다. JDK 1.2 이상을 가지고 있으면 됩니다.
Ant 의 몇몇 특정 Task 들의 경우 (JUnit, FTP, Telnet 등) 해당 라이브러리가 필요하다. 이는 http://jakarta.apache.org/ant/manual/install.html#librarydependencies 항목을 읽기 바란다.


Install

바이너리 파일을 기준으로 설명하겠습니다. 설치는 Windows 기반으로 설명하겠습니다. Unix/Linux 기반을 비슷하니 알아서(?) 하세요. ^^;


일단 받은 Ant 압축파일을 C:\Ant 에 풀어 놓고 시작해봅시다. 하위 디렉토리는 bin,doc,lib 등이 있겠죠. ^^ (Win 9x 시리즈에서는 환경변수에 들어가는 긴 파일명이 문제가 될 수 있으니 위와 같이 C:\Ant 에 설치하는 것이 좋습니다.)

PATH 환경변수에 Ant 아래에 bin 디렉토리를 추가합니다. 즉 C:\Ant\bin 을 추가합니다.

ANT_HOME 이라는 환경 변수를 만들고 그안에 Ant 가 설치된 디렉토리 값을 넣습니다. 즉 C:\Ant 를 넣습니다.

JAVA_HOME이라는 환경변수에는 JDK가 설치된 디렉토리를 추가합니다.

Windows Shell


set ANT_HOME=c:\ant
set JAVA_HOME=c:\jdk1.3.1_01
set PATH=%PATH%;%ANT_HOME%\bin


Unix(Linux) (bash)

export ANT_HOME=/usr/local/ant
export JAVA_HOME=/usr/local/jdk-1.3.1_01
export PATH=${PATH}:${ANT_HOME}/bin


Optional Tasks

Ant 는 다양한 Optional Tasks를 제공합니다. 일단 Task 라는 말이 앞으로 많이 나올텐데 Glossary 를 참고하세요. 예를들면 CVS 에 소스를 업데이트 해주는 Optional Task 가 있을 수 있고, 또 .NET 컴파일을 한다던지.. 기타 등등 다양한 Task 가 있습니다. (이에 대한 예제로는 AntTask를 참조)



Running 이제 Ant 를 실행하는 방법에 대해서 알아보자. Ant를 실행하는 것은 마치 make 명령을 내리는 것처럼 쉽다. Ant 에서 중요한 것은 make에서 "Makefile" 을 만들듯이 Build 파일을 잘 만드는 것이 중요합니다. Build 파일을 만드는 것에 대해서는 나중에 알아보기로 하고 일단 실행하는 방법부터 알아보죠.

일단 쉘에서 실행하는 간단한 형태는 다음과 같습니다.(여기서 '%'는 쉘을 의미합니다.)


% ant

이것은 현재 디렉토리에 build.xml 이라는 파일을 Build File 로 해서 Build 를 하겠다는 것입니다. build.xml 파일이 없다면 에러를 출력하겠죠? ^^

% ant -buildfile test.xml

이것은 build 파일을 test.xml 이라는 파일을 build 파일로 사용해서 build 하겠다는 의미입니다.

% ant -buildfile test.xml dist


이것은 바로 위에 있는 것에다가 dist라는 것이 붙었는데 이것은 target 을 나타냅니다. Unix/Linux 에서 make 명령으로 컴파일 해보신 분들을 아실껍니다. 보통 make 명령으로 컴파일 하고 make install 명령으로 인스톨을 하죠? 거기서 쓰인 install 이 target 입니다. Ant 에서는 Build 파일 안에 다양한 target 을 둘 수 있습니다. 예를 들면 debug 모드 컴파일과 optimal 모드 컴파일 2개의 target 을 만들어서 테스트 할 수 있겠죠? ^^

% ant -buildfile test.xml -Dbuild=build/classes dist

위의 예에 하나가 추가됐죠? -D 옵션은 Build 파일의 Property task 와 같은 역할을 합니다. 즉 Build File 내부에서 사용되는 일종의 변수를 선언한다고 볼 수 있겠죠? ^^


직접 실행하기
실행 파일 ant는 Unix 계열에서는 shell 스크립트로 Windows 계열에서는 ant.bat 라는 배치파일로 배포됩니다. 내부에 보면 java 프로그램을 실행하는데, 다음과 같이 자신이 직접할 수도 있습니다.

% java -Dant.home=c:\ant org.apache.tools.ant.Main [options] [target]


Buildfile(build.xml) 을 만들어보자 Ant 를 다룰줄 안다는 말은 즉, Build File 을 만들줄 안다는 의미와 같다. Build File 은 파일이름에서도 알 수 있듯이 xml 을 기반으로 하고 있다. 예제로 참조해볼만한 화일로 Ant/TaskOne, Ant/BuildTemplateExample 이 있다. 해당 화일을 보면서 설명을 읽으면 편할것이다.


--------------------------------------------------------------------------------

project 태그

일단 제일 처음 나오는 Root Element 로는 project 태그로 프로젝트 정의를 하는 곳이다.

Attribute Description Required
name 프로젝트의 이름 No
default default target 명을 넣는 곳이다. ant 를 실행할 때 target 을 지정하지 않으면 여기서 지정한 target 으로 실행한다. Yes
basedir 프로젝트의 base 디렉토리를 말한다. ant 내부에서 사용되는 모든 path 들은 이 디렉토리를 기반으로 한다. No


추가적으로 project 태그 뒤에 description 이란 태그를 사용하여 Project 를 설명할 수 있다.


--------------------------------------------------------------------------------

target 태그

project 태그 다음에 올수 있는 태그로 아래 나오는 Task 들의 묶음이라고 생각하면 된다.
기존의 Makefile 이라던지 다른 Build 툴을 보면 의존관계(Dependency)라는 것이 있을 것이다. 즉, 배포(distribute)라는 target 을 수행하기 전에 compile 이라는 target 을 먼저 수행해야 하는 의존 관계가 발생할 수 있을 것이다. target 에서는 이런 의존관계(dependency)를 다음과 같은 방법으로 제공한다.


<target name="A"/>
<target name="B" depends="A"/>
<target name="C" depends="B"/>
<target name="D" depends="C,B,A"/>


위의 예를 보면 B 는 A 를 의존하고 있고, C 는 B를 D는 C를 의존하고 있다. 처음 시작하는 tag 라 D라고 했을 때, D 는 C에 의존하므로 C 를 실행하러 간다. C 를 보면 B 를 의존하므로 B 를 수행하고 B 는 A를 의존하므로 A 가 수행된다. 즉 이것의 수행 순서는 A,B,C,D 순으로 수행된다.
그리고 D 가 C 에 의존해서 A,B,C 를 수행하고 난 후에 다시 B 에 의존하게 된는데 B는 한번 수행했으므로 다시 실행되지 않는다. 이점을 유의하도록 하자. target 은 한번만 수행된다.

의존관계외에 target을 수행하기 위해서 조건을 걸어서 사용할 수 있다. 이는 "'if'"와 "'unless'" 라는 attribute 를 사용해서 할 수 있다. 형식은 다음과 같다.



<target name="build-module-A" if="module-A-present"/>
<target name="build-own-fake-module-A" unless="module-A-present"/>

Posted by 꿈꾸는자의 생각의파편들

펌 : www.javaservice.net

 

JDK의 ResourceBundle을 쓰건, Struts의 MessageResources를 쓰건 자바의 Properties
파일을 이용하는 이상 인코딩 문제는 피해갈 수가 없습니다. 실제 대부분의 프로퍼티
파일들은 각 시스템의 기본 인코딩으로 작성되는 반면 자바의 Properties는 무조건
ISO-8859-1 인코딩으로만 인식하고 읽기 때문에 이를 기반으로 한 대부분의 클래스들
역시 인코딩의 문제를 피해갈 수 없습니다.(ISO-8859-1로 인식할 수 없는 문자에
대해서는 유니코드로 인식합니다.) 따라서 원죄는 Properties에 있는 것이고 근본적인
해결책은 Properties에 현재의 load, store를 빨리 deprecated시키고 Reader, Writer
혹은 nio를 통해 설정파일에 입출력할 수 있는 메쏘드가 추가되는 것입니다.

그러나, 현실적으로 프로퍼티를 사용하는 곳은 너무나 많고 이를 모두 수정하기는
불가능에 가까운 일입니다. 따라서, 프로퍼티에서 읽을 때 인코딩 변환을 해주는
방법이 가장 현실적인 대안이라고 할 수 있겠습니다. 그렇다면 차선책으로 가장 좋은
것은 Struts에서 이 점을 반영한 패치를 내놓는 것입니다. 이건 동아시아권
개발자들이 참여해야할 부분이라고 생각됩니다. 그러나, 그렇다고 패치가 나오기까지
무작정 기다릴 수는 없겠죠. 그 패치가 다른 나라 개발자들의 동의를 얻을 수
있을지도 미지수이고요. (이 문제는 우리가 유니코드만 쓴다면 아무 문제가 안되는
것입니다. 사실 저 역시 우리도 어서 UTF-16이든 UTF-8이든 유니코드 기반의
인코딩으로 모든 소스들을 전환해야한다고 생각합니다.) 결국 마지막 남은 방법은
우리 개발자들의 몫이겠죠.

다행스럽게도 Struts의 MessageResources 클래스는 어느 정도 추상화가 되어
있습니다. 실제 구현하는 클래스는PropertyMessageResources입니다. 이놈의 코드를
살펴보면, 어떤 로케일로 getMessage를 호출했을 때 해당하는 로케일로 읽어둔
메세지가 없으면 그 때 해당 로케일의 프로퍼티 파일을 찾아서 읽게 되어 있습니다.
근데, 그냥 읽어서 Properties 객체로 갖고 있는 것이 아니라 새로운 HashMap 객체를
생성해서 이곳에 담습니다. (이 개발자도 Properties에서 Hashtable을 사용하는 것은
못마땅했던 모양입니다.) 덕분에 우리는 큰 퍼포먼스 저하 없이 쉽게 인코딩 변환할
할 방법을 찾을 수 있게 되었죠. HashMap으로 옮겨 담는 부분에서 Configuration
등에서 읽어온 인코딩으로 변환을 시켜주면 됩니다. 사실 이 작업을 getMessage를
오버라이드해서 해줄 것인지 HashMap에 옮겨 담는 과정에서 해줄 것인지 고민하긴
했습니다만 결국 중요한 것은 프로퍼티 파일 작성자의 의도가 담긴 객체로 남아 있는
것이라 생각해서 HashMap에 옮겨 담을 때 인코딩 변환을 하도록 구현했습니다.

아직도 문제는 남았습니다. 그렇다면 이 과정으로 Struts 소스를 고쳐서 새로
컴파일하고 사용하는 것이 바람직할까요? 제 생각엔 No입니다. 개발자 자신이
유지보수하는 것이 아닌 패키지를 제공 받아 사용할 때 이를 함부로 수정해서
사용하는 것은 많은 문제를 낳습니다. 당장 Struts 버전업할 때마다 새로 수정,
컴파일, 패키징 과정을 거쳐야하죠. 다행스럽게도 Struts의 개발자들은 이런 부분에
대해 세심한 배려를 해두었습니다. Factory 클래스를 교체할 수 있게 한 것이죠. 이런
배려는 여기 뿐 아니라 Jakarta 프로젝트 전반에 걸쳐 나타나고 있죠.(사실 Abstract
Factory 메쏘드 패턴을 사용할 때 당연히 따라오는 장점이기도 합니다.) 따라서
우리는 PropertyMessageResources와 PropertyMessageResourcesFactory를 상속 받아서
위에서 설명한 부분을 오버라이드하고 이 팩토리를 struts-config.xml에 설정해주면
됩니다. 다음과 유사하게 설정하면 됩니다.

<message-resources parameter="messages" factory="com.hangame.jwdf.util.NativePropertyMessageResourcesFactory"/>


상속 받아 추가된 클래스는 다음과 유사하게 작성하면 됩니다.

NativePropertyMessageResourcesFactory.java
package com.hangame.jwdf.util;import org.apache.struts.util.MessageResources;import org.apache.struts.util.PropertyMessageResourcesFactory;public class NativePropertyMessageResourcesFactory extends PropertyMessageResourcesFactory {		public NativePropertyMessageResourcesFactory() {		super();	}	public MessageResources createResources(String config) {		return new NativePropertyMessageResources(this, config, this.returnNull);	}}


NativePropertyMessageResources.java
package com.hangame.jwdf.util;import net.javaservice.jdf.util.CharConversion;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.apache.struts.util.MessageResourcesFactory;import org.apache.struts.util.PropertyMessageResources;import com.hangame.jwdf.ExceptionHandler;import com.hangame.jwdf.config.Configuration;import com.hangame.jwdf.config.ConfigurationException;import java.io.IOException;import java.io.InputStream;import java.io.UnsupportedEncodingException;import java.util.Iterator;import java.util.Locale;import java.util.Properties;public class NativePropertyMessageResources extends PropertyMessageResources {	Log log = LogFactory.getLog(NativePropertyMessageResources.class);	/**	 *	 */	public NativePropertyMessageResources(MessageResourcesFactory factory, String config) {		super(factory, config);	}	/**	 *	 */	public NativePropertyMessageResources(MessageResourcesFactory factory, String config, boolean returnNull) {		super(factory, config, returnNull);	}	/**	 * Load the messages associated with the specified Locale key.  For this	 * implementation, the config property should contain a fully	 * qualified package and resource name, separated by periods, of a series	 * of property resources to be loaded from the class loader that created	 * this PropertyMessageResources instance.  This is exactly the same name	 * format you would use when utilizing the	 * java.util.PropertyResourceBundle class.	 *	 * @param localeKey Locale key for the messages to be retrieved	 */	protected synchronized void loadLocale(String localeKey) {		if (log.isTraceEnabled()) {			log.trace("loadLocale(" + localeKey + ")");		}		// Have we already attempted to load messages for this locale?		if (locales.get(localeKey) != null) {			return;		}		locales.put(localeKey, localeKey);		// Set up to load the property resource for this locale key, if we can		String name = config.replace('.', '/');		if (localeKey.length() > 0) {			name += ("_" + localeKey);		}		name += ".properties";		InputStream is = null;		Properties props = new Properties();		// Load the specified property resource		if (log.isTraceEnabled()) {			log.trace("  Loading resource '" + name + "'");		}		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();		if (classLoader == null) {			classLoader = this.getClass().getClassLoader();		}		is = classLoader.getResourceAsStream(name);		if (is != null) {			try {				props.load(is);			} catch (IOException e) {				log.error("loadLocale()", e);			} finally {				try {					is.close();				} catch (IOException e) {					log.error("loadLocale()", e);				}			}		}		if (log.isTraceEnabled()) {			log.trace("  Loading resource completed");		}		// Copy the corresponding values into our cache		if (props.size() < 1) {			return;		}		synchronized (messages) {			Iterator names = props.keySet().iterator();			while (names.hasNext()) {				String key = (String) names.next();				if (log.isTraceEnabled()) {					log.trace("  Saving message key '" + messageKey(localeKey, key));				}				String convertedMessage = props.getProperty(key);				try {					Configuration conf = Configuration.getInstance();					convertedMessage = CharConversion.convert(props.getProperty(key), "ISO-8859-1", conf.get("native.encoding"));				} catch (UnsupportedEncodingException e) {					log.fatal("Invalid Encoding..");				} catch (ConfigurationException e) {					log.fatal("Configuration Error..");				}				messages.put(messageKey(localeKey, key), convertedMessage);			}		}	}			/**	 *	 */	public String getMessage(String key) {		String message = super.getMessage(key);		try {			Configuration conf = Configuration.getInstance();			Locale locale = new Locale(conf.get("native.locale.language"), conf.get("native.locale.country"));			message = getMessage(locale, key);		} catch (ConfigurationException e) {			ExceptionHandler.handle(e);		}		return message;	}}


좀더 생각해보면 더 좋은 해결책도 있을 것입니다. 일단 이 정도만 해도 struts에서
별 불편 없이 메세지를 그대로 사용할 수 있을 것입니다.
제목 : Re: xml 은 어떨까요N 글쓴이: 이희승(anoripi)   2003/10/30 23:08:06  조회수:26  줄수:21
잘 이해가 안가는데요 그러니까...프로퍼티즈 파일을 직접 에디터로 수정해서 한글 메시지 같은 것을 넣을 수 없다는문제점을 지적하신 것 같은데요. (\uXXXX 로 표현되는..)더 좋은 방법은 리소스 파일을 xml로 만들어서 쓰는게 아닐까 하네요.일단 XML 은 파서 측에서 엔코딩에 맞게 해석하고, 사람이 직접 수정할 수도 있고, XML 의 장점도 그대로 가져갈 수 있어서 좋다고 봅니다.  JSF cardemo 를 보면 JSF 의 메시지 리소스를 구현해 만든 XML 리소스 클래스가 있습니다.  그것을 참고해도 좋을 것 같네요.--what we call human nature in actually is human habit.--http://gleamynode.net/
제목 : Re: 글쎄요...N 글쓴이: 박영록(poci)   2003/10/31 00:00:02  조회수:8  줄수:12
움. 논쟁 거리가 될 수도 있는 문제를 끄집어내시는군요-_-개인적인 생각으론, XML도 충분히 좋은 선택이나 그렇다고해서 Properties보다 나은선택이라고 말할 수는 없다..정도인 것 같습니다.XML을 쓸 때는 아무래도 그 무게와 복잡성을 고려하지 않을 수 없고, 또 XML을 쓰면서Properties 수준의 key-value 구조만 사용한다면 XML을 쓴 이유가 희석되겠죠.근데 사실 제가 제기한 문제는 이게 아니죠. Properties의 문제를 지적하긴 했지만그건 struts MessageResources가 뜻대로 동작하지 않는 원죄가 Properties에 있다는걸 말하기 위한 거지 Properties 자체의 문제를 해결하자는 것이 목적인 건 아니었죠.struts에서 bean:message 태그를 한글 문제 걱정 없이 쓰기 위한 방편 정도로 보면잘 이해가 안간다는 말을 하실 정도는 아닐 겁니다.
제목 : Re: 글쎄요...N 글쓴이: 이희승(anoripi)   2003/10/31 00:51:50  조회수:11  줄수:13
잘 이해가 안간다는 말은 음..> 프로퍼티즈 파일을 직접 에디터로 수정해서 한글 메시지 같은 것을 넣을 수 없다는> 문제점을 지적하신 것 같은데요. (\uXXXX 로 표현되는..)이게 긴가 민가 하다는 이야기였습니다. ^^--what we call human nature in actually is human habit.--http://gleamynode.net/
제목 : Re: XML 사용해서 성공했습니다N 글쓴이: 박원호(guest)   2003/11/03 10:05:35  조회수:62  줄수:33
메세지 리소스 문제로 저도 고민하다가,XML 가지고 해결하는 방향으로 했습니다.PropertyMessageResources 클래스 대신에MessageResource 클래스를 상속받은 XMLMessageResource 라는 클래스를 작성해서해결했습니다.위에 박영록님이 말씀하신데로Property 정도의 수준으로 XML을 이용하기에는 낭비같지만,다국어 처리에는 이게 가장 쉽고 편한 방법인 것 같습니다.그리고, 데이터 형태도 "CDATA" 타입을 사용하면메세지 안에 내용도 HTML과 긴 내용도 사용이 가능합니다.리소스 관리 측면에서는,처음에 Resource가 초기화 될때 한번만 XML 파싱을 하고,로딩이 끝나면 내용을 "List" 구조에 넣어 두게 되므로성능에서는 큰 차이는 없을 듯 합니다.소스 파일은 첨부된걸 참고하세요.<message-resources null="false"   factory="com.em.struts.util.XMLMessageResourcesFactory"   parameter="com.em.strutsfile.ApplicationResources" />struts-config.xml 파일에 위의 내용을 추가해주셔야 합니다.그리고, 현재 첨부된 소스 파일은 JDOM을 이용해서 구현하였습니다.(XML 처리를 쉽게 하기 위해서.)필요하시다면 JAXP 등으로 구현하셔도 별로 어려움은 없을 듯 합니다.참고하세요.

Download XMLMessageResources.zip (3120 Bytes) XMLMessageResources.zip (3120 Bytes)
Download ApplicationResources.xml (1448 Bytes) ApplicationResources.xml (1448 Bytes)
Posted by 꿈꾸는자의 생각의파편들

 

 

출처 : www.jongsclub.com

 

 
자카르타 서브프로젝트 대강 흩어보기
[ 조회수: 553 ]
 

jakarta.apache.org 혹은 아파치 서브프로젝트 한글화 프로젝트인 http://jakarta.apache-korea.org/ 에


가시면 보다 상세한 정보를 얻을수 있습니다.


** 이페이지는 자카르타-서울 프로젝트에서 번역한 내용들의 서두부분만 발췌해온것에 불과합니다.그냥 한눈에 보기 편하달까?


 


 


 


Apache Ant  아파치 앤트 

  아파치 앤트는 Java기반의 빌드 도구입니다.
  make, gunmake,nmake,jam .. 같은 기존의 툴들은 멀티 플랫폼
  에서 소프트웨어를 개발하는것을 고려하지 못했지만, 앤트는
  쉘기반 명령어 대신 자바클래스를 사용하여 다양한 환경에서 이용및
  확장 되고 xml을 기반으로 다양한 기능을 제공합니다. 









Avalon은 공통의 프레임워크와 자바 언어로
작성된 어플리케이션의 컴포넌트를 생성, 디자인,
개발 및 유지하기 위한 프로젝트입니다....



 


자카르타 캑터스


  캑터스는 서버측 자바 코드(서블릿, EJB, 태그, 필터 등)을
   단위 시험하기 위한 간단한 시험 골격중의 하나입니다.


 


 


 


Commons


Commons는 자카르타의 새로운 서브프로젝트로서 재사용가능한 자바 콤퍼넌트들의 모든 측면에 포커스를 맞추고 있습니다.


자카르타 Commons 프로젝트는 두 부분으로 구성됩니다:




콤퍼넌트 페이지는 현재 Sandbox와 Commons Proper 둘 다에서 이용가능한 콤퍼넌트들을 나열하고 있습니다.


 


 


James - Java Apache Mail Enterprise Server


자바 아파치 메일 엔터프라이즈 서버(일명 아파치 제임스)는 100% 순수 자바 서버이며, 현재 사용 가능한 오픈 프로토콜(SMTP, POP3, NNTP)에 완전하고 이식가능하게 설계된 엔터프라이즈 메일 엔진 솔루션이다.


또한, 제임스는 메일 애플리케이션 플랫폼이다.
제임스 프로젝트는 Apache Mailet API를 주관하고, 이 메일 애플리케이션 플랫폼 API의 구현을 제공한다.


제임스는 아파치 아바론 애플리케이션 프레임웍에 기반하였다. (아바론에 관한 더 많은 정보를 위해, 이곳을 참고하라. http://jakarta.apache.org/avalon)


 


 


 


 


 


The log4j projectLog4j를 사용하면 애플리케이션 바이너리를 수정하지 않아도 런타임시에 로깅 작업이 가능합니다. Log4j 패키지는 로깅 문장이 퍼포먼스 저하를 야기시키지 않는 채로 완성된 코드에 남아있을 수 있도록 설계되었습니다. 로깅 동작의 제어는 애플리케이션 바이너리를 건드리지 않고, 설정 파일만을 편집함으로써 가능합니다.













POI 프로젝트는 마이크로소프트 OLE 2 복합도큐먼트포맷형식의 파일을 순수 자바를 이용하여 핸들링하는 APIs로 구성되어있습니다.


OLE 2 복합도큐먼트포맷형식의 파일은 마이크로소프트 엑셀 혹은 워드파일 등의 대부분의 오피스파일들입니다. 




                                                                 


 Struts는 전형적 Model-View-Controller(MVC) 디자인 패러다임의 변화, 즉 Model2 접근법에 기반한 어플리케이션 아키텍쳐를 권장합니다. Struts는 자체적으로 컨트롤러 컴포넌트를 제공하며, Model과 View를 제공하기 위한 다른 기술들을 통합합니다. Model의 측면에서, Struts는 엔터프라이자 자바 빈즈, JDBC, 그리고 Object Relational Bridge를 포함한 어떠한 표준 데이타 접근 기술과도 상호작용 할 수 있습니다. View에 있어서 Struts는 자바서버 페이지, Velocity 템플릿, XSLT, 다른 표현 시스템과 잘 작동합니다.






이 프로젝트는 JSP커스텀태그 라이브러리와 TLV(TagLibraryValidator)클래스와 태그라이브러리를 지원하는 페이지제작도구와 같이 이 프로젝트와 관련있는 프로젝트들의 오픈소스 보관소이다. 태크라이브러리의 전반적인 설명은 여기를 보면된다. JSP(tm) 태그라이브러리.






Velocity

벨로시티는 자바기반의 템플릿 엔진이다.


벨로시티를 이용하면 기본적으로 제공되는 자바코드들과 템플릿으로 보다쉽게 웹 사이트를 개발하수 있게 되며, 궁극적으로는 jsp난 php를 대체하는 효과를 목표로 하고 있다.



 


Alexandria
 알렉산드라는 오픈소스 프로젝트시 CVS/Javadoc/Source code/Documentation 관리시스템 으로 이용하려한다. 이것의 목표는 프로젝트시 코드를 공유하고 소스코드를 이해하기 쉽게 돕는 광범위한 문서와소스의 체제 시스템을 구축하는 것이다.  ( 영어가 딸려서 좀 이상함 -_-?)


 


Element Construction Set



 


ecssms Element Construction Set  말그대로 HTML이나 XML관련 마크업 언어의 기능 요소들을 구현하기 위한 자바 API이다. 하지만 확장성이 좋기때문에 다른 마크업 언어 또한 역시 잘 지원한다.


 


 


 


 


 


 


 


The Jakarta Slide Project 
 내용관리 구성 시스템 즉 CMS를 구현하는  low-level의 문서 관리 구조 이다. 슬라이드는 추상적인 여러 가지 데이터들을 계층적으로 분산시켜 저장할수 있고, 보안,잠금,내용, 버전관리 등도 지원한다.
슬라이드가 우수한것은 서블릿으로 구현된 WebDAV 접속 모듈을 지원하기 때문이다. 

Posted by 꿈꾸는자의 생각의파편들

출처 : www.javaservice.net

 

 

이번 개발시에 cvs와 ant를 이용 웹 어플리케이션을 개발 하려고 합니다. 시나리오는 다음과 같습니다.1. cvs를 이용해 파일의 형상관리를 한다. 서버는 개발서버를 사용한다.2. 개발자들이 cvs 레파지토리에 올리고 브라우져로 바로 확인 할 수 있도록   레파지토리에 있는 내용을 자동으로 웹 어플리케이션에 올린다.3. 개발자들이 웹 브라우저에서 변경 사항을 확인한다.웹 서버와 cvs 레파지토리는 같은 서버입니다. 2번 단계에서 수정사항을 자동으로레파지토리에서 웹 어플리케이션 디렉토리로 복사하고 자바 파일(클래스 파일은레파지토리에 저장하지 않는 경우)인 경우 컴파일까지 자동으로 하려고 하는 부분에서 ant를 사용할 수 있을 것 같은데 이부분을 어떤 식으로 해결해야할지 궁금합니다. 비슷한 방법으로 사용하시는 분께 도움 구합니다.
제목 : Re: CVS와 ANTN 글쓴이: 손권남(kwon37xi)   2004/02/15 20:14:36  조회수:87  줄수:34
우리 회사에서 쓰는 ant 파일입니다.모듈 이름을 proejct 라고 할 때의 가정입니다.CVS 의 모듈중에 바뀐 것들을 가져오고, 그 중 WEB-INF/classes 에 있는 자바 파일들응 자동으로 컴파일을 합니다.마지막의 copy 부분은 저희가 프로그램 짤때 *.properties 와 *.xml, *.xsl 들을리소스로서 읽으들이기 때문에 그것들도 또한 classes 디렉토리로 옮겨주는 것입니다. <target name="build" depends="prepare">                <cvs cvsRoot=":pserver:anoncvs@localhost:/var/cvs"                        package="project"                        />                <cvs command="update -A -d" dest="."/>                <javac srcdir="project/WEB-INF/src"                        destdir="project/WEB-INF/classes"                        debug="on"                        failonerror="false"                        deprecation="on">                        <include name="**/*.java"/>                        <classpath refid="xlms.classpath"/>                </javac>                <copy todir="project/WEB-INF/classes" overwrite="true">                        <fileset dir="project/WEB-INF/src">                                <include name="**/*.xml"/>                                <include name="**/*.xsl"/>                                <include name="**/*.properties"/>                        </fileset>                </copy>        </target>나도 expert가 될날이..
제목 : Re: 감사합니다..N 글쓴이: 손님(guest)   2004/02/15 22:32:33  조회수:10  줄수:2
감사합니다..많은 도움이 되겠군요...^^..잘사용하겠습니다.
제목 : Re: 톰캣에 있는 추천 웹개발 가이드N 글쓴이: 허광남(heogn)   2004/02/17 09:54:35  조회수:37  줄수:14
웹 개발 경험을 토대로 정리된 개발 가이드입니다.소스 디렉토리, 디플로이 디렉토리, cvs 커맨드 사용법, build.xml 샘플 스크립트 등의 내용이 있습니다.문서 작성자는 Struts를 만든 Craig R. McClanahan 아저씨입니다.http://jakarta.apache.org/tomcat/tomcat-4.1-doc/appdev/processes.html번역링크http://jakarta.apache-korea.org/tomcat/tomcat-4.1-doc/appdev/processes.html----------------------------------------------------jsp/서블릿 정보공유; http://www.okjsp.pe.krjakarta 문서 한글화; http://jakarta.apache-korea.org----------------------------------------------------

Posted by 꿈꾸는자의 생각의파편들
2005.02.13 17:23

[펌] Forrest Dev.../플밍 관련 자료2005.02.13 17:23

Forrest...

프로젝트 문서화를 해주는 유틸리티라네요...

한번 사용해 봐야 겠네요...

 

http://xml.apache-korea.org/

 

포레스트로 빌드를 하면 위 페이지 같이 문서화 할 수 있다는군요...

pdf로도 변환이 되구...

 

참고사이트

 

Forrest 프로젝트 사이트

http://xml.apache.org/forrest/

 

Cocoon프로젝트 사이트

http://cocoon.apache.org/

 

Cocoon한글 번역 사이트

http://cocoon.apache-korea.org/

 

 

Posted by 꿈꾸는자의 생각의파편들

 

출처 : http://www.jlab.net/

 

 

언어팩을 설치해서 한글 플러그인 이클립스를 사용하다 보면 영문 플러그인 이클립스가 필요할 경우가 생깁니다.
 
eclipse -nl en_US
 
이렇게 실행할 경우 영문으로 이클립스 플랫폼이 시작됩니다. 단축아이콘이나 심볼릭 링크만 만들어두면 편리하게 사용할 수 있습니다.

Posted by 꿈꾸는자의 생각의파편들

퍼온것 : http://joldo.com/board.do?boardId=java&act=read&pkIdx=10

 

역자: noct ( http://www.noct.pe.kr/ )
원본 : http://www.vipan.com/htdocs/log4jhelp.html
 
                      System.out.println 을 사용하지 말고 Log4j 를 사용하라.




                      Log4j를 사용하기 위한 빠른 시작


- log4j 소프트웨어(약 2.3MB)를 다운로드해서 log4j.jar (약 156KB)를 추출하라.
logging 메소드가 필요한 클래스들을 찾을 수 있도록 log4j.jar 파일을 어플리케이션의 클래스패스에 포함시켜라.
(필자는 log4j.jar 파일을 자바 설치 디렉토리 밑의 lib/ext 디렉토리에 카피했다. 왜냐하면 자바는 자동적으로
그 디렉토리에서 얻어오고 클래스패스에 추가하기 때문이다.)

- 다음의 예제코드를 TestLogging.java 로 저장해여 클래스패스로 지정된 디렉토리에 위치시키라.

import org.apache.log4j.*;

// log4j 사용방법
public class TestLogging {

    // loggin 카테고리를 초기화한다.  여기서 THE ROOT CATEGORY 를 얻는다
    //static Category cat = Category.getRoot();
    // 또는 사용자 정의 category를 얻는다
    static Category cat = Category.getInstance(TestLogging.class.getName());

    // 여기서부터 로깅한다!  해당메소드들: cat.debug(로그메세지문자열),
    // cat.info(...), cat.warn(...), cat.error(...), cat.fatal(...)

    public static void main(String args[]) {
        // 몇가지 로깅 메소드들.
        cat.debug("Start of main()");
        cat.info("Just testing a log message with priority set to INFO");
        cat.warn("Just testing a log message with priority set to WARN");
        cat.error("Just testing a log message with priority set to ERROR");
        cat.fatal("Just testing a log message with priority set to FATAL");

        // 대체할 수 있지만 불편한 형식
        cat.log(Priority.DEBUG, "Calling init()");
       
        new TestLogging().init();
    }

    public void init() {
        java.util.Properties prop = System.getProperties();
        java.util.Enumeration enum = prop.propertyNames();

        cat.info("***System Environment As Seen By Java***");
        cat.debug("***Format: PROPERTY = VALUE***");

        while (enum.hasMoreElements()) {
            String key = (String) enum.nextElement();
            cat.info(key + " = " + System.getProperty(key));
        }
    }

}

Log4j 는 기본적으로 다섯개의 우선권(이하 Priority) 등급으로 메세지를 로깅할 수 있다.

1. 완성된 어플리케이션에서는 출력되지 않아야 할 디버깅 메세지들을 쓰기위해 debug 를 사용하라.
2. 어플리케이션의 verbose 모드에서 출력될만한 메세지들을 로깅하기 위해 info 를 사용하라.
3. 어플리케이션이 이상없이 계속 실행될 수 있는 정도의 경고메세지를 로깅하기 위해 warn 을 사용하라.
4. 어플리케이션이 그럭저럭 돌아갈만한 정도의 에러베세지를 로깅하기 위해 error 를 사용하라.
   예를들어 관리자에 의해 주어진 설정인자가 올바르지 않아 하드코딩된 기본값을 사용해야 할 경우.
5. 로깅후에 애플리케이션이 비정상적으로 종료될 치명적인 메세지를 로깅하기 위해 fatal 을 사용하라.


- 다음의 몇줄을 log4j.properties 라는 이름의 파일로 저장하고 TestLogging.class 파일과 같은 디렉토리에 저장하라.
(TestLogging.java 파일을 컴파일 한 후에)
Log4j는 기본적으로 getRoot()가 호출되거나 getInstatnce("category_name") 이 코드상에서 호출되었을 때
어플리케이션의 클래스패스에서 이 파일을 찻을 것이다.


log4j.rootCategory=DEBUG, dest1
log4j.appender.dest1=org.apache.log4j.ConsoleAppender
log4j.appender.dest1.layout=org.apache.log4j.PatternLayout


PatternLayout 은 기본적으로 사용자가 작성하는 메세지와 개행을 의미하는 %m %n 의 형태이다.
이것은 Log4j의 메소드들의 여러 장점중에 쓰기에 더 짧다는 것을 제외하고는
Java의 System.out.println(...) 메소드와 정확히 동일하게 출력된다.

- TestLoggin.java 파일을 컴파일 하고 실행했을 때 다음과 유사한 출력을 얻게 될 것이다.

Start of main()
Just testing a log message with priority set to INFO
Just testing a log message with priority set to WARN
Just testing a log message with priority set to ERROR
Just testing a log message with priority set to FATAL
Calling init()
***System Environment As Seen By Java***
***Format: PROPERTY = VALUE***
java.runtime.name = Java(TM) 2 Runtime Environment, Standard Edition
sun.boot.library.path = c:\jdk1.3\jre\bin
java.vm.version = 1.3.0_02
java.vm.vendor = Sun Microsystems Inc.
... and so on



- 만약 메세지 다음에 priority 를 출력하고 싶다면(당신이 지정한 메세지에)
  다음 라인을 log4j.properties 파일에 추가하고 저장하면 된다.

log4j.appender.dest1.layout.ConversionPattern=%-5p: %m%n


기본값인 %m %n 을 오버라이드 한다. %p 는 메세지의 priority를, %m은 메세지 자체를,
%n 은 개행문자를 출력할 것이다.
당신은 어떤 자바코드를 바꿀필요도 없고, TestLogging.java 파일을 재컴파일 할 필요도 없이
단지 properties 파일만 바꾸면 된다.

DEBUG: Start of main()
INFO : Just testing a log message with priority set to INFO
WARN : Just testing a log message with priority set to WARN
ERROR: Just testing a log message with priority set to ERROR
FATAL: Just testing a log message with priority set to FATAL
DEBUG: Calling init()
INFO : ***System Environment As Seen By Java***
DEBUG: ***Format: PROPERTY = VALUE***
INFO : java.runtime.name = Java(TM) 2 Runtime Environment, Standard Edition
INFO : sun.boot.library.path = c:\jdk1.3\jre\bin
INFO : java.vm.version = 1.3.0_02
INFO : java.vm.vendor = Sun Microsystems Inc.
... and so on


만약 DEBUG 나 INFO 메세지에 질려서 이것들이 출력되지 않기를 원하고, 다른 메세지들을 여전히 출력되길 원한다면
(예를 들어, 어플리케이션이 생산이 시작될 준비가 되었을 때) log4j.rootCategory=DEBUF, dest1 행을
log4j.rootCategory=WARN, dest1 으로 수정하면 된다.

위의 행은 WARN 보다 priority가 낮은 등급(DEBUG와 INFO 같은)의 메세지들을 제외하는 것이다.
수정하면 다음과 같이 출력될 것이다.

WARN : Just testing a log message with priority set to WARN
ERROR: Just testing a log message with priority set to ERROR
FATAL: Just testing a log message with priority set to FATAL



                               Log4j의 상세


- Log4j에는 세개의 주요한 컴포넌트가 있다. 이것들은 Categories, appenders 그리고 layouts 이다.
- Category를 초기화 시키고 그 후에 여러 로깅메소드를 호출하여 로그파일로 메세지를 보낸다.
- 하나의 Category는 하나 혹은 그 이상의 대상(목적지)에 로그하도록 설정된다.
   Log4j 에서는 이 대상을 "appenders" 라고 부른다. 왜냐하면 이 클래스들은 기본적으로 메세지 문자열을 로그의 끝에
   더하기(append) 때문일 것이다.
   Log4j 는 한번의 로깅을 호출함으로 로그메세지를 콘솔, 텍스트파일, html 파일, xml 파일, 소켓이나
   심지어는 Windows NT Event Log 등 모든 것으로 보낼 수 있다.
   거기다 로그메세지를 이메일로 전송할 수도 있다.(예를 들어 치명적인 에러가 날 경우 사용하기 적당하다)

- 몇몇 appender 클래스들을 나열하자면 ConsoleAppender, FileAppender, SMTPAppender, SocketAppender,
   NTEventLogAppender, SyslogAppender, JMSAppender, AsyncAppender and NullAppender 가 있다.

- appender 는 실제로 로그에 쓰기 전에 메세지 형식을 만드는 layout 을 사용한다.
   예를들어 HTMLLayout 은 모든 메세지를 보기좋은 HTML 테이블 형식으로 만들것이다.

-  Log4j는 날짜, 시간, 메세지 priority(DEBUG, WARN, FATAL 등), Java 클래스명,
   소스코드의 행번호, 메소드명, Java 스레드의 이름 등등을 당신이 보내는 로그메세지에 더할 수 있다.
   로그하는 것은 appender 에 설정된 layout 에 명시된대로이다.


- Category 는 사용자가 지정하며 대소문자를 구별하는 도트로 구분된 문자열이다. 완전한 이름의 자바 클래스를 얻고
  그것을 Category 이름으로 지정하기 위해 보통 클래스명.class.getName() 을 사용한다.
  (게다가 runtime 시에 category 명을 로깅하는 것이 class 명을 로깅하는 것보다 훨씬 더 빠르다.
  만약 빠르면서도 클래스명을 로깅하고 싶다면, class명을 category의 이름으로 지정하고, 카테고리 이름을 로깅하라!)

- category명의 각각의 단어는 그 다음 이어지는 단어의 ancestor(조상)라 하고, 바로 다음 단어의 parent(부모)이다.
  Log4j 는 특정 category 에서 오버라이드 될때까지 ancestor(조상)으로부터 priority와 appender 를
  상속하는 개념이 있기 때문에, 이는 매우 중요하다.

- XML 문서의 root 와 같이 log4j 에는 언제나 이름이 없는 root category 가 존재한다.
  category 를 초기화하기 위해 Category 클래스의 static 메소드를 사용한다.

Category cat = Category.getRoot();
Category cat2 = Category.getInstance("your.category.name");


\\특정 category 이름을 위해 Category.getInstance(...) 메소드는 항상 정확히 동일한 Category 객체를 리턴한다.
따라서 Category 를 초기화해서 차례로 돌릴 필요가 없다. 대신
필요한 어느곳이든 Category.getInstance("wanted.category.name"); 을 써주면 된다.

- "com.comp"라는 패키지의 "TestApp" 라는 이름의 클래스로 Category를 인스턴스화 하는 전형적인 방법은

static Category cat = Category.getInstance(TestApp.class.getName());


TestApp 는 클래스이름 자체이지 인스턴스가 아니라는 것을 명심하라. 또한 TestApp.class 구문은 TestApp 클래스의
새로운 인스턴스를 생성하지 않는다.

- Priority 클래스의 다섯개 priority(우선권) 상수는 우선권이 감소하는 차례로 FATAL, ERROR, WRAN, INFO, DEBUG 이다.
원한다면 (Priority 클래스를) 상속받음으로써 그 이상의 priority를 만들 수 있다.

- category 들에게 priority 를 지정할 수 있지만 꼭 그럴 필요는 없다.
  만약 priority 를 지정하지 않으면 log4j 는 상속관계의 계층구조를 따라서 가장 먼저 할당된 것을 찾아 사용한다.
  root category는 항상 지정된 priority가 있다.(기본값은 Priority.DEBUG),
  따라서 모든 category 들은 항상 priority를 갖도록 보장되어 있다.

- Category 클래스의 logging 메소드의 사용

// 일반적인 로깅 메소드 (불편함)
public void log(Priority p, Object message);

// 편리하게 사용할 수 있는 일반적인 로깅 메소드
public void debug(Object message);
public void info(Object message);
public void warn(Object message);
public void error(Object message);
public void fatal(Object message);


- log4j는 category의 log(...) 메소드가 지정한 priority가 category가 할당되거나 상속받은 priority와
  같거나 더 높을 때에만 로깅한다.

Category cat = Category.getRoot();
cat.setPriority(Priority.ERROR);
// Later...
//cat.info("Started processing..."); //Will not log
cat.error("User input is erroneous!"); //Will log
cat.fatal("Cannot process user input.  Program terminated!"); //Will log



                             Log4j 설정


- 로깅이 가능해지기 전에, 첫째로 log4j 를 설정해야한다. Log4j 를 설정한다는 것은 category(loggers) 들에
  appender (목적지/대상/핸들러)들을 더하고 각각의 appender 에게 layout(전체구성)을 지정하는 것이다.

- category 들은 어떤 순서로든 생성되고 설정될 수 있다. 특히 category 는 그것의 decendants(자손들)을 찾아
  연결할 수 있고, 심지어 그것들보다 나중에 인스턴스화 될 수 있다.

- 일반적으로 Log4j 는 어플리케이션이 초기화되는 동안 보통 설정파일을 읽어들여 한번만 설정된다.

- 또한 category 객체의 addAppender() 메소드를 사용함으로써 특정 appender 에 로그하도록 프로그래밍적으로
  category를 설정할 수 있다. 원하는 만큼 더할 수 있다(원하지 않는다면 하지 않아도 상관없다)
  이 메소드는 보통 추천하지 않는다 왜냐 하면 소스파일을 수정하여 다시 컴파일 해야 하기 때문이다.
  java 프로퍼티 파일이나 XML 파일 같은 외부 설정파일을 이용하는 것이 더 좋은 방법이다.

- appender 들은 singleton 이 아니라 추가된다는 것을 주의하라.
  category 는 기본적으로 그것의 조상에서 부터의 모든 appender 들을 물려받는다.
  만약 appender 를 category에 더하고 그것의 기반이 되는 동일한 스트림에 쓴다면(콘솔, 같은 파일 등)
  같은 로그메세지가 두번 이상 로그될 것이다.
  게다가 만약 계층구조의 두개의 category 들이 같은 appender 이름을 사용한다면,
  Log4j 는 그 appender 들에 두번 쓸 것이다.
  appender 로부터 물려받는 것을 불가능하게 하기 위해 category의 cat.setAdditivity(false) 메소드를 사용하라.
  그러면 로그 메세지는 해당 category에 특별히 설정된 appender 로만 보내질 것이다.

- 정적 메소드인 BasicConfigurator.configure() 메소드는 System.out.println(...) 구문이 그러하듯 콘솔에 로깅한다.
  이 메소드는 루트 category 에 ConsoleAppender 를 붙여 콘솔에 프린트 하는 기능을 가지고 있다.
  출력은 %-4r [%t] %-5p %c %x - %m%n 으로 세팅된 PatternLayout 을 사용하여 구성된다.
  이 메소드는 log4j.properties 파일을 사용하는 것이 더 간단하고 유연하기 때문에 그다지 필요하지 않다.

- log4j 를 설정하는 기본 파일은 log4j.properties 이다.
  이 파일을 어플리케이션의 클래스패스에 지정된 어느곳이든 위치시킨다.

- Java 프로퍼티 파일에서 설정 정보를 읽어오려면 정적메소드 중 하나인 PropertyConfigurator.configure(...)
  메소드를 사용하라. 이미 설정되어 있는 설정은 지워지지도 재설정되지도 않는다. 이 메소드를 사용하려면
  정적메소드인 BasicConfigurator.resetConfiguration() 메소드를 먼저 호출하라. 이 메소드 사용은 코드를 길고
  복잡하게 할 수도 있다. 초보자는 각각의 어플리케이션의 루트디렉토리에 log4j.properties 파일 하나만 위치시켜라.

- log4j 예제 설정 파일
# root category의 priority 를 to DEBUG 로 설정하고 appender 를 A1 으로 지정한다.
log4j.rootCategory=DEBUG, A1

# A1 을 ConsoleAppender 로 지정(시스템 콘솔에 출력하는).
log4j.appender.A1=org.apache.log4j.ConsoleAppender

# A1 을 PatternLayout 을 사용하도록.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

이 예제 파일은 BasicConfigurator.configure() 메소드를 사용한것과 완전히 같이 log4j를 설정한다. 그러나 이방법으로 하면
나중에 설정을 수정할 때에, 예를들어 DEBUG 를 FATAL로 프로퍼티 파일을 고치고 어떤 자바파일도 재컴파일 할 필요가 없다.

- 더 복잡한 log4j 설정파일

#### 두개의 appender를 사용하며, 하나는 콘솔에 로깅하고 다른 하나는 파일에 로깅한다.
log4j.rootCategory=debug, stdout, R

# priority가 WARN 보다 같거나 더 높은 메세지만 출력한다.
log4j.category.your.category.name=WARN
# Specifically inherit the priority level
#log4j.category.your.category.name=INHERITED

#### 첫번째 appender는 콘솔에 쓴다.
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

# 호출하는 파일명과 라인넘버를 출력하는 Pattern
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n

#### 두번째 appender 는 파일에 쓴다.
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=example.log

# 최대로그파일 크기를 조절
log4j.appender.R.MaxFileSize=100KB
# 집적하는 로그파일의 수 (여기서는 하나의 백업파일)
log4j.appender.R.MaxBackupIndex=1

log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n


이제 출력은 example.log 라는 파일에 덧붙여질 것이고, 이 파일은 크기가 100KB 가 될때 롤오버 될것이다.
롤오버가 일어날 때 구버전의 example.log 파일은 자동으로 example.log.1 파일로 바뀐다.
DailyRollingFileAppender 를 사용하여 파일을 매분, 매시간, 매일, 매주, 매달 또는 하루 2회씩 롤오버되게 할 수 있다.


- 서버 같이 오랫동안 실행되는 프로그램에서는 Java 프로퍼티 파일을 이용하여 환경설정을 하기 위해
  configureAndWatch(String configFilename, long delay_in_milliseconds)를 사용한다.
  Log4j 는 몇 밀리세컨드 마다 프로퍼티 파일이 변하는지를 계속 모니터링 하다가
  프로퍼티 파일이 변하면 설정을 업데이트할것이다.

- 프로그램 출시단계가 되면 빠른 성능을 위해 계층구조의 모든 category에서 특정 priority 이하의 모든 메세지를
  로깅하지 않도록 할 수 있다. 예를 들어, 아무것도 로깅하지 않으려면, log.diable=FATAL 을
  설정파일(property파일)에 명시해주면 된다.

단 log.disableOverride 프로퍼티가 false 로 세팅되어 있지 않다면 예외가 일어난다.
따라서 시스템 관리자는 log.disable을 오버라이드 할 수 있도록 환경설정 파일에
log.disableOverride=true 를 (일시적으로)명시하고 모든 메세지를 로그해서 생기는 문제를 조사해봐야 한다.




                               유용한 Layout 들


- 몇가지 layout 클래스들을 들자면 TTCCLayout, HTMLLayout, PatternLayout, SimpleLayout 그리고 XMLLayout이 있다.
- SimpleLayout 과 PatternLayout 클래스들은 자바의 Throwable 에러들과 예외를 무시한다.
  HTMLLayout과 XMLLAyout 은 그것들을 다룬다.
- SimpleLayout 은 로그 구문의 property 에 이어 "-" 이나오고 로그메세지가 나오는 구성이다. 예를 들어
 
  DEBUG - Hello world

- PatternLayout 은 C언어의 printf 함수와 유사한 변환 패턴에 따라 출력을 형식을 지정할 수 있게 한다.
  PatternLayout 의 변환 형식을 %r [%t] %-5p %c - %m%n 로 하면 다음과 같이 출력된다.

176 [main] INFO  org.foo.Bar - Located nearest gas station

- 가장 첫 필드는 프로그램이 시작된 후로부터 경과된 시간의 밀리세컨드 값이다.
- 두번째 필드는 로그 요청을 만든 스레드이다.
- 세번째 필드는 로그 구문의 priority 이다.
- 네번째 필드는 로그요청에 관련된 category의 이름이다.
- "-" 뒤의 문자열은 로깅메세지이다.

- 변환 형식에 어떤 문자도 삽입될 수 있다.
- 변환 문자들은 다음과 같다.
- %m : 당신이 지정한 메세지를 출력
- %p : 로깅 이벤트의 priority 를 출력
- %r : 어플리케이션이 시작되어 로깅이벤트가 일어날때까지의 경과시간을 밀리세컨드 값으로 출력
- %c : 로깅이벤트의 category를 출력한다. 예를 들어 category 이름이 "a.b.c" 일때 %c{2} 는 "b.c"를 출력하며 {2}는
        도트(.)로 구분된 category 이름의 마지막 두개의 컴포넌트를 의미한다.
        {n} 이 없으면 기본적으로 카테고리의 이름을 모두 출력한다.
- %t : 로깅 이벤트를 생성한 스레드 이름을 출력
- %x : 로깅이벤트를 발생시킨 스레드에 관련된 내포검사항목(Nested Diagnostic Context : NDC)을 출력한다.
        Java Servlet 과 같이 다수의 클라이언트가 분산된 스레드에 의해 다루어 질 때 유용하다.
- %n : 플랫폼 독립적인 개행문자를 출력한다. "\n" 또는 "\n\r" 등이 지정될 수 있다.
- %% : 하나의 % 기호를 출력한다.
- 경고 : 아래의 형식은 프로그램의 실행속도를 느리게 한다. 실행속도가 중요하지 않은 것이 아니라면 사용을 피하도록 한다.
- %d : 로깅이벤트가 일어난 날자(date)을 출력한다.
        date 변환 지정자는 날짜형식 지정자 뒤에 이어 나오는 brace({..}) 사이에 둘러쌓여 나온다.
        예: %d{HH:mm:ss,SSS} 또는 %d{dd MMM yyyy HH:mm:ss,SSS}
        만약 날자 형식 지정자가 주어져있지 않다면 ISO8601 형식으로 나타난다. 날짜형식 지정자는 자바의 속도가 느린
        SimpleDateFormat 클래스의 시간형식 문자열과 같은 문법을 수용했다.
        더 빠른 성능을 위해 %d{ISO8601}, %d{ABSOLUTE}, %{RELATIVE}(프로그램 시작 후 경과시간의 밀리세컨드값을 나타내며
        가장 빠르다) 또는 %d{DATE} 를 사용하며 각각은
        log4j의 ISO8601DateFormat, AbsoluteTimeDateFormat, RelativeTimeDateFormat, DateTimeDateFormat 날자형식을 사용한다.

- %l : 소스코드의 위치정보를 출력한다. %C. %M(%F:%L) 의 축약형이다.
- %C : 로깅요청을 일으킨 호출자의 완전한 클래스이름을 출력한다.
        예를들어 "org.apache.xyz.SomeClass"라는 클래스 이름이 있을때, %C{1} 은 "SomeClass"를 출력한다.
        {1} 는 "완전한 클래스이름의 마지막 하나의 구성요소를 출력하라" 는 뜻이다. 만약 {n} 이 없다면
        기본적으로 완전한 클래스 이름을 출력한다.
- %M : 로깅요청을 일으킨 메소드를 출력한다.
- %F : 로깅요청을 일으킨 파일 이름을 출력한다.
- %L : 로깅요청을 일으킨 곳의 행번호를 출력한다.


- 선택적으로 퍼센트 기호와 변환 문자 사이에 형식수정자(format modifier)를 사용하여 최소 필드넓이를 바꾸고,
  최대 필드 넓이와 필드 안에서의 문자의 정렬을 바꿀 수 있다.

- 필드 안에서 완쪽 정렬을 하기위해 마이너스 기호(-)를 사용한다. 기본적으로는 오른쪽 정렬이다(왼쪽에 여백을 둠)
- 최소 필드 넓이를 명시하기 위해 양의 정수를 사용한다. 만약 데이타 항목이 더 적은 문자를 가지고 있으면 최소넓이에
   도달할 때까지 오른쪽 똑은 왼쪽에 공백이 생긴다. 만약 데이터 항목의 길이가 최소 필드폭 보다 크면
   필드넓이가 데이터에 맞게 확장된다.

- 마침표 뒤에 나오는 양의 정수는 최대 필드폭을 지정한다. 만약 데이터항목이 최대필드폭보다 길면 나머지 문자들은
   데이터항목의 끝이 아니라 시작에서부터 지워진다.예를 들어 최대필드폭이 8이고 데이터 항목의 길이가 10개문자라면,
   데이터 항목 처음 두개의 문자는 지워진다. 이런 동작은 끝에서부터 잘라내는 C언어의 printf 함수와 차이가 난다.

- 예 :
- %20c : 최소 20문자 공간에서 category 이름을 (기본적인)오른쪽 정렬
- %-20c : 최소 20문자 공간에서 category 이름을 왼쪽 정렬
- %.30c : 만약 category 이름이 30문자보다 길면 (앞에서부터)자른다.
           최소폭이 없으므로 30문자보다 짧다고 해도 여백공간은 없다.
- %20.30c : category 이름이 20문자보다 짧으면 오른쪽 정렬을 하고, 30자보다 길면 시작부터 자른다.
- %-20.30c : category 이름이 20자보다 짧으면 왼쪽 정렬을 하고, 30자보다 길면 시작에서부터 자른다.
- %r [%t] %-5p %c %x - %m\n : 이 형식이 본래 TTCCLayout 이다.
- %-6r [%15.15t] %-5p %30.30c %x - %m\n : TTCCLayout과 다음의 형식을 제외하고 유사하다.
   상대시간이 6자가 안될때에 오른쪽에 여백을 두고, 스레드명이 15자가 안될때에
   오른쪽에 여백을 두고, 더 길때에는 자르며, category명이 30자가 안될때는 오른쪽에 여백을 두고 더 길때는 자른다.

- 고급 : 단지 log로 문자열만을 넘길 필요는 없다. 객체도 로그메세지에 넘길 수 있다.
         ObjectRenderer 를 implement 하면 객체를 문자열로 표시하여 appender 에 로깅한다.



                 Log4j 에서 Appender와 Layout 옵션의 Property keys

log4j 의 전체 옵션들

- log4j.configuration=app_config.properties : Category.getRoot() 나 Category.getInstance(...) 메소드를 처음으로 호출하여
  Log4j 의 초기화 과정을 마친다.("log4j.debug=true" 로 지정하여 초기화가 일어나는 것을 볼 수 있다)
  초기화되는 동안 Log4j 는 어플리케이션의 클래스패스에서 "log4j.properties" 파일이나
  property key를 통해 지정한 파일을 찾는다. 그러나 이것(설정파일을 지정하기 위해 설정한 property key)을 시스템 property로
  설정할 필요가 있다. 예를 들어 다음과 같이 프로그램을 구동한다.
    java -Dlog4j.configuration=app_config.properties ...

  왜냐하면 만약 설정파일에 세팅했다면 너무 늦기 때문이다.
  Log4j 는 기본 설정파일인 log4j.properties 파일을 읽기 위해 이미 시작했을 것이다.

- log4j.debug=true : 기본값은 false. log4j 를 설정하는 상세 정보를 출력한다.
- log4j.disable=INFO : 모든 category에서 여기 지정한 priority 보다 같거나 낮은 priority 메세지는 로깅하지 않는다.
  log4j.disableOverride 프로퍼티가 기본값인 false 일때에만 동작한다.
- log4j.additivity.your.category.name=false : 기본값은 true. appender를 ancestor(조상)으로부터 쌓이게 할지(true)
  그렇게 하지 않을지(false)를 지정한다.
- log4j.defaultInitOverride=false : Category.getRoot() 나 Category.getInstance(...) 메소드를 처음으로 호출하여
  Log4j 의 초기화 과정을 마친다.("log4j.debug=true" 로 지정하여 초기화가 일어나는 것을 볼 수 있다)
  초기화되는 동안 Log4j 는 어플리케이션의 클래스패스에서 "log4j.properties" 파일이나
  "log4j.configuration=app_config.properties" 프로퍼티를 통해 지정한 파일을 찾는다.
  만약 이것(프로퍼티를 통해 지정한 환경파일을 찾는 것)을 원하지 않는다면 이 프로퍼티를 true 로 세팅하라.
  그러나 이것을 시스템 property로 설정할 필요가 있다. 예를 들어 다음과 같이 프로그램을 구동한다.
  java -Dlog4j.defaultInitOverride=true ...
  왜냐하면 설정파일에 세팅했다면 이미 너무 늦기 때문이다.Log4j는 이미 그 파일을 읽기위해 시작되었을 것이다.
- log4j.disableOverride=false: 기본값은 false. 가끔 true로 설정하여 log.disable 프로퍼티를 무시할 수 있다.


ConsoleAppender 옵션들
- Threadhold=WARN: 이 appender는 category의 priority가 더 낮게 지정되어 있다고 할지라도 여기 명시된 priority보다
  낮은메세지들을 로깅하지 않을 것이다. 이것은 콘솔에 모든 메세지가 나타나는 동안 파일에 로깅되는 경우와 같이
  메세지의 숫자를 줄이는데 유용하다.
- ImmediateFlush=true: 기본값은 true. 로그메세지들이 전혀 버퍼되지 않는 것을 의미하며 대부분의 상황에 적당하다.
- Target=System.err: 기본값은 System.out


FileAppender 옵션들
- Threadhold=WARN: 이 appender는 category의 priority가 더 낮게 지정되어 있다고 할지라도 여기 명시된 priority보다
  낮은메세지들을 로깅하지 않을 것이다. 이것은 콘솔에 모든 메세지가 나타나는 동안 파일에 로깅되는 경우와 같이
  메세지의 숫자를 줄이는데 유용하다.
- ImmediateFlush=true: 기본값은 true. 로그메세지들이 전혀 버퍼되지 않는 것을 의미하며 대부분의 상황에 적당하다.
- File=mylog.txt : 로깅할 파일명. 앞부분에 경로를 나타내기 위해 ${some_property_key}
  (예를 들어 java.home 또는 user.home 과 같은 시스템 프로퍼티)를 사용할 수 있다. 사실 모든 옵션들의 프로퍼티키들은
  이런 종류의 값을 설정 가능하다.
- Append=false : 기본값은 true이며 파일 끝에 추가하는 것을 의미한다.
  false 는 각각의 프로그램이 시작할때 파일에 덮어씌운다.


RollingFileAppender 옵션들
- Threadhold=WARN: 이 appender는 category의 priority가 더 낮게 지정되어 있다고 할지라도 여기 명시된 priority보다
  낮은메세지들을 로깅하지 않을 것이다. 이것은 콘솔에 모든 메세지가 나타나는 동안 파일에 로깅되는 경우와 같이
  메세지의 숫자를 줄이는데 유용하다.
- ImmediateFlush=true: 기본값은 true. 로그메세지들이 전혀 버퍼되지 않는 것을 의미하며 대부분의 상황에 적당하다.
- File=mylog.txt : 로깅할 파일명. 앞부분에 경로를 나타내기 위해 ${some_property_key}
  (예를 들어 java.home 또는 user.home 과 같은 시스템 프로퍼티)를 사용할 수 있다. 사실 모든 옵션들의 프로퍼티키들은
  이런 종류의 값을 설정 가능하다.
- Append=false : 기본값은 true이며 파일 끝에 추가하는 것을 의미한다.
  false 는 각각의 프로그램이 시작할때 파일에 덮어씌운다.
- MaxFileSize=100KB : 끝에 KB, MB 또는 GB를 붙인다. 지정한 크기에 도달하면 로그파일을 교체한다(roll).
- MaxBackupIndex=2 : 최대 2개(예)의 백업 파일들을 유지시킨다. 오래된 파일들은 삭제한다. 0 은 백업파일을 만들지 않는다.


DailyRollingFileAppender 옵션들
- Threadhold=WARN: 이 appender는 category의 priority가 더 낮게 지정되어 있다고 할지라도 여기 명시된 priority보다
  낮은메세지들을 로깅하지 않을 것이다. 이것은 콘솔에 모든 메세지가 나타나는 동안 파일에 로깅되는 경우와 같이
  메세지의 숫자를 줄이는데 유용하다.
- ImmediateFlush=true: 기본값은 true. 로그메세지들이 전혀 버퍼되지 않는 것을 의미하며 대부분의 상황에 적당하다.
- File=mylog.txt : 로깅할 파일명. 앞부분에 경로를 나타내기 위해 ${some_property_key}
  (예를 들어 java.home 또는 user.home 과 같은 시스템 프로퍼티)를 사용할 수 있다. 사실 모든 옵션들의 프로퍼티키들은
  이런 종류의 값을 설정 가능하다.
- Append=false : 기본값은 true이며 파일 끝에 추가하는 것을 의미한다.
  false 는 각각의 프로그램이 시작할때 파일에 덮어씌운다.
- DatePattern='.'yyyy-ww : 매주마다 파일을 교체(roll)한다. 교체주기를 월, 주, 일, 하루 2회, 시간, 분 별로 정할수 있다.
  이 값은 교체주기를 설정할 뿐만 아니라 백업파일의 붙는 문자열도 정한다. 콜론(:) 문자를 값의 어디에도 사용하지 말라.
  그것 말고는 자바의 SimpleDateFormat 의 어떤 형식 문자열을 사용할 수 있다.
  특히 한쌍의 작은따옴표(single quote) 안에 있는 문자를 반드시 제어해주어야 한다.(예의 '.' 와 같이)
- '.'yyyy-MM: 매달의 첫날에 로그파일을 교체한다.
- '.'yyyy-ww: 매주의 첫날에 로그파일을 교체한다.
- '.'yyyy-MM-dd: 매일 자정에 로그파일을 교체한다.
- '.'yyyy-MM-dd-a: 매일 자정과 정오에 로그파일을 교체한다.
- '.'yyyy-MM-dd-HH: 시간마다(시간이 시작할때) 로그파일을 교체한다.
- '.'yyyy-MM-dd-HH-mm: 분마다(분이 시작할때) 로그파일을 교체한다.


PatternLayout 옵션들
- ConversionPattern=%m%n : 각각의 로그메세지의 형식을 나타내는 방법(포함하는 정보)


HTMLLayout 옵션들
- LocatoinInfo=true: 기본값은 false. 자바파일명과 행번호를 출력한다.
- Title=My app title : 기본값은 Log4j Log Message. HTML의 <title>태그에 주어진다


XMLLayout 옵션들
- LocatoinInfo=true: 기본값은 false. 자바파일명과 행번호를 출력한다.


TTCCLayout 옵션들(이것 대신 더 유연한 PatternLayout을 사용하라)
- DateFormat=ISO8601: 자바의 SimpleDateFormat 의 생성자이거나 NULL, RELATIVE, ABSOLUTE, DATE, ISO8601 중 하나.
- TimeZoneID=GMT-8:00: TimeZone.getTimeZone(java.lang.String) 메소드에 의해 나올만한 형식의 문자열
- CategoryPrefixing=false: 기본값은 true. category 이름을 출력한다.
- ContextPrinting=false: 기본값은 true. 현재 스레드에 속하는 내포검사항목 정보를 출력한다.
- ThreadPrinting=false: 기본값은 true. 스레드명을 출력한다.





                            종합적인 Log4j 설정 프로퍼티 파일

#log4j.debug=true
#log4j.disable=fatal
#log4j.additivity.TestLogging=false

log4j.rootCategory=, dest1
log4j.category.TestLogging=DEBUG, dest1
log4j.appender.dest1=org.apache.log4j.ConsoleAppender
#log4j.appender.dest1.layout=org.apache.log4j.SimpleLayout
log4j.appender.dest1.layout=org.apache.log4j.PatternLayout
#log4j.appender.dest1.layout.ConversionPattern=%-5p %l %x: %m%n


!----------------------####### END OF PROPERTIES #######----------------------!


###############################################################################
# 밑으로 log4j 설정파일을 어떻게 써야하는지 더 자세히 기록해놓았다.           #
# #으로 시작하는 행을 선택적으로 복사해서 주석을 제거하고 붙여라.             #
###############################################################################

!-----------------------------------------------------------------------------!
! 이 파일을 클래스패스가 지정된 어느곳이든 위치시켜라.                        !
! Appender 들은 기본적으로 추가된다.                                          !
! 프로퍼티들은 category가 오버라이드 될때까지 상속된다.                       !
! ${property_key} 에서 키의 값은 시스템 프로퍼티나 파일 자체에서 정의될 수    !
! 있다. 시스템 프로퍼티들은 이 파일보다 먼저 검색된다.                        !
!-----------------------------------------------------------------------------!


!-----------------------------------------------------------------------------!
! log4j의 상위 수준에서의 동작을 설정한다.                                    !
!-----------------------------------------------------------------------------!
! log4j가 이파일을 파싱하는 것을 볼 수 있다.
#log4j.debug=true
! 이것을 false로 지정하면 실제적으로 log4j.disable 프로퍼티를 따르게된다.
#log4j.disableOverride=false
! 주어진 priority 보다 같거나 낮은 priority 를 가진 메세지의 로깅을
! 모든 category에서 불가능 하게 한다.
#log4j.disable=INFO



!-----------------------------------------------------------------------------!
! category(logger) 설정                                                       !
!-----------------------------------------------------------------------------!

! ROOT CATEGORY (보통 이것만 세팅하는 것으로 충분하다)
! 여기서는 priority가 DEBUG(기본값) 이상되는 메세지를 로깅한다.
#log4j.rootCategory=, dest1
! 또는,
#log4j.rootCategory=debug, dest1, dest2

! 당신이 설정하는 CATEGORY들
! (클래스/패키지/프로젝트/기타 별로 로깅을 사용자설정한다)
! 조상의 priority를 오버라이드 하고, 이 카테고리에서 WARN 또는 그보다 높게설정
#log4j.category.TestLogging=WARN, dest3
! 또는,
#log4j.category.TestLogging=DEBUG, dest3

!--------다음을 하지마라!!  APPENDER들은 기본적으로 추가된다!!!---------------!
! 같은 로그 메세지들을 dest1에 두번 이상 쓸것이다. 한번은 root,               !
! 그리고는 이 category 로                                                     !
!#log4j.category.TestLogging=DEBUG, dest1, dest3                              !
! 만약 이 category에서 추가(additive)되기를 원하지 않으려면 다음과 같이 하라  !
!#log4j.additivity.TestLogging=false                                          !
!-----------------------------------------------------------------------------!


!-----------------------------------------------------------------------------!
! appender(log destinations/targets) 와 옵션들을 설정                         !
!-----------------------------------------------------------------------------!

! CONSOLE에 쓰기 (stdout 또는 stderr)
#log4j.appender.dest1=org.apache.log4j.ConsoleAppender
#log4j.appender.dest1.ImmediateFlush=true

! FILE에 로그 쓰기, 지정한 크기를 넘어서면 파일을 교체
#log4j.appender.dest2=org.apache.log4j.RollingFileAppender
! 이 appender 는 여기 명시된 priority 와 같거나 높은 메세지만 로깅한다.
#log4j.appender.dest2.Threshold=ERROR
!  파일명을 명시한다 (${property_key} 는 대신 사용가능한 값을 얻어온다)
#log4j.appender.dest2.File=${java.home}/log4j.log
! 추가하지 않고, 덮어씌운다.
#log4j.appender.dest2.Append=false
! 최대 파일크기를 조절
#log4j.appender.dest2.MaxFileSize=100KB
! 백업파일 갯수 지정 (백업 파일은 파일이름.1, .2 등으로 생성된다)
#log4j.appender.dest2.MaxBackupIndex=2

! 파일에 로그를 쓰고, 매주 교체된다.
#log4j.appender.dest3=org.apache.log4j.DailyRollingFileAppender
! 파일명을 명시.
#log4j.appender.dest3.File=log4TestLogging2.html
! 최대 파일크기를 조절
#log4j.appender.dest3.MaxFileSize=300KB
! 각 주를 시작하며 로그파일을 교체
#log4j.appender.dest3.DatePattern='.'yyyy-ww



!-----------------------------------------------------------------------------!
! appender의 layout(log 형식, 구성) 과 옵션들을 설정                          !
!-----------------------------------------------------------------------------!

! 간단한 로그 형식을 사용 (예 INFO - your log message)
#log4j.appender.dest1.layout=org.apache.log4j.SimpleLayout

! 로그 메세지 구성을 C의 printf 스타일의 형식을 사용
#log4j.appender.dest1.layout=org.apache.log4j.PatternLayout
! pattern layout 에서 패턴을 지정 (기본값은 %m%n 이며 가장 빠르다)
#log4j.appender.dest1.layout.ConversionPattern=%-5p: %m%n
! 또는,
#log4j.appender.dest1.layout.ConversionPattern=%-5p %6.10r[%t]%x(%F:%L) - %m%n

#log4j.appender.dest2.layout=org.apache.log4j.PatternLayout
#log4j.appender.dest2.layout.ConversionPattern=[%d{ISO8601}]%5p%6.6r[%t]%x(%F:%L) - %m%n
! 또는, (아래의 형식은 어플리케이션을 느리게 할 것이다)
#log4j.appender.dest2.layout.ConversionPattern=[%d{yyyy-mm-dd hh:mm},%6.6r]%-5p[%t]%x(%F:%L) - %m%n


! HTML 테이블 형태로 로그메세지를 구성
#log4j.appender.dest3.layout=org.apache.log4j.HTMLLayout
! 자바 file명과 행번호를 출력 (기본값은 false)
#log4j.appender.dest3.layout.LocationInfo=true
! <title>태그 설정 (기본값: Log4J Log Messages)
#log4j.appender.dest3.layout.Title=My App Log


!-----------------------------------------------------------------------------!
!                          PATTERN 형식 용어들                                !
!-----------------------------------------------------------------------------!
! %n - 개행                                                                   !
! %m - 로그 메세지                                                            !
! %p - 메세지 priority (FATAL, ERROR, WARN, INFO, DEBUG 또는 사용자정의)      !
! %r - 프로그램 구동이 시작한 이후 경과시간의 밀리세컨드값                    !
! %% - 퍼센트 기호 출력                                                       !
!                                                                             !
!----------------------- 로그에서의 몇가지 추가요소들-------------------------!
! %c - category(logger)이름, %c{2}는 마지막 두개의 요소를 출력한다.           !
! %t - 현재 스레드 이름                                                       !
! %x - 내포검사항목 (NDC)    \\                                               !
!                                                                             !
!------------------------- 성능 저하시키는 형식들 ----------------------------!
! %d - 날자와 시간, 또한 %d{ISO8601}, %d{DATE}, %d{ABSOLUTE},                 !
!        %d{HH:mm:ss,SSS}, %d{dd MMM yyyy HH:mm:ss,SSS} 등                    !
! %l - %F%L%C%M 의 축약형                                                     !
! %F - 자바 소스 파일명                                                       !
! %L - 자바 소스의 행번호                                                     !
! %C - 자바 클래스 이름, %C{1} 마지막 하나의 요소를 출력                      !
! %M - 자바 메소드 이름                                                       !
!                                                                             !
!------------------------------  형식 변경자   -------------------------------!
! %-어떤형식문자 -  최소폭 이하에서 왼쪽정렬 (기본값은 오른쪽 정렬)           !
! %20어떤형식문자 - 20 글자 최소폭 (가능할 때에는 왼쪽에 여백이 가능)         !
! %.30어떤형식문자 - 최대 30글자 (필요하면 앞에서부터 잘린다)                 !
! %-10.10r - 예.  경과시간이 10개문자 이하의 넓이이면 왼쪽정렬                !
!            10개문자 이상의 길이이면 앞에서 부터 잘린다.                     !
!-----------------------------------------------------------------------------!


!-----------------------------------------------------------------------------!
!                             OPTIONS GLOSSARY                                !
!-----------------------------------------------------------------------------!
!-------------------------OVERALL OPTIONS FOR log4j---------------------------!
! 커맨드 라인 option으로 명시: -Dlog4j.defaultInitOverride=false
! 커맨드 라인 option으로 명시: -Dlog4j.configuration=app_config.properties
!#log4j.debug=true
!#log4j.disable=INFO
!#log4j.disableOverride=false
!#log4j.additivity.your.category.name=false
!
!----------------------------NullAppender OPTIONS-----------------------------!
!#log4j.appender.dest1.Threshold=INFO
!
!---------------------------ConsoleAppender OPTIONS---------------------------!
!#log4j.appender.dest1.Threshold=INFO
!#log4j.appender.dest1.ImmediateFlush=true
!#log4j.appender.dest1.Target=System.err
!
!-----------------------------FileAppender OPTIONS----------------------------!
!#log4j.appender.dest2.Threshold=INFO
!#log4j.appender.dest2.ImmediateFlush=true
!#log4j.appender.dest2.File=mylog.txt
!#log4j.appender.dest2.Append=false
!
!-------------------------RollingFileAppender OPTIONS-------------------------!
!#log4j.appender.dest2.Threshold=INFO
!#log4j.appender.dest2.ImmediateFlush=true
!#log4j.appender.dest2.File=mylog.txt
!#log4j.appender.dest2.Append=false
!#log4j.appender.dest2.MaxFileSize=100KB
!#log4j.appender.dest2.MaxBackupIndex=2
!
!-----------------------DailyRollingFileAppender OPTIONS----------------------!
!#log4j.appender.dest2.Threshold=INFO
!#log4j.appender.dest2.ImmediateFlush=true
!#log4j.appender.dest2.File=mylog.txt
!#log4j.appender.dest2.Append=false
!#log4j.appender.dest2.DatePattern='.'yyyy-ww
!
!-----------------------------SimpleLayout OPTIONS----------------------------!
!**None**
!
!-------------TTCCLayout OPTIONS (PatternLayout is more flexible)-------------!
!#log4j.appender.dest1.layout.DateFormat=ISO8601
!#log4j.appender.dest1.layout.TimeZoneID=GMT-8:00
!#log4j.appender.dest1.layout.CategoryPrefixing=false
!#log4j.appender.dest1.layout.ThreadPrinting=false
!#log4j.appender.dest1.layout.ContextPrinting=false
!
!-----------------------------PatternLayout OPTIONS---------------------------!
!#log4j.appender.dest1.layout.ConversionPattern=%m%n
!
!-------------------------------HTMLLayout OPTIONS----------------------------!
!#log4j.appender.dest3.layout.LocationInfo=true
!#log4j.appender.dest3.layout.Title=My app title
!
!--------------------------------XMLLayout OPTIONS----------------------------!
!#log4j.appender.dest3.layout.LocationInfo=true
!-----------------------------------------------------------------------------!



- 코드상에서 성능이 매우 중요한 곳에서는 로깅메소드의 파라미터를 만드는 시간을 절약하기 위해 다음과 같이 사용한다.
if (cat.isDebugEnabled() {
    cat.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}

- SimpleLayout을 사용하였거나 %p, %m, %n의 패턴만 사용하여 설정한 경우 System.out.println(...) 만큼 성능이
  빠르다고 테스트됐다.

- 내포검사항목(NDC)를 사용한다 : 가끔 서블릿처럼 하나의 코드가 각각의 클라이언트를 서비스 하기위해
  여러개의 스레드로 인스턴스화 되어 많은 클라이언트를 서비스한다.
  이때 다른 클라이언트로 부터의 로깅 요청을 차별화하기 위해서 내포검사항목(NDC)를 사용할 수 있다.
  할 수 있는 것은 로깅하기 전에 클라이언트의 고유한 정보를 NDC로 넣는다. 고유한 정보는 클라이언트의 IP주소,
  호스트이름 또는 요청과 관련된 어떤 것도 될 수 있다. %x를 layout 패턴에 명시하면 요청한 로그 메세지에
  그 문자열(고유한 정보)을 찍는다.

import org.apache.log4j.*;

public class TestNDC {

  // !log4j.properties 파일이 클래스패스 상에 존재하는지 확인하라.

  static Category cat = Category.getInstance(TestNDC.class.getName());

  public static void main(String[] args) {

    // 내포검사 설정은 서블릿과 같이 멀티스레드로 이루어진 클라이언트의 요청들을 구별한다.
    NDC.push("Client #45890");

    cat.info("Testing Nested Diagnostic Context (NDC).");
    cat.info("Make sure %x is in layout pattern!");
    cat.info("Client #45890 should appear in this log message.");

    switchNDC();

    cat.info("Finished.");
  }

  static void switchNDC() {
    NDC.push("Client #99999");
    cat.debug("Client #99999 should appear nested in this log message.");
    NDC.pop();
  }

}

Posted by 꿈꾸는자의 생각의파편들
2005.02.13 17:19

[펌] POI Quick Guide Dev.../플밍 관련 자료2005.02.13 17:19

Busy Developers' Guide to Features

HSSF를 이용해서 빨리 스프레드쉬트에 읽고 쓰는 작업을 해보구싶으시다구요? 그렇다면 이번가이드는 여러분을 위한 것입니다. 좀더 깊이 있는 HSSF user-API의 정보를 원하신다면 HOWTO를 참조해주십시요. 그것은 이러한 내용의 보다 자세한 정보가 있으니깐요.

Index of Features

Features

새로운 통합문서생성

    HSSFWorkbook wb = new HSSFWorkbook();    FileOutputStream fileOut = new FileOutputStream("workbook.xls");    wb.write(fileOut);    fileOut.close();                    

새로운 스프레드시트 생성

    HSSFWorkbook wb = new HSSFWorkbook();    HSSFSheet sheet1 = wb.createSheet("new sheet");    HSSFSheet sheet2 = wb.createSheet("second sheet");    FileOutputStream fileOut = new FileOutputStream("workbook.xls");    wb.write(fileOut);    fileOut.close();                    

셀의 생성

    HSSFWorkbook wb = new HSSFWorkbook();    HSSFSheet sheet = wb.createSheet("new sheet");    // Create a row and put some cells in it. Rows are 0 based.    HSSFRow row = sheet.createRow((short)0);    // Create a cell and put a value in it.    HSSFCell cell = row.createCell((short)0);    cell.setCellValue(1);    // Or do it on one line.    row.createCell((short)1).setCellValue(1.2);    row.createCell((short)2).setCellValue("This is a string");    row.createCell((short)3).setCellValue(true);    // Write the output to a file    FileOutputStream fileOut = new FileOutputStream("workbook.xls");    wb.write(fileOut);    fileOut.close();                    

날짜타입의 셀의 생성

    HSSFWorkbook wb = new HSSFWorkbook();    HSSFSheet sheet = wb.createSheet("new sheet");    // Create a row and put some cells in it. Rows are 0 based.    HSSFRow row = sheet.createRow((short)0);    // Create a cell and put a date value in it.  The first cell is not styled    // as a date.    HSSFCell cell = row.createCell((short)0);    cell.setCellValue(new Date());    // we style the second cell as a date (and time).  It is important to    // create a new cell style from the workbook otherwise you can end up    // modifying the built in style and effecting not only this cell but other cells.    HSSFCellStyle cellStyle = wb.createCellStyle();    cellStyle.setDataFormat(HSSFDataFormat.getFormat("m/d/yy h:mm"));    cell = row.createCell((short)1);    cell.setCellValue(new Date());    cell.setCellStyle(cellStyle);    // Write the output to a file    FileOutputStream fileOut = new FileOutputStream("workbook.xls");    wb.write(fileOut);    fileOut.close();                    

타입이 다른 셀을 함께 작업하기

    HSSFWorkbook wb = new HSSFWorkbook();    HSSFSheet sheet = wb.createSheet("new sheet");    HSSFRow row = sheet.createRow((short)2);    row.createCell((short) 0).setCellValue(1.1);    row.createCell((short) 1).setCellValue(new Date());    row.createCell((short) 2).setCellValue("a string");    row.createCell((short) 3).setCellValue(true);    row.createCell((short) 4).setCellType(HSSFCell.CELL_TYPE_ERROR);    // Write the output to a file    FileOutputStream fileOut = new FileOutputStream("workbook.xls");    wb.write(fileOut);    fileOut.close();                    

다양한 정렬옵션 데모

    public static void main(String[] args)            throws IOException    {        HSSFWorkbook wb = new HSSFWorkbook();        HSSFSheet sheet = wb.createSheet("new sheet");        HSSFRow row = sheet.createRow((short) 2);        createCell(wb, row, (short) 0, HSSFCellStyle.ALIGN_CENTER);        createCell(wb, row, (short) 1, HSSFCellStyle.ALIGN_CENTER_SELECTION);        createCell(wb, row, (short) 2, HSSFCellStyle.ALIGN_FILL);        createCell(wb, row, (short) 3, HSSFCellStyle.ALIGN_GENERAL);        createCell(wb, row, (short) 4, HSSFCellStyle.ALIGN_JUSTIFY);        createCell(wb, row, (short) 5, HSSFCellStyle.ALIGN_LEFT);        createCell(wb, row, (short) 6, HSSFCellStyle.ALIGN_RIGHT);        // Write the output to a file        FileOutputStream fileOut = new FileOutputStream("workbook.xls");        wb.write(fileOut);        fileOut.close();    }    /**     * Creates a cell and aligns it a certain way.     *     * @param wb        the workbook     * @param row       the row to create the cell in     * @param column    the column number to create the cell in     * @param align     the alignment for the cell.     */    private static void createCell(HSSFWorkbook wb, HSSFRow row, short column, short align)    {        HSSFCell cell = row.createCell(column);        cell.setCellValue("Align It");        HSSFCellStyle cellStyle = wb.createCellStyle();        cellStyle.setAlignment(align);        cell.setCellStyle(cellStyle);    }                    

테두리 다루기

    HSSFWorkbook wb = new HSSFWorkbook();    HSSFSheet sheet = wb.createSheet("new sheet");    // Create a row and put some cells in it. Rows are 0 based.    HSSFRow row = sheet.createRow((short) 1);    // Create a cell and put a value in it.    HSSFCell cell = row.createCell((short) 1);    cell.setCellValue(4);    // Style the cell with borders all around.    HSSFCellStyle style = wb.createCellStyle();    style.setBorderBottom(HSSFCellStyle.BORDER_THIN);    style.setBottomBorderColor(HSSFColor.BLACK.index);    style.setBorderLeft(HSSFCellStyle.BORDER_THIN);    style.setLeftBorderColor(HSSFColor.GREEN.index);    style.setBorderRight(HSSFCellStyle.BORDER_THIN);    style.setRightBorderColor(HSSFColor.BLUE.index);    style.setBorderTop(HSSFCellStyle.BORDER_MEDIUM_DASHED);    style.setTopBorderColor(HSSFColor.BLACK.index);    cell.setCellStyle(style);    // Write the output to a file    FileOutputStream fileOut = new FileOutputStream("workbook.xls");    wb.write(fileOut);    fileOut.close();                    

색채우기와 글꼴색

    HSSFWorkbook wb = new HSSFWorkbook();    HSSFSheet sheet = wb.createSheet("new sheet");    // Create a row and put some cells in it. Rows are 0 based.    HSSFRow row = sheet.createRow((short) 1);    // Aqua background    HSSFCellStyle style = wb.createCellStyle();    style.setFillBackgroundColor(HSSFColor.AQUA.index);    style.setFillPattern(HSSFCellStyle.BIG_SPOTS);    HSSFCell cell = row.createCell((short) 1);    cell.setCellValue("X");    cell.setCellStyle(style);    // Orange "foreground", foreground being the fill foreground not the font color.    style = wb.createCellStyle();    style.setFillForegroundColor(HSSFColor.ORANGE.index);    style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);    cell = row.createCell((short) 2);    cell.setCellValue("X");    cell.setCellStyle(style);    // Write the output to a file    FileOutputStream fileOut = new FileOutputStream("workbook.xls");    wb.write(fileOut);    fileOut.close();                    

셀 병합

    HSSFWorkbook wb = new HSSFWorkbook();    HSSFSheet sheet = wb.createSheet("new sheet");    HSSFRow row = sheet.createRow((short) 1);    HSSFCell cell = row.createCell((short) 1);    cell.setCellValue("This is a test of merging");    sheet.addMergedRegion(new Region(1,(short)1,1,(short)2));    // Write the output to a file    FileOutputStream fileOut = new FileOutputStream("workbook.xls");    wb.write(fileOut);    fileOut.close();                    

폰트 다루기

    HSSFWorkbook wb = new HSSFWorkbook();    HSSFSheet sheet = wb.createSheet("new sheet");    // Create a row and put some cells in it. Rows are 0 based.    HSSFRow row = sheet.createRow((short) 1);    // Create a new font and alter it.    HSSFFont font = wb.createFont();    font.setFontHeightInPoints((short)24);    font.setFontName("Courier New");    font.setItalic(true);    font.setStrikeout(true);    // Fonts are set into a style so create a new one to use.    HSSFCellStyle style = wb.createCellStyle();    style.setFont(font);    // Create a cell and put a value in it.    HSSFCell cell = row.createCell((short) 1);    cell.setCellValue("This is a test of fonts");    cell.setCellStyle(style);    // Write the output to a file    FileOutputStream fileOut = new FileOutputStream("workbook.xls");    wb.write(fileOut);    fileOut.close();                    

통합문서 읽고 쓰기

    POIFSFileSystem fs      =            new POIFSFileSystem(new FileInputStream("workbook.xls"));    HSSFWorkbook wb = new HSSFWorkbook(fs);    HSSFSheet sheet = wb.getSheetAt(0);    HSSFRow row = sheet.getRow(2);    HSSFCell cell = row.getCell((short)3);    if (cell == null)        cell = row.createCell((short)3);    cell.setCellType(HSSFCell.CELL_TYPE_STRING);    cell.setCellValue("a test");    // Write the output to a file    FileOutputStream fileOut = new FileOutputStream("workbook.xls");    wb.write(fileOut);    fileOut.close();                    

셀에서의 개행문자 사용하기

    HSSFWorkbook wb = new HSSFWorkbook();    HSSFSheet s = wb.createSheet();    HSSFRow r = null;    HSSFCell c = null;    HSSFCellStyle cs = wb.createCellStyle();    HSSFFont f = wb.createFont();    HSSFFont f2 = wb.createFont();    cs = wb.createCellStyle();    cs.setFont( f2 );    //Word Wrap MUST be turned on    cs.setWrapText( true );    r = s.createRow( (short) 2 );    r.setHeight( (short) 0x349 );    c = r.createCell( (short) 2 );    c.setCellType( HSSFCell.CELL_TYPE_STRING );    c.setCellValue( "Use \n with word wrap on to create a new line" );    c.setCellStyle( cs );    s.setColumnWidth( (short) 2, (short) ( ( 50 * 8 ) / ( (double) 1 / 20 ) ) );    FileOutputStream fileOut = new FileOutputStream( "workbook.xls" );    wb.write( fileOut );    fileOut.close();

데이터타입

    HSSFWorkbook wb = new HSSFWorkbook();    HSSFSheet sheet = wb.createSheet("format sheet");    HSSFCellStyle style;    HSSFDataFormat format = wb.createDataFormat();    HSSFRow row;    HSSFCell cell;    short rowNum = 0;    short colNum = 0;    row = sheet.createRow(rowNum++);    cell = row.createCell(colNum);    cell.setCellValue(11111.25);    style = wb.createCellStyle();    style.setDataFormat(format.getFormat("0.0"));    cell.setCellStyle(style);    row = sheet.createRow(rowNum++);    cell = row.createCell(colNum);    cell.setCellValue(11111.25);    style = wb.createCellStyle();    style.setDataFormat(format.getFormat("#,##0.0000"));    cell.setCellStyle(style);    FileOutputStream fileOut = new FileOutputStream("workbook.xls");    wb.write(fileOut);    fileOut.close();                    

스프레드시트내의 인쇄범위설정법

    HSSFWorkbook wb = new HSSFWorkbook();    HSSFSheet sheet = wb.createSheet("format sheet");    HSSFPrintSetup ps = sheet.getPrintSetup()        sheet.setAutobreaks(true)        ps.setFitHeight((short)1);    ps.setFitWidth((short)1);    // Create various cells and rows for spreadsheet.    FileOutputStream fileOut = new FileOutputStream("workbook.xls");    wb.write(fileOut);    fileOut.close();                    

스프레드시트의 바닥글에 페이지번호 설정법

    HSSFWorkbook wb = new HSSFWorkbook();    HSSFSheet sheet = wb.createSheet("format sheet");    HSSFFooter footer = sheet.getFooter()        footer.setRight( "Page " + HSSFFooter.page() + " of " + HSSFFooter.numPages() );        // Create various cells and rows for spreadsheet.    FileOutputStream fileOut = new FileOutputStream("workbook.xls");    wb.write(fileOut);    fileOut.close();                    
by Glen Stampoultzis
last modified: 05/20/2004 10:06:56 last modified: 04/30/2004 07:40:52 last modified: 04/29/2004 11:14:25
Posted by 꿈꾸는자의 생각의파편들

오픈소스를 꺼리게 만드는「6가지 편견」

Dan Farber (ZDNet Korea)

 

원문보기

 

2004/03/24

 우리 모두는 오픈소스 소프트웨어를 사용하면 총소유비용(TCO)이 줄어들 뿐만 아니라 선택의 폭도 더 넓어지고 코드의 품질과 기능을 향상시킬 수 있는 등 많은 장점이 있다는 것을 잘 알고 있다. 게다가 요즘에는 리눅스가 서버 분야에서 데이터센터에까지 진출하고 있다는 점을 볼 때 오픈소스 모델이 점차 깊이 뿌리를 내리고 있다는 것도 알 수 있다.

하지만 기업 차원에서 리눅스를 비롯한 오픈소스 프로젝트들이 널리 보급되기 전에 해결해야 할 큰 장애물이 많은 것도 사실이다. 지난주 샌프란시스코에서 열린 오픈소스 비즈니스 컨퍼런스(OSBC) 2004에서 기조연설에 나선 레이 레인은 포춘지 선정 500대 기업에 속하는 수십명의 CIO들과의 인터뷰 결과 과연 어떤 장애물이 있는지 6가지로 요약해 발표했다. 레이 레인은 전에는 오라클의 고위 경영진을 거쳐 현재는 클라이너 퍼킨즈 코필드 & 바이어즈의 수석 파트너로 있다. 물론 이 6가지 문제점 때문에 오픈소스가 데이터 센터나 데스크톱 분야로 진출하지 못한다는 것은 아니지만 이 문제점들은 오픈소스 소프트웨어의 로드맵에 대해서 토론하는데 필요한 기본 틀을 제공하고 있다.

공식적인 지원이 부족하다?
레인이 생각하는 문제점 가운데 가장 중요한 것은 지원 문제이다. 하지만 사실 IT 업계 경영진은 오픈소스 패키지의 라이선스가 무료라는 점은 사실상 여러 애플리케이션을 배치하고 관리하는 데 드는 전체 비용과 비교하면 조족지혈(鳥足之血)에 불과하다고 여긴다.

이들은 특히 레드햇이나 노벨과 같이 자금 사정이 매우 좋은 회사의 경우에 있어서는 리눅스에 대한 지원도 계속해서 향상될 것이라고 기대하고 있다. 예를 들어 레드햇은 약 10억 달러 정도의 현금 보유고를 가지고 있으며 그동안 노벨은 자사의 독자적 제품들을 보완해주는 오픈소스 소프트웨어들을 계속해서 개발하고 있다. 오픈소스 소프트웨어를 번들하는 하드웨어 판매업체들은 자기네 회사의 이름을 위해 많은 노력을 기울이고 있다. 즉 이들은 자기네가 유통 과정을 개발하지는 않지만 고객들에게 총체적인 솔루션을 가져다 줄 수밖에 없는 형편이다. IBM이나 HP같은 회사들은 리눅스 유통업체들이 고객들이 만족할만한 서비스 차원을 제공하겠다는 동의를 하지 못하면 레드햇이나 수세, 터보리눅스 또는 맨드레이크소프트 등의 기업과 함께 일하려 하지 않을 것이다.

아파치는 웹서버 소프트웨어 시장에서 MS의 인터넷 정보 서비스를 능가하고 있다는 것만 봐도 지원 서비스 부족으로 문제가 있는 것 같지는 않다.

많은 중소기업들은 오픈소스 코드 위에서 독자적인 확장 기능이나 지원 서비스 등을 구축하고 있다. 예를 들어 글루코드(Gluecode)는 아파치 프로젝트를 이용하고 있으며 거기에다가 자기네 독자적인 포탈과 관리 기술을 통합하고 있다. 글루코드는 이 제품이 BEA나 IBM 그리고 오라클에서 나온 유사 솔루션들에 비해 3~6배나 저렴하다고 주장한다. 이 회사는 자사의 애드밴스드 서버 제품들에 대해 한달에 4~2000달러 정도의 이용요금을 청구하고 있다.

프록터 앤 갬블 등의 기업을 위해 콜센터를 운영해주는 컨솔리데이티드 커뮤니케이션의 웹 개발자인 제임스 체이니는 "우리는 PHP에서 자바로 전환하고 있다. 또한 단일인증 시스템으로 통합하고 서로 다른 웹 애플리케이션의 호환성 확보하기 위해 글루코드를 사용하고 있다“고 말했다. 그는 ”지원은 매우 훌륭하게 이뤄지고 있다“고 덧붙였다.

물론 중소기업들이나 신생업체라고 할 수 있는 회사들 혹은 이미 자리가 확립된 회사들이라 해도 고객들을 만족시킬만한 지원이나 사후서비스(A/S)를 제공할 수 없다면 시범설치 후에 더 이상 계속 이용하지 않을 것이다.

또한 레인은 협력 개발 과정 외에 형식적인 지원을 가지고 있지 않은 수많은 오픈소스 프로젝트에 대해서도 언급한다. 비영리 업계단체인 아파치 소프트웨어 재단(ASF)에서는 아파치 오픈소스 프로젝트에 대해서 도움과 지원을 제공하며 공동 개발 모델이 잘 돌아가는지 보여준다. 사실 아파치 그룹의 공동 협력 프로젝트의 기반이 되는 오픈소스 소프트웨어가 콜래브넷 소스캐스트의 기반이 되며 웹에 기반을 둔 공동개발 소프트웨어로 현재 썬, 사이베이스, 모토롤라 등이 도입하고 있다.

오픈소스 애플리케이션 서버 제조사 J보스(JBoss)는 24시간 지원하고 있으며 자사의 소프트웨어가 자바2 엔터프라이즈 에디션(J2EE) 표준을 준수하도록 인증 작업을 하고 있다. 이 작은 회사는 현재 BEA나 IBM, MS 그리고 썬보다 더 좋은 평판을 받고 있다. CTO에게 수십억 달러의 자산을 보유하고 있는 대기업들보다 더 좋은 그리고 더 비용 효율적인 지원을 제공해줄 수 있다고 설득시킬 수 있다면 그것은 J보스와 비슷한 처지의 회사들로서는 신임을 크게 얻으며 성장할 수 있는 기회가 될 것이다.

오픈소스 소프트웨어에게 있어서 지원 인프라라든지 지원에 대한 확실한 약속은 덜 분명하기 때문에 기업들은 자기네 스스로 위험 가능성을 감당해야만 한다. 대부분 기업들은 오픈소스 공동체로부터 좀더 비공식적인 지원밖에는 기대할 수 없는데 좀더 핵심적인 업무에 관련된 애플리케이션이라면 이 정도로는 부족하다. 그리고 사실 이것은 독자적인 소프트웨어를 판매하고 있는 작은 규모의 회사들에 있어서도 거의 비슷할 것이다.


너무 자주 바뀐다?


대부분 기업들은 인프라에 새로운 소프트웨어를 소개하는 문제에 있어서도 그렇겠지만 패치나 취약점으로 매우 불편을 겪고 있다. IT 관리들은 사실 오픈소스 공동체에서는 끊임없이 자사의 소프트웨어를 바꾼다는 점에 대해서 우려하고 있다. 오픈소스 소프트웨어를 사용하면 소프트웨어 사후 관리가 좀더 복잡해지지만 또한 오픈소스 소프트웨어에서는 버그나 취약점에 대한 픽스를 신속하게 내보내기 때문에 오픈소스 코드는 좀더 안전하고 믿을만하다고 하겠다. 반면 MS는 특정 취약점이 발견됐을 때 패치를 한 가지 내보내는 데 200일이 걸렸다.

끊임없는 업그레이드나 픽스를 원하는 기업은 없을 것이라는 점을 고려하면 주요 리눅스 유통업체들은 이런 문제점을 덜기 위해 소프트웨어에 대한 인증은 물론 회원등록제를 통해 끊임없이 업그레이드나 픽스를 내보내는 대신 일정한 주기에 따라 내보내고 있다. 레드햇은 새로운 기능이나 보완을 위한 패치를 시험할 때 100만 명 이상의 데이터베이스를 이용하고 있다는 점을 내세운다.

전반적으로 반대하는 입장에서는 버전에 관한 문제점들은 좀더 많은 판매업체들이 오픈소스 소프트웨어에 대한 구독 시스템과 지원 서비스를 개발함에 따라 다 없어질 것이다. 이것은 자동화된 라이프사이클 관리 인프라에 속하는 것이다. 또한 판매업체와 IT 회사들도 자기네들의 코드 베이스이기도 한 오픈소스 프로젝트를 관리하는데 있어서 공동체에 좀더 참여해야 한다.

판매업체들이나 기업들 입장에서는 오픈소스 프로젝트의 숫자나 규모가 문제될 수도 있다. 애플의 소프트웨어 기술부서의 부사장인 버드 트리블은 "오픈소스 프로젝트는 매우 다양해서 마음대로 고를 수 있다. XML 파서(parser)도 5-6개 정도에 4-5개의 데이터베이스도 있다. 공동체가 얼마나 탄탄한지와 우리 사정에 얼마나 최적화될 것인지는 동일시하기 어렵다"라고 말했다.


일정한 로드맵이 없다?


오픈소스 프로젝트들은 비공식성으로 인해 CIO들은 불안해한다. 대부분 IT 관리들은 제품에 대한 분명한 로드맵을 원한다. 그래야만 미래에 대해 계획을 하거나 판매업체를 선택하는 일도 할 수 있기 때문이다. 주요 오픈소스 유통업체들은 다양한 프로젝트들에 대해 알려줄 수 있는 웹사이트나 사양을 가지고 있는 반면 일부 기업들이 가지고 있는 목표에는 여러 사람이 공동으로 코드를 개발하는 방식의 접근방식은 불편할 것이다. 그러나 프로토콜 표준 위원회와 마찬가지로 오픈소스 공동체 프로세스에도 장단점은 있다. 오히려 기업들은 가장 최소한의 사양이나 솔루션에 발목을 잡힐 우려가 있다.

다른 한편 TCP/IP나 XML과 같은 표준이 없다면 우리에게는 인터넷도 웹서비스도 없을 것이다. 오픈소스 소프트웨어 개발 방식은 독자적 소프트웨어에 비해 좀더 민주적이며 토론도 공개되어 있다. 오픈소스 공동체는 자율적이며 단기 목표보다는 장기적인 목표에 초점을 두는 편이다.

오픈소스 프로젝트들도 앞으로는 다양한 참가자들의 피드백을 따라서 점점 더 투명해질 것이며 좀더 상세한 로드맵을 가질 수 있을 것이다.

또 한편으로 모든 판매업체들이나 위원회에서 제시하는 로드맵들에는 함정이 있다는 것을 기억해야한다. 판매업체들은 고객들에게 정보를 주기 위해서 로드맵을 만들어낼 수 있지만 동시에 고객들이 솔루션을 다른데서 찾지 못하게 하자는 속셈도 있는 것이다.

제품 출시가 연기된다든지 로드맵에 있어서 우회가 있는 것은 짜증나는 일이지만 이런 일은 사실 소프트웨어 개발이 너무나 복잡하기 때문이며 업계에서는 앞으로 출시될 버전들을 너무 일찍 마케팅하는 관행이 있기 때문이기도 하다. 현재 대부분의 오픈소스 공동체들은 로드맵을 제공할 수 있으며 자체 소프트웨어를 보유한 기업들보다 그 과정이 더 공개적이라는 점을 감안하면 엔드 유저 공동체에서도 좀더 자기네 의견을 제시할 수 있고 프로젝트 진행 과정을 추적하기도 쉬울 것이다.


오픈소스 제품은 성능이 떨어진다?


현재 리눅스 시장은 저사양 서버 애플리케이션들이 주도하고 있다. 그러나 앞으로 몇 년 안에 메인프레임이나 데이터센터, ERP 애플리케이션 분야에 있어서도 점유율이 크게 올라갈 것으로 기대된다. 갖가지 업계 보고서를 보면 2007년까지 리눅스는 세계적으로 데스크톱의 5% 정도를 점유할 것으로 보인다.

가장 잘 알려진 오픈소스 프로젝트 가운데 마이SQL은 현재 마이SQL 클러스터를 개발 중에 있다. 이것은 마이 SQL의 오픈소스 데이터베이스 가운데서 특히 다른 데이터베이스에 문제가 있을 때 마이SQL 데이터베이스가 대신할 수 있게 해주는 좀더 하이엔드급에 속하는 버전이다. 또한 이 회사는 포스트그리SQL(PostgreSQL)과 파이어버드(Firebird) 등 다른 오픈소스 데이터베이스에서도 그렇듯이 저장방식을 추가하고 있다.

이번 주 노벨은 수세 리눅스 9.1 프로페셔널에 2.6 리눅스 커널을 채택하겠다고 발표했다. 리눅스 2.6커널은 AMD와 인텔의 x86 칩에 대한 64비트 확장 버전에 대한 지원을 포함한 리눅스 코어의 새로운 정식 버전이다. 레드햇은 내년에 2.6버전을 유통시키기 위해 준비 중에 있다. 일부 오픈소스 제품들은 CC 인증을 준수하고 있는데 이것은 정부와 군에 속하는 고객들을 위해서는 필수조건이다.

상용 소프트웨어와 비교했을 때 시간이 지남에 따라 오픈소스의 기능 문제는 더 이상 큰 문제가 되지 않을 것이다. 중요한 것은 오픈소스 개발자들의 다양한 성격의 공동체뿐 아니라 주요 판매업체들도 오픈소스 프로젝트를 위해서 엔지니어링 및 전파사업에 필요한 자원을 아끼지 않고 있다는 사실이다. 소프트웨어 판매업체들을 비롯한 여러 종류의 판매업체들과 오픈소스 공동체들 사이에는 갈등도 있을 것이고 새로운 기능이나 여러 가지 라이선스 모델들이 정착되면서 문제점도 많을 것이다. 예를 들면 레드햇에서는 리눅스 커널에 특정 변형이 있기를 원하지만 리누스 토벌즈나 OSDL이 반대한다면? 그럼에도 불구하고 많은 사람들의 재능과 엔지니어링 기술로 인해 계속해서 좋은 결과가 있을 것이다. 어쩌면 독자적 플랫폼보다도 더 뛰어난 결과도 기대할 수 있을 것이다.


라이선스가 복잡하다?


IT 관리자들은 오픈소스 라이선스 문제에 관한 여러 가지 혼란과 SCO와의 법적인 문제로 인해 모든 것이 불확실하다는 느낌과 위협을 받기도 할 것이다. 수없이 많은 변호사들이 GPL을 둘러싼 여러 가지 문제점들과 지적 재산권이 어떻게 하면 보호받을 수 있는지에 관해 끊임없이 토론을 벌이고 있다. 현재까지는 BSD와 아파치 모델이 가장 유연한 라이선스 모델을 가지고 있는 것 같다.

오픈소스와 독자적 코드가 혼합된 여러 가지 라이선스 모델들이 요즘은 좀더 유연한 방식으로 나오고 있다. 특히 글루코드에서는 상용 요소를 가진 제품을 만들어내는데 있어서 오픈소스 소프트웨어를 기반으로 사용하고 있다. 동시에 글루코드는 엔터프라이즈 소스 라이선스(ESL)를 통해 고객들이 소스 코드를 볼 수 있도록 하고 있다. 그러나 고객들은 코드에 덧붙일 수는 있지만 제 3자에게 코드를 이용한 제품을 팔거나 임베디드하거나 유통 및 라이선스할 수는 없다.

마이SQL은 오픈소스 라이선스와 상업적 라이선스의 이중 라이선스 방식을 가지고 있어서 오픈소스 소프트웨어에 관해서는 오픈소스 라이선스를 통해 자사의 데이터베이스 소프트웨어를 제공하고 있으며 독자적 소프트웨어에 대해서는 상업적 라이선스를 준다. 그러나 한 개 이상의 회사가 소스코드 저작권을 가지고 있는 경우에 이중 라이선스는 별로 효과가 없다. 최근에 이 회사는 리눅스, 아파치, 마이SQL, 펄(Perl), PHP, 파이썬(Python)과 같은 프로그램과의 라이선스 문제를 해결했다. 지적재산의 보호는 물론 라이선스 문제에 오면 모든 것이 좀더 정확해야하고 분명해야한다.


군소 유통사의 지원에 신뢰가 가지 않는다?


사실 CIO들은 군소 소프트웨어 판매업체의 지원 약속을 그다지 신뢰하지 않지만, 다른 여러 CIO 동료들이 보증하고 있다는 점은 중요하게 받아들인다. 지금껏 리눅스를 사용해서 특정 업무를 수행하는데 아무런 지장이 없다는 것은 밝혀졌다. 그리고 앞으로 리눅스가 더 많은 업무를 수행하는데 있어서 장애물이 될 만한 것은 별로 없어 보인다.

오픈소스가 발전하고 있는 지금으로서는 장애물이 언제 그리고 어떤 식으로 해결될 것이라고 미리 속단할 수는 없다. 그러나 오픈소스 코드로 인해서 소프트웨어 개발과 비즈니스 모델이 변하고 있다는 것은 분명하다. 미래는 오픈소스 코드와 독자적 코드가 모두 포함되는 표준을 토대로 해서 상호호환적인 그리고 모듈식의 컴포넌트라고 할 수 있다. 썬의 소프트웨어 부서의 CTO인 존 파울러는 이같은 트렌드가 '조합적' 가치를 제공하는 것으로 표현하고 있다.

오레일리 & 어쏘시에이츠의 사장이자 오픈소스 소프트웨어의 활발한 팬인 팀 오레일리는 독립적으로 개발된 컴포넌트들을 가지고 믿고 사용할만한 시스템을 만들어내는 것이야말로 오픈소스 비즈니스가 성공하기 위한 관건일 것이라고 말한다. 개발자들이 성능을 높이기만 한다면 오픈소스 소프트웨어의 도입을 꺼리게 만드는 장애물들도 수구적인 회사들과 기업들이 뒤에서 투덜대는 소리에 지나지 않게 될 것이다. @

Posted by 꿈꾸는자의 생각의파편들