oracle.java.com 가면 OSX용 JDK 1.6버젼대를 찾을 수 없는데,

JDK6은 아래 apple 사이트에서 받을 수 있네요.

https://developer.apple.com/downloads/index.action


그리고 dmg 패키지로 jdk를 설치하면


/Library/Java/JavaVirtualMachines


아래 경로에 설치가 됩니다.


google reader에서 소식을 접하고 homepage에 가 봤는데, 오늘 공개되었군요.
거의 6개월만의 새 버젼이군요~

어떤 기능들이 추가되었는지, 어떤 버그들이 수정되었는지 살펴볼까 했는데... 내용이 넘 많네요.
버젼이 올라간 정도를 봐서도 대략 짐작이 되지요~

3.0버젼업을 앞둔 API 하위 호환성 얘기부터, runtime 변경, api 변경, 새 기능, bugfix... 많군요.
그 중 중요 내용을 정리한 Lucene News에 나온 내용들 중에서도 개인적으로 관심을 갖게된 부분은 

Near real-time search capabilities added to IndexWriter

너무 늦었으니, 오전에 좀 더 꼼꼼히 보고 추가할까 합니다.
그럼 이만

쩝... 계속 발전하는 루씬의 모습을 보면 기분은 좋긴한데...
2.0으로 만들었던 걸 2.3으로 다시 만들어서 런칭한 날 2.4가 나오다니 --;;

게다가 2.4에는 바뀐것도 많다.
심지어 changelog 형식도 바뀌었군요 ㅋㅋ


역시나 별로 관심 없지만 뭐가 바뀌었는지 궁금하긴 한 사람들을 위해 중요 point만 정리해볼까 합니다.

가장 큰 변화
Lucene 2.4.0 includes index format changes that are not readable by older versions of Lucene. Lucene 2.4.0 can both read and update older Lucene indexes. Adding to an index with an older format will cause it to be converted to the newer format.
index format을 또(과거 2.1.0에서 한번 변경 되었다.) 변경하셨다. 그래서 이전 버젼으로 만든 lucene서버에서는 새 index format을 읽을 수 없다. 당연하지만 새 버젼으로 만든 lucene으로는 기존 버젼의 index를 읽을 수 있지만... 

기타 변화들 중 중요한 변화를 change log에서 뽑아볼까 했으나 이미 여기에 정리가 다 되어 있는 것 같아서 그냥 한글로만 정리해 볼까 합니다.

- "InstantiatedIndex"라는 class가 생겼는데, 기존의 RAMDirectory보다 훨씬 빠르다고 한다. 테스트 해 봐야겠네요.

- IndexWrite가 indexing 중에 OS의 문제나 갑자가 power가 꺼져도 index가 깨지지 않는다고 한다. 이건 맘에 들지만.. 여지껏 index가 깨지는 걸 경험하질 못해서... --;;

LUCENE-997 : 검색 시 시간 제약을 둘 수 있게 되었다. 특정 시간이 넘어가지 않도록... 해당 시간이 넘어가면 "TimeExceeded Exception"를 발생시킨다고 한다. 이걸 외부에서 wrapping해서 처리한다고 삽질했던 기억이....

- NIOFSDirectory : to allow multiple threads to read from the same open file without locking. 이걸 쓰면 퍼포먼스가 좀 향상될라나??

- "now the filter is applied to a document before scoring is done" : 예전엔 filter로 거르기 전에 scoring을 다 했었나보네요 --;; filter 쿼리가 많이 빨라지지 않았을까요? 아이고 궁금해라...

- "IndexReader can be opened with new readOnly=true mode" : IndexReader를 readOnly모드로 열면 multithread환경에서 보다 나은 성능을 기대할 수 있다는데... 그럼 IndexSearcher를 그냥 만들면 알아서 readonly 모드로 열릴라나... 이것도 테스트 해봐야겠네요~
소스 받아서 확인해 봤는데... IndexSearcher를 생성하면 내부적으로 알아서 IndexerReader를 readonly로 생성하는군요. 
public IndexSearcher(String path) throws CorruptIndexException, IOException {
        this(IndexReader.open(path), true);
}


위에 나열한 변화 외의 변화들도... 평소의 변화들에 비해는 조금 큰 변화이니 처음 접하는 분들이야 그냥 쓰면 되겠지만 예전부터 사용하는 분들은 꼼꼼히 살펴보는 게 좋을 것 같네요~

그럼.. 게으른 포스팅 여기서 마물...

'programming > Java' 카테고리의 다른 글

lucene 2.9.0 available!! 루씬 새버젼 출시~  (0) 2009.09.29
lucene의 Release 2.2.0 2007-06-19 을 보다가...  (0) 2008.04.10
lucene 2.1.0 released  (1) 2007.02.21
현재 lucene 2.0.0을 쓰고 있는데, 2008년 2월 22일에 나온 2.3.1 버젼을 적용할 필요가 있는지를 살펴보다가, 예전에 블로깅한 lucene내부의 query를 escape하는 함수에 버그가 고쳐진 것을 발견했다.

이상하게도 &와 |에 대해서 escape이 빠져있다 생각했는데.. 버그였다니 --;;

17. LUCENE-881: QueryParser.escape() now also escapes the characters
'|' and '&' which are part of the queryparser syntax. (Michael Busch)

lucene의 버젼 별 변경 내역

'programming > Java' 카테고리의 다른 글

루씬 upgrade 되다!! (Lucene Java 2.4.0 available)  (4) 2008.10.31
lucene 2.1.0 released  (1) 2007.02.21
Java에서 XML관련 예외  (2) 2007.01.30
오늘 lucene 홈페이지 들어갔다가 알게됐다. 2월 14일에 새 release가 발표됐다.

lucene으로 프로그래밍 한 지 좀 지나서 또 가물가물 해졌지만... 그래도 관심이 있어 좀 읽어 봤는데, 몇 가지 내용만 정리해 봤다.

Changes
* 's'와 't'가 StopAnalyzer(StandardAnalyzer에서도 사용됨)의 stopword에서 제거됨.
* StandardAnalyzer의 CJK에 대한 unicode code point ranges가 update됐다.(CJ와 K로 분리됨)
* WildcardQuery의 queryString에 ? 나 *가 포함되어 있지 않으면 알아서 TermQuery를 수행한다. 이전 버젼의 경우에는 StringIndexOutOfBoundsException이 발생했었다
* deprecated되었던 doc.fields() 와 Enumeration을 제거
* write lock 파일이 Index directory에 생성됨. 이전에는 "org.apache.lucene.lockDir" or "java.io.tmpdir"였음.
 - 첨엔 write lock이 어디 있는지 몰라 헤맸었는데, 찾기 쉬워진 듯

New Feature
* ThaiAnalyzer와 ThaiWordFilter가 추가됨
 - 태국어쪽 작업하는 사람은 별로 없겠지만... 요즘 게임업체는 태국에 많이 진출했으니, 그 업체들에서 CS 툴의 검색 기능을 lucene으로 붙일 수 있을 듯 ^^''
* NGramTokenizer와 EdgeNGramTokenizer class 추가됐고, unit test를 통과
 - cjk analyzer는 특정 unicode 범위에 대해서는 2-gram 방식인걸로 알고 있는데, NGram을 응용하면 보다 나은 검색 시스템을 만들 수 있을까???
* IndexWriter에 document를 update(내부적으로는 delete then add)할 수 있는 method추가
 - 귀찮게 delete했다가 add할 것 없이 바로 update할 수 있으니 조금 편할 듯

더 자세한 내용은 아래에서...

출처 : http://svn.apache.org/repos/asf/lucene/java/tags/lucene_2_1_0/CHANGES.txt
XML관련 처리 로직에서 아래와 같은 에러가 났다.

java.lang.NoSuchMethodError: org.w3c.dom.Element.getTextContent()Ljava/lang/String;
    keron.client.xmlutil.SimpleDomBuilder.w3cElemenetToSimpleElement(SimpleDomBuilder.java:43)
    keron.client.xmlutil.SimpleDomBuilder.createSimpleDocument(SimpleDomBuilder.java:32)
    keron.client.xmlutil.SimpleDomBuilder.createSimpleDocument(SimpleDomBuilder.java:19)

대략 sun에서 정의해 놓은 interface를 구현한 외부 구현체를 이용해서 사용하는데, 같은 소스를 독립 app로 돌리면 문제가 없는데, tomcat위에서 돌리면 위와 같은 에러가 난다.
그렇다고 모든 tomcat위에서 예외가 발생하는 것은 아니다.

아마도 그 위에 돌아가는 web app와 관련된 어떤 문제려니... 추측만 무성하다. 회사 동료와 같이 살펴봤는데, 정확한 원인을 못 찾았다.

결국 구글신의 도움으로
http://www.velocityreviews.com/forums/t144510-problems-with-jboss-an-xerces.html
위 사이트에서 다음과 같은 도움을 받았다.

element.getTextContent() // 이 부분 대신

Text contents = (Text) element.getFirstChild();
result.setValue(contents.getNodeValue());

이렇게 변경해서 해결했다. 시간이 없어 정확히 찾아보진 않았지만, 혹시 같은 문제로 고생하는 분 도움이 되시길..

실제 이런 문제를 겪는 경우도 그리 흔치 않고, 아주 가끔 발생한다면 알아 채기도 힘들다.
그래서 그런지 해결책에 대한 논의를 많이 보지도 못했다.

추후 reference 용도로 링크를 하나 달고, 페이지가 삭제될 위험(?)에 대비해 내용을 파일로 저장해 둔다.


관련 글
- A Collection of JVM Options


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




'programming > Java' 카테고리의 다른 글

Java에서 XML관련 예외  (2) 2007.01.30
Lucene 검색 시 and Query와 Filter의 차이점  (2) 2006.09.29
lucene의 Highlighter를 한글에 적용...  (2) 2006.09.12

Lucene 검색을 할 때,

특정 조건을 AND로 추가해서 Query할 수도 있고,
특정 조건을 Filter로 추가해서 Query할 수도 있다.

총 검색되는 갯수는 같지만, 간단하지만 보이지 않는 차이를 정리해 보면...
* AND로 검색을 하면 score에 해당 내용이 반영이 되어 정확도로 정렬할 경우 해당 내용이 반영된다.
* AND로 검색을 하면 별로도 추가로 검색을 하는 것이므로, 부하가 있는 쿼리의 경우는 AND조건 검색보다 Filter로 걸러내는 것이 속도가 빠르다. (검색된 것들 중에서 filtering을 하는 것이니 당연히 빠르겠죠? 전체 인덱스의 크기가 크면 클 수록 and query를 이용한 것 보다 훨씬 빠를테니까요.)

조금 더 자세히 몇 가지를 설명하자면...
Lucene in Action과 현재 licene 2.0 버젼이 filter 부분이 차이가 좀 있는데
DateFilter라는건 없어졌다.

그리고 내 경우는 기존에 사용하던 Filter도 있어서...
추가로 한가지 Filter를 추가한 case라서..

ChainedFilter에 두가지 filter를 추가해서 생성해서 사용했다.
참고 : http://lucene.apache.org/java/docs/api/index.html

Lucene에서는 numeric 범위 연산을 제공하지 않아, 숫자에 대해 범위 연산을 할 경우, 사용하는 자리수 많은 부족한 부분에 0을 채워줘야 한다.

간단하게 예를 들어 0~999까지의 숫자를 range검색하려면... 인덱싱할 때
1 -> 001
42 -> 042
999 -> 999

이렇게 인덱싱을 하고 검색할 때도 "032 TO 311" 이렇게 검색해 줘야만 제대로 검색이 가능하다.
그러므로 속도가 많이 느리다.

아래 출처에 보면, 음수를 포함하는 범위 검색을 하는 방법도 나와 있으니 필요한 분은 참고 하시길...

출처 : http://wiki.apache.org/jakarta-lucene/SearchNumericalFields

출처의 내용은 첨부 파일로 올려 놓는다.


SearchNumericalFields - Jakarta-lucene Wiki.mht



검색 결과에서 검색어를 highlight 시키는 기능을 구현하는데, lucene의 sandbox의 Highlighter를 이용해 봤다.


샘플 소스와 동일하게하고 analyzer만 CJKAnalyzer로 변경했는데... 결과는

"학교에서 우리 선생님께서 나에게 좋은 대학교를 골라 주셨다."에서 "학교"를 검색했다고 가정하면

변환한 결과는 아래와 같이 나온다.
"<B>학교에서</B> 우리 선생님께서 나에게 좋은 <B>대학교를</B> 골라 주셨다"

검색한 단어만이 아닌 조사까지 포함해서 처리가 된다.
혹시 단어만 하일라이팅 시키는 방법을 알고 계신분 있으신가요???


lucene을 이용해 검색을 구현할 때, 검색어에 lucene에서 사용하는 특수기호를 넣으면, 잘못 반영 될 소지가 있어, lucene에서 사용하는 특수 기호들에 대해서는 escape(기호 앞에 \를 추가)을 해 줘야 한다.

정규식을 이용해 간단하게 구현했는데, Lucene in Action 책을 보니 sandbox에 있는 js를 참고하라고 해서 홈페이지에 가 보니 없었다.

결국 알고보니 api에 추가가 되었다.
QueryParse.escape();

나 처럼 뻘짓하는 분 없기를...  

but....

http://lucene.apache.org/java/docs/queryparsersyntax.html
여기 가 보면 lucene에서 사용하는 특수기호들에 대한 설명이 나와 있다.
'+ - && || ! ( ) { } [ ] ^ " ~ * ? : \'

그런데 lucene의 escape 코드를 보면 '&&'와 '||'은 빠져 있다.
(2007년 6월 19일 발표된 2.2.0버젼에서 bugfix 되었습니다.)

직관적으로 이해 하겠지만 search value에  &&는 and로 ||는 or로 변환되어 처리되므로,
실제  &&나 ||를 검색해야 하는 경우 코드를 따다 수정해서 사용해야 할 듯.



실제 lucene 코드

드디어 Dell의 새 모니터와 새 시스템을 받아 기분 좋게 시스템 세팅 중에...
새로 3.2를 설치하고 테스트 하는데 ant build시 제목 표시줄과 같은 에러가 발생

원인은 eclipse 내에 ANT_HOME path가 잘못 걸려 있어서 발생했던 것.

'Window->Preferences->Ant->Runtime' 여기서 ANT_HOME 버튼 눌러 맞는 위치로 설정해 주면 해결~

참고 : http://www.herrodius.com/blog/?p=42

'programming > Java' 카테고리의 다른 글

[갱신]lucene의 검색 값 escape  (0) 2006.09.11
java Date 관련 Quick reference  (0) 2006.07.27
Hibernate Quick Reference  (0) 2006.07.27

* 오늘 날짜 구하기
- new Date();
- Calendar now = Calendar.getInstance();
  now.getTime();

* 어제 날짜 구하기
  Calendar now = Calendar.getInstance();
  now.add(Calendar.DAY_OF_MONTH, -1);
  now.getTime();

* 날짜 포맷을 원하는 형태로 바꾸기
       Calendar now = Calendar.getInstance();
       SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
      sdf.format(now.getTime());    // 결과는 String

* 지 맘데로의 날짜를 담은 문자열을 다른 형태로 convert

        String dateStr = "200707211541122";
        SimpleDateFormat oldFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        SimpleDateFormat newFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
       
        try {
            System.out.println(newFormat.format(oldFormat.parse(dateStr)));
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

* yyyy-MMM-dd 형태 parse 시 주의 할 점
      String regDt = "27/Jul/2006:00:00:00";
       SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MMM/dd:hh:mm:ss",
               Locale.US);

       try {
           System.out.println(sdf.parse(regDt).toString());
       } catch (ParseException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
       }

-> 위와 같이 Locale을 지정하지 않으면 한글 OS에서는 parse 오류가 난다.

* 특정날짜가 무슨 요일인지 알아보기
       String regDt1 = "2006-11-14";
       SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.US);

       Calendar cal = Calendar.getInstance();

       try {
           cal.setTime(sdf.parse(regDt1));
           System.out.println(cal.get(Calendar.DAY_OF_WEEK));
       } catch (ParseException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
       }

주의: cal.DAY_OF_WEEK라고 하면 처음 생성했던 instance의 값을 리턴한다.

 * 날짜 간의 비교
   
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        Calendar now = Calendar.getInstance();
        now.add(Calendar.HOUR, -3);
        Date before3hour = now.getTime();
       
        try {
            if (before3hour.before(sdf.parse(regdttm))) {
                return true;
            } else {
                return false;
            }
        } catch (ParseException e) {
            return false;
        }
Hibernate 사용하기

1. 객체를 이용하여 저장하는 방법
           Transaction tx = session.beginTransaction();
           Cafe cafe = new Cafe();
           cafe = new Cafe();
           cafe.setId(Id);
           cafe.setName(name);
           session.save(cafe);
           tx.commit();


2. key 값을 이용해 값이 존재하는지 확인한 후 저장하는 방법
       Session session = HibernateUtil.getCurrentSession();

       Cafe existCafe = (Cafe) session.get(Cafe.class, grpId);
       
       if (existCafe == null) {
           Transaction tx = session.beginTransaction();
           Cafe cafe = new Cafe();
           cafe = new Cafe();
           cafe.setId(id);
           cafe.setName(name);
           session.save(cafe);
           tx.commit();
           System.out.println("inserted");
       }
       else{
           System.out.println("already exist");
       }

       HibernateUtil.closeSession();

3. key가 아닌 값을 이용해 존재하는지 확인한 후 저장하는 방법
* createQuery 안의 문장은 SQL Query가 아니라 Hibernate에서 사용하는 HQL(Hibernate Query Language) 이다.
  * 자세한 문법은 http://www.hibernate.org/hib_docs/v3/reference/ko/html/queryhql.html

       Session session = HibernateUtil.getCurrentSession();

       Keyword k = (Keyword) session.createQuery(
               "select k from Keyword as k where keyword = ?").setString(0,
               keyword).uniqueResult();
       if (k == null) {
           Transaction tx = session.beginTransaction();
           Keyword kw = new Keyword();
           kw.setKeyword(keyword);
          
           session.save(kw);
           tx.commit();
           System.out.println("inserted");
       } else {
           System.out.println("already exist");
       }

       HibernateUtil.closeSession();

4. 자동 증가값 받기
* 걍 강제 casting
   int id = (Integer) session.save(kw);

5. DB의 identity 컬럼 관련 XML 설정
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="net.daum.cafe.search.weblog.entity">
   <class name="Keyword" table="tKeyword">
       <id name="id" column="id">
           <generator class="identity" />
       </id>
       <property name="keyword" type="string" column="keyword" />
   </class>
</hibernate-mapping>

6. 복합키 관련 XML 설정
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="net.daum.cafe.search.weblog.entity">
   <class name="DTBC" table="tableD">
       <composite-id>
           <key-property name="Id" type="int" column="Id" />
           <key-property name="keywordId" type="int" column="keywordId" />
       </composite-id>
       <property name="count" type="int" column="count" />
   </class>
</hibernate-mapping>
* 참고 : 복합키를 구현하려면 Serializable을 반드시 implements해 주어야 한다. 그렇지 않으면 'composite-id class must implement Serializable' 예외가 발생한다.

걍 5초가 걸리는 작업들 10개를 ThreadPool 5개에 넣고, 10개의 작업이 끝날 때까지 기다리는 코드

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class TestThread {

   private static ExecutorService indexLoadService = Executors
           .newFixedThreadPool(5);

   public static void main(String[] args) {
       for (int i = 1; i < 10; i++) {
           indexLoadService.execute(new TTest(i));
       }

       indexLoadService.shutdown();
       try {
            // 2초에 한번씩 check한다.
            // awaitTermination의 경우 작업이 종료되었으면 true를 그렇지 않고 timeout이 지났으면 false를 리턴한다.
           while(!indexLoadService.awaitTermination(2000, TimeUnit.MILLISECONDS)){
           }
       } catch (InterruptedException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
       }

       System.out.println("Done");
   }

   static class TTest implements Runnable {
       private int num;

       TTest(int num) {
           this.num = num;
       }

       public void run() {
           System.out.print(".");
           try {
               Thread.sleep(5000);
           } catch (InterruptedException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
           }
           System.out.println("finish " + num);
       }

   }
}

'programming > Java' 카테고리의 다른 글

Hibernate Quick Reference  (0) 2006.07.27
Java Puzzlers : 9. Tweedledum  (0) 2006.07.19
Javolution  (0) 2006.07.14
문제는 역시 간단...

x += i;

x = x + i;

와 같지 않다.

왜????

'programming > Java' 카테고리의 다른 글

concurrent 패키지를 이용 간단한 ThreadPool 돌리기  (3) 2006.07.24
Javolution  (0) 2006.07.14
Java Tuning White Paper  (0) 2006.07.13
요즘 점점 XML을 많이 사용해 가는 추세에 맞춰 java 진영에도 다수의 XML 관련 라이브러리들이 존재한다.

나 역시도 어떤 결과 값을 XML로 만들 필요가 생겼는데, 결과 Object를 알아서 XML로 만들어주면 얼마나 좋을까라는 생각에 관련 라이브러리들을 찾다가 아래와 같은 사이트를 발견했다.

XML data to Java classes 를 위한 라이브러리들에 대한 벤치마크를 한 사이트...
https://bindmark.dev.java.net/

눈에 띄는 두개의 라이브러리가 있으니,
JIBX와 Javolution

둘 다 간략하게 리뷰를 해 본 결과 실제 사용하는 사람 입장에서 좀 편한 것을 택하게 되었으니,
그 놈이 Javolution이었다.

Javolution은 단순히 XML관련 라이브러리만이 아니고, 기타 다른 여러 개의 라이브러리 묶음 중 XML관련 기능도 제공하는 것이었다.

이 넘을 이용해 잘 사용하고 있는데... 문제가 발생했다. 서버가 뻗는 --;;
여러 모로 원인을 찾다가... 아무래도 Javolution에 문제가 있는게 아닐까 하는 생각에 만든 사람한테 미친척 오늘 새벽에 메일을 보내봤다. thread dump뜬 내용과 간단한 상황설명과 관련 소스 조금...

그런데... 아침에 와보니 답변이 와 있었다.~~

답장 메일


한편으로 무지 반가웠지만 한편으로는 좀 원망스럽기도 했다. (그 간의 맘 고생을 생각하면...)

엉망으로 보낼 질문 메일의 원문은 공개하기 꺼려져 공개하지 않는다...

뭐... 위 메일대로 수정해서 테스트 중인데, 정말 해결될 지는 잘 모르겠지만...
잘 되길 바라며..

혹시 Javolution을 사용하고 있는 분 특히 CDATA 출력을 위해 CharacterData를 사용하시는 분 참고하시기 바랍니다.

이상~~ 


'programming > Java' 카테고리의 다른 글

Java Puzzlers : 9. Tweedledum  (0) 2006.07.19
Java Tuning White Paper  (0) 2006.07.13
RMI 연결 시 timeout이 안나는 문제  (0) 2006.07.07
돌아댕기다 이런 문서도 발견했네요...

Java Tuning White Paper

'programming > Java' 카테고리의 다른 글

Javolution  (0) 2006.07.14
RMI 연결 시 timeout이 안나는 문제  (0) 2006.07.07
linux 서버 app를 local jconsole에서 monitoring하기  (0) 2006.07.07
--;; 거의 3시간은 헤맨것 같다.

대환님의 도움으로 정말 황당하게 해결했다.
로컬에서는 RMI 서버가 없을 경우 RMI client가 연결을 시도할 때, timeout exception이 잘 나는데... 서버에서 내 컴으로 테스트를 하면, lookup하는 부분에서 먹통이 되어 버렸다.

이 부분 찾는건 역시 최고의 debug 방법인 stdout을 이용했다 --;;

알고 보니 원인은 windows xp에 설치된 방화벽!!!

왜 그런지 모르겠지만 방화벽에 대고 lookup을 하면 connection timeout exception이 발생하지 않았다.
혹시 아시는 분 알려주시면 ㄳ...

참고로... vm에 rmi 관련 timeout 시간을 다 짧게 주고 해도 동일했다.


<<서버에서 할 작업>>
local에서 띄울 땐 -Dcom.sun.management.jmxremote 이 옵션만 추가하고 jconsole를 띄우면 해결되지만 서버의 경우 몇 가지 옵션 설정이 더 필요하다.

-Dcom.sun.management.jmxremote.port=1818
이 옵션은 아마 빼게되면 rmi기본 port인 1099를 이용하겠지만, 내 경우는 내부적으로 사용하고 있어 다른 port 지정

-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
일단 언능 해 보기 위해 두가지 인증 절차 안거치게 설정

ant를 이용할 경우
           <jvmarg value="-Dcom.sun.management.jmxremote" />
           <jvmarg value="-Dcom.sun.management.jmxremote.port=1818" />           
           <jvmarg value="-Dcom.sun.management.jmxremote.authenticate=false" />
           <jvmarg value="-Dcom.sun.management.jmxremote.ssl=false" />

<<로컬에서 할 작업>>

jconsole 띄우고 서버 주소와 port 번호만 넣고 connect하면 성공



참고 url : http://java.sun.com/j2se/1.5.0/docs/guide/management/agent.html#no_security

'programming > Java' 카테고리의 다른 글

RMI 연결 시 timeout이 안나는 문제  (0) 2006.07.07
Java Puzzlers : 1. Oddity  (0) 2006.07.03
jstat - Java 가상 머신 통계 데이터 감시 툴  (0) 2006.06.30
아래 코드가 제대로 작동 할 것인가?

-- CODE start --
   public static boolean isOdd(int i){
       return i % 2 == 1;  
   }
-- CODE end --

조금 주의 깊게 생각해 보면 쉽게 알 수 있을지 모르겠지만 --''


이상 오늘 공부한 내용 끝~




출처 : Java Puzzlers

목차는 아래와 같다.
  * 개요
  * 설명
  * 가상 머신 식별자
  * 옵션
       - 일반적인 옵션
       - 출력 옵션
  * 예
  * 관련 항목

출력 header 들에 대한 설명도 같이 나와 있다.

출처 : http://pllab.kw.ac.kr/j2seapi/tooldocs/share/jstat.html#examples

lucene에 (YYYYmmDDHHMMSS) 형태로 저장된 컬럼에 대해 sort를 했는데, 결과가 정확히 소트가 되지 않는 문제가 있었다.

 

 

sort를 할 때는 여러 가지 형태로 가능한데.. 가장 간단한 형태인

- searcher.search(new TermQuery(new Term("dataname", "1")), new Sort("regdt");

 

 

이 경우 Sort객체 안에서 대상 컬럼을 소트하기 전 적절한 형태로 type casting을 하게 되는데, 아무 옵션이 없을 경우 lucene은 먼저 int 그 다음 float으로 그 다음 String으로 casting을 해 보게 된다.

 

위와 같이 YYYYmmDDHHMMSS 형태의 데이터는 두번째 float로 casting이 되어 버리면서 문제가 발생하게 된다.

 

Float.parseFloat("20051004130501")=2.00510045E13
Float.parseFloat("20051006102501")=2.00510066E13
Float.parseFloat("20051005102501")=2.00510045E13

 

그래서 정렬이 제대로 안되는 문제가 있다. 이 문제를 해결 하려면 아래와 같이 SortField를 생성하면서 type을 정해줘야 한다.

Sort sort = new Sort(new SortField("regdt", SortField.STRING, true));
searcher.search(new TermQuery(new Term("dataname", "1")), sort);

 

SortField.Auto라는 것이 있는데, 이 값이 default이고 그렇게 하면 역시 Float로 casting 되어 버리니 반드시 SortField.STRING으로 고정해줘야 한다.

 

아래는 위에 설명된 부분의 실제 lucene 소스 코드이다. (ver 2.0)

 

try {
       Integer.parseInt(termtext);
       ret = getInts(reader, field);
} catch (NumberFormatException nfe1) {
       try {
             Float.parseFloat(termtext);
             ret = getFloats(reader, field);
        } catch (NumberFormatException nfe2) {
             ret = getStringIndex(reader, field);
        }
}

 

** 참고로 String은 Int나 Float에 비해 성능이 떨어진다고 한다.

 

참고 사이트 : http://mail-archives.apache.org/mod_mbox/lucene-java-dev/200511.mbox/%3c729868946.1132944655882.JavaMail.jira@ajax.apache.org%3e

'programming > Java' 카테고리의 다른 글

jstat - Java 가상 머신 통계 데이터 감시 툴  (0) 2006.06.30
linux signal 처리하는 방법  (0) 2006.05.27
Java web app monitoring for JAMON  (0) 2006.05.16

Jamon 사용법

 

Jamon이란
The Java Application Monitor (JAMon) is a free, simple, high performance, thread safe, Java API that allows developers to easily monitor production applications

http://jamonapi.sourceforge.net

 


web app 모니터링을 위한 초간단 사용법
1. JAMon.jar를 Tomcat root/Common/lib에 넣는다
2. 모니터링을 원하는 web application web.xml에 아래의 filter를 추가한다.

 <filter>
    <filter-name>JAMonFilter</filter-name>
    <filter-class>com.jamonapi.JAMonFilter</filter-class>
   </filter>

   <filter-mapping>
    <filter-name>JAMonFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

뭐 내용을 보면 알겠지만 url-pattern을 수정해서 원하는 요청만 모니터링할 수도 있겠지만..

3. JAMon.war를 web root에 복사하면 준비 끝
4. http://host:port/JAMon/JAMonAdmin.jsp 여기에 접속하면 아래와 같은 모니터링 결과가 나온다.

 

응용
기본적으로는 웹 요청시작부터 결과를 받은 시점까지의 시간이 계산되므로, 내부 로직들의 수행 시간을 구체적으로 알고 싶으면,
아래와 같은 코드를 추가하면 된다.
import com.jamonapi.*;
...
Monitor mon=MonitorFactory.start("myFirstMonitor");
...Code Being Timed...
mon.stop();

그러면 start안에 넘긴 parameter이름으로 monitoring 항목이 하나 더 생긴다.


* 주의 사항
JAMon webappr와 내 web app가 같은 JAMon.jar를 이용해야만 모니터링 결과를 JAMon webapp에서 확인할 수 있으므로,
내 web app에서 build path와 classpath에 tomcat/common/lib를 잡아줘야만 결과를 확인할 수 있다.
(첨에 내 web app에 별도의 jamon.jar를 import하고 테스트 했다가 결과가 안나와서 잠시 당황했었음 --;;)

 

 


 
 
 
위 그림에서 RMIQuery와 ToXml 이 부분이 코드상에 추가한 모니터링 결과 임
 
이상~

 

RMI Clinet를 만들어 Tomcat에서 돌리다가 아래와 같은 에러가 발생했다.

java.rmi.UnmarshallException: error unmarshalling arguments; nested exception is:
java.net.MalformedURLException: no protocol: Files/Apache.

RMI client와 Server 테스트는 잘 됐는데 왜 안될까
거의 3시간 삽질하다가.. 겨우 알았다 --;;


http://forum.java.sun.com/thread.jspa?threadID=367368&tstart=0
여기 보면 사람들이 달아 놓은 답변들이 있는데...

해결책
1. tomcat을 space를 포함하지 않는 경로에 설치한다.(JRE는 상관없을라나 --;;)
2. 문제가 되는 경로의 space를 %20으로 바꿔 아래와 같이 사용한다.
 * file://c:/program%20files/some/other/path


내 경우에는 내가 사용하는 특정 경로의 문제라기 보다 내부적으로 사용되는 경로에 문제가 있는것 같아서, 어디 한 군데를 찾아 바꿔서 될 일이 아닌거 같아 1번을 선택해야 할 듯
함 해보고 결과를 다시 적을 생각이다.

위 글에 보면 아래 링크에 버그 리포팅이 되었다고 한다.

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4496398
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4273532

이상



* 테스트 후기 *

역시 tomcat만 다시 깔았는데 잘 된다 --;;

삽질한거 생각하면 좀 열받지만... 결국 원인을 찾아 해결을 해서 기분은 좋다

<< class not found 에러 >>

MyRemote service = new MyRemoteImpl();
Naming.rebind("RemoteHello", service);

* 위와 같은 코드를 통해 RMI서버를 등록하는 과정에서 class not found 에러가 나는 경우가 있는데, 이 이유는 rmiregistry를 실행하는 쪽에 classpath에 rmi server 관련 class들의 classpath가 지정되어 있지 않은 경우 발생하므로 rmiregistry를 실행하기 전에 아래와 같이 classpath를 추가해 준 후에 실행하면 된다.

D:>set classpath CLASSPATH=D:\jdk1.5.0_06;D:\Source\RMIServerTest\bin


 

<< 원격서버 객체를 RMI 등록부에 등록할 때 사용하는 이름>>

Naming.rebind("Remote Hello", service);
위와 같은 코드를 통해 등록하게 되는데, 어떤 책에는 이름에 위와 같이 공백이 들어간 경우가 있는데 그러면 에러가 나므로 공백은 삭제

 

 

<< clinet쪽에 필요한 파일 >>

client쪽에는 rmic를 통해 생성된 xxx_Stub.class 파일과 RMI서비스에 사용되는 interface 두개가 필요하다.

rmic HelloImpl

 

여러 책이나 문서에 나온데로 꼴랑 위와 같이 명령을 내릴 경우 target이 되는 class의 classpath가 잡히지 않아서

 

"Class HelloImpl not found."

 

위와 같은 오류가 날 수 있다.

 

classpath 변경없이 아래와 같은 명령으로 한방에 해결할 수 있다.

 

rmic -classpath . -d . HelloImpl

 

 

* package 명이 있는 경우

class파일이 있는 디렉토리 root에서

 

rmic -classpath . -d . rmiTest.HelloImpl

 

위와같이 package 명까지 다 적어준다.

 

 

예전에 해 보고, 다시 하려다 기억이 안나서 --;;

 

정말 이건 거지 같다고 생각함... 찾기 너무 어려움

 

        DateFormat sdFormat = new SimpleDateFormat("yyyyMMdd");
       
        String birthdayStr ="19790806";
        Date birthDay = sdFormat.parse(birthdayStr);

 

'programming > Java' 카테고리의 다른 글

rmic로 Stub와 Skeleton 생성 시 오류  (0) 2006.05.11
서블릿에서 한글 처리  (2) 2006.03.21
[펌] JDBC Driver load 하는 3가지 방법  (3) 2006.01.10

+ Recent posts