반응형
0. Java Profiling API란?

프로파일러라고 함은 application의 문제를 진단하고 성능을 측정하기 위해서 사용하는 도구임.
Java관련한 application은 JVM의 정보를 가져와야 하는데 이를 위해서 자바에서 제공하는 API이다.

JVMPI for Java 1.3, 1.4
- 클래식 자바 가상머신에서 잘 동작하도록 설계되어 있음
- 이벤트 기반 모델 방식
- Sun에서 실험적이라는 표현을 사용하기도 하고 Java 1.6에서부터는 사용하고 있지 않음
- 이번 application에서는 Java 1.6이라 이 방식을 활용한 tool에 대한 조사는 하지 않음

JVMTI for Java 1.5 이상
- ByteCode Instrumentation(BCI)라는 방법을 통하여 사용함
- 모니터링하고자 하는 바이트 코드의 정확한 위치에 프로파일링 코드를 추가함으로써 수행함
- 아래에 설명되는 거의 모든 기술이 이 방식을 통해서 사용하고 있음

Profiling Tool은 정보수집/분석/정보수집 & 분석 을 담당한다.
따라서 수집만 하는 툴은 눈으로 직접 분석하던지 분석을 하는 툴을 따로 써야 한다.

관련자료 : http://openframework.or.kr/Wiki.jsp?page=JvmtiNjvmpi


1. Jstack

1.1 정보를 수집하는 Tool이다.
1.2 Thread Dump를 뜨는 자바의 기본적인 명령어이다.
1.3 윈도우는 Java 1.6에서부터 사용가능, 리눅스용은 Java 1.4부터 가능
1.4 사용방법
   - jps 를 이용해서 java의 프로세스를 찾는다 : C:\Java\jdk1.6.0\bin>jps -v
   - 발견한 PID를 이용해서 Thread Dump를 뜬다 : C:\Java\jdk1.6.0\bin>jstack 4740 > st.txt
    - Dump 내용 예시
      "hmux-127.0.0.1:6802-9" daemon prio=10 tid=0x9e3ad400 nid=0x17b9 runnable [0x9d3fd000..0x9d3fdfa0]
      java.lang.Thread.State: RUNNABLE
      at java.net.SocketInputStream.socketRead0(Native Method)
      at java.net.SocketInputStream.read(SocketInputStream.java:129)
      at com.caucho.vfs.SocketStream.read(SocketStream.java:175)
      at com.caucho.vfs.ReadStream.readBuffer(ReadStream.java:1012)
      at com.caucho.vfs.ReadStream.waitForRead(ReadStream.java:336)
      at com.caucho.server.port.TcpConnection.run(TcpConnection.java:598)
      at com.caucho.util.ThreadPool$Item.runTasks(ThreadPool.java:690)
      at com.caucho.util.ThreadPool$Item.run(ThreadPool.java:612)
      at java.lang.Thread.run(Thread.java:619)
1.5 Dump 내용을 분석하는 법 : http://www.j2eestudy.co.kr/lecture/lecture_read.jsp?db=lecture0201_1&table=j2ee&id=24
1.6 장단점
    - 특별한 Coding 을 필요로 하지 않는다.
    - 문제가 발생한 시점에 명령어를 수행해서 Hang이 걸린 Thread의 정보를 찾아낼수 있다.
    - 눈으로 찾아야 하기에 연습을 통한 숙달이 필요하다.
1.7 참고자료 : http://kwon37xi.egloos.com/2871508


2. HPRof

2.1 정보를 수집하는 Tool이다.
2.2 Heap And CPU Profilling Agent 의 약자, JDK에서 기본적으로 제공해준다.
2.3 HPRof로 수집된 데이터를 Heap Analyzer로 다시 분석한다.
2.4 사용방법 (resin 3.1.X 기준)
    - resin.conf 파일을 오픈한다
   - JVM arguments 항목에 <jvm-arg>-agentlib:hprof=heap=sites,cpu=samples,file=d:\zeous\profiling.txt</jvm-arg> 넣는다.
2.5 수집데이터 예시
    TRACE 300539:
    java.security.ProtectionDomain.getCodeSource(ProtectionDomain.java:Unknown line)
    java.lang.ClassLoader.postDefineClass(ClassLoader.java:Unknown line)
    java.lang.ClassLoader.defineClass(ClassLoader.java:Unknown line)
    java.security.SecureClassLoader.defineClass(SecureClassLoader.java:Unknown line)
2.6 장단점
   - 데이터가 엄청나게 많이 생성된다 (모든 데이터를 다 기록하는듯)
   - JVM 옵션을 주고 서버를 구동시키면 한참 느려진다
   - 프로파일 데이터에 실시간 기록이 아니라 서버를 종료하거나 action (Ctr+break)을 해줘야 기록된다.
2.7 참고자료 : http://wiki.ex-em.com/index.php/HProf


3. ASM

3.1 정보를 수집&분석하는 Tool 이다.
3.2 BCI의 API 를 이용해서 가장 low 레벨로 컨트롤하는 방법임
3.3 HPRof가 모든 class에 대한 분석임에 반해 이 방법은 특정 클래스에 대한 action을 원하는 형태로 지정(코딩)할수 있다.
3.4 장단점
    - 특정 class에 대한 컨트롤이 가능하다(예, connection 연결이 몇번 호출되었는지 카운트가능)
    - 자유도가 높은 만큼 처음부터 코딩해야 한다.
3.5 참고자료
    - http://somnusong.tistory.com/275
    - http://asm.objectweb.org/index.html

4. Jconsole

4.1 정보수집 & 분석해주는 Tool이다.
4.2 JDK1.5 부터 포함된 로컬, 원격 자바 application 분석툴
4.3 자료수집 및 Swing으로 구성된 분석 UI까지 제공한다
4.4 사용법 (resin 3.1.X 기준)
    - resin.conf 파일을 오픈한다
    - JVM argument 항목에
      <jvm-arg>-Dcom.sun.management.jmxremote</jvm-arg>
      <jvm-arg>-Dcom.sun.management.jmxremote.port=1403</jvm-arg>
      <jvm-arg>-Dcom.sun.management.jmxremote.ssl=false</jvm-arg>
      <jvm-arg>-Dcom.sun.management.jmxremote.authenticate=false</jvm-arg> 넣는다
4.5 장단점
    - 자료를 수집하는 과정에서도 서버의 부하가 거의 없다.
    - 특별한 코딩을 하지 않고 분석된 자료까지 UI를 통해서 제공 받는다
    - id/password를 설정해서 입력받기도 가능한데 설정이 조금 까다롭다. (성공못하였음)
    - Jstack으로 생성되는 Thread Dump 의 자료는 모두 포함하고 있음
    - Jconsole을 다시 실행시키면 지금까지의 내용이 저장되지 않고 처음부터 다시 시작한다
4.6 참고자료
    - http://java.sun.com/javase/6/docs/technotes/guides/management/jconsole.html
    - http://sjchoi.wordpress.com/2007/01/10/jconsole-사용하기/
    - http://www.mimul.com/pebble/default/tags/jmx/


5. Jennifer

5.1 정보수집 및 분석을 해주는 상용 Tool이다
5.2 2주간의 무료 라이센스를 얻어서 테스트 가능하다.
5.3 Jconsole은 자료를 저장할 수 없는 단점을 상용 Tool답게 분석된 로그를 저장해서 가지고 있다.
5.4 사용법 (resin 3.1.x기준)
    - 설치메뉴얼 : http://www.jennifersoft.com:8080/man/viewer/DocumentViewer.jsp?id=abc385f1-e652-48e5-8616-e24b13014734
    - 설치메뉴얼 이외에 http_service_class = javax.servlet.http.HttpServlet;com.caucho.jsp.JavaPage 를 W11.conf에 넣어줘야 한다
    - localhost로 나와있는 정보를 모두 IP정보로 셋팅해준다
5.5 사용메뉴얼 : http://www.jennifersoft.com/docs/ko/77.html
5.6 장단점
    - 돈이 든다 ^^
    - 실시간 경고 및 모니터링에 뛰어난 장점을 보여준다.
반응형
반응형
오픈소스테스트툴이 있는 사이트다..
http://www.opensourcetesting.org/


성능테스트 툴 목록 사이트
http://www.opensourcetesting.org/performance.php

반응형

IBM developerWorks에서 독자, 필자, 리뷰블로거 등이 함께하는 즐거운 이야기 장을 마련합니다. 이름하여, ‘개발자들의 수다’ 입니다.
이 행사는 '현장에서 참여자들이 토론 주제를 정해서 실시간으로 자유로이 이합집산하면서 토론을 진행'하는 OST(Open Space Technology) 형식으로 진행할 예정입니다.
정해진 아젠다 없이, 현장에서 함께 얘기 나눌만한 주제를 정하거나 건의해서 독자, 필자, 리뷰블로거들이 편안하게 생각을 나누고 그 과정에서 서로 영감을 받을 수 있는 행사입니다.
개발자로서의 진로, 고민이나 기술 및 트렌드에 대한 난상 토론 등 어떤 내용이어도 무방합니다.
독자, 필자, 리뷰블로거가 한자리에 모일 수 있는 올해 처음이자 마지막으로 열리는 이번 행사에서 개발자들의 수다가 활발하게 이뤄지도록 많은 분들의 참석을 기대합니다.

  • 일 시: 11월 8일 토요일 오후 2:00~6:00
  • 장 소: 도곡동 군인공제회관 23층 온디맨드홀 (약도 참고)
  • 참가 신청
    참가 신청은 전자우편(dWkorea@kr.ibm.com)으로 해주시고, 신청시 이름, 소속, 연락처 등을 적어서 보내주시기 바랍니다.
    장소 관계상 참가 신청은 선착순 200명으로 한정하니, 빠른 신청을 부탁드립니다.


* 여러분들이 이 곳을 채워주세요.
반응형

수행 결과 및 상태 코드

오라클과 알티베이스의 실행 시간 에러 처리를 위한 SQLSTATE, SQLCODE, SQLCA 값의 차이점을 비교한다.

SQLCA

내장 SQL문의 수행 결과를 저장하는 구조체로서 알티베이스에서 사용하는 구성 요소는 sqlcode, sqlerrm.sqlerrmc, sqlerrm.sqlerrml, sqlerrd[2]이며 오라클의 SQLCA에만 존재하고 알티베이스에서 지원하지 않는 구성 요소는 사용할 수 없다.(e.g sqlwarn)

SQLCA의 선언
  • 오라클

    EXEC SQL INCLUDE SQLCA;

    또는

    #include <sqlca.h>

  • 알티베이스

    별도의 선언없이 사용할수 있다.

sqlca.sqlcode 상태값
  • 오라클

    Status Code Description
    0 SUCCESS
    >0 No row returned
    <0 database, system, network , application error
     
  • 알티베이스

    Status Code Description
    SQL_SUCCESS SUCCESS
    SQL_SUCCESS_WITH_INFO  
    SQL_NO_DATA No row returned
    SQL_ERROR  
    SQL_INVALID_HANDLE  
     
sqlca.sqlerrm

오라클과 알티베이스에서 sqlerrmc, sqlerrml은 용도와 사용법이 동일하다.

sqlca.sqlerrd[2]
  • 오라클

    INSERT/UPDATE/DELETE/SELECT INTO 연산에 의해 영향받은 레코드 개수(누적 레코드 개수)

  • 알티베이스

    INSERT /UPDATE /DELETE 연산에 의해 영향받은 레코드 개수

    SELECT 문이나 fetch문 수행시 출력 호스트 변수가 배열일 때 리턴되는 레코드 개수

SQLSTATE

SQLSTATE에는 상태 코드가 저장되며 이 상태 코드를 통해 에러와 예외 상황의 종류를 알 수 있다.

SQLSTATE의 선언과 사용
  • 오라클

    전처리기의 명령행 옵션으로 MODE=ANSI를 선언하고 사용

    char SQLSTATE[6];

  • 알티베이스

    별도의 선언 없이 사용한다.

SQLSTATE의 상태 코드

오라클과 알티베이스의 SQLSTATE 상태 코드는 그 의미와 코드값이 다르므로 코드 테이블에 따라서 변환되어야 한다.

SQLCODE

SQLCODE에는 내장 SQL문 수행 후 에러 코드가 저장된다.

SQLCODE의 선언과 사용
  • 오라클

    전처리기의 명령행 옵션으로 MODE=ANSI를 선언하고 사용

    long SQLCODE;

  • 알티베이스

    별도의 선언 없이 사용할수 있다.

    알티베이스에서의 SQLCODE의 자료형은 int 형이다.

SQLCODE의 상태코드값
  • 오라클

    sqlca.sqlcode와 동일한 상태 코드 값이 저장된다.

  • 알티베이스

    Status Code Description
    0 내장 SQL문을 성공적으로 수행한 경우. 즉, sqlca.sqlcode 값이 SQL_SUCCESS 인 경우
    1 내장 SQL문을 수행하였으나 예외 상황이 발견된 경우. 즉, sqlca.sqlcode 값이 SQL_SUCCESS_WITH_INFO 인 경우
    100 SELECT문이나 FETCH문 수행 후 리턴되는 레코드가 없는 경우. 즉, sqlca.sqlcode 값이 SQL_NO_DATA인 경우
    -1 내장 SQL문 수행 시 에러가 발생하였지만 해당 에러코드가 없는 경우. 이 때의 sqlca.sqlcode 값은 SQL_ERROR 이다.
    -2 데이터베이스 서버와 연결하지 않고 내장 SQL문을 수행한 경우, 즉, sqlca.sqlcode 값이 SQL_INVALID_HANDLE 인 경우
    위의 값 이외에 SQLCODE에 설정되는 경우는 에러 메시지가 있는 경우로서 해당 SQL에서 에러가 발생한 경우이다.
반응형
src 디렉터리에 package 가 aaa.bbb.ccc의 형태로 되어 있을 때....

       <target name="compile">

             <mkdir dir="${build}"/>

             <javac destdir="${build}">

                    <src path="${src}"/>

                    <include name="**/*.java"/>

             </javac>

             <copy todir="${build}/aaa/bbb/ccc">

                    <fileset dir="${src}/aaa/bbb/ccc">

                           <include name="*.xml"/>

                           <include name="*.jsp"/>

                    </fileset>

             </copy>

       </target>

컴파일(javac)의 경우에는 destdir에 하위 폴더를 지정해주지 않아도 자동 생성된다.
그러나 copy의 경우에는 하위폴더를 지정해주지 않는다면
(만약 copy todir="${build}" 라고만 한다면 build 디렉터리에 카피될 것이다.

반응형
<< 참고사이트 >>
Apache Ant 1.7.0 Manual : http://ant.apache.org/manual/

Ant 기본구조 및 태스크는 아래 블로그를 참조하자.
잘 정리되어 있는 듯...

Ant 자바 빌드 툴 I : 기본 구조 : http://blog.naver.com/thdusin/100005914122
Ant 자바 빌드 툴 II : 태스크 : http://blog.naver.com/thdusin/100005926620

더 자세한 task를 알고 싶다면 apache 사이트를 참조하자.
Overview of Ant Tasks : http://ant.apache.org/manual/tasksoverview.html


build.xml 은 하나의 project 요소를 가진다.
project 요소는 target 요소를 포함하고, 각 target은 여러 task를 포함한다.
간단한 구조는 다음과 같다.

<project name="project_name" default="default" basedir=".">
      
<target name="compile" description="compile">

       <!--compile이라는 target name 대한 설명(description)-->

             ...

       </target>

      

       <target name="dist" depends="compile">

       <!-- dist target compile 의존.
       compile target 실행 후에 dist target이 실행된다. -->

             ...

       </target>

 

       <target name="doc">

             ...

       </target>

</project>  



※ 예제 :

사용자 삽입 이미지
test1과 test2 패키지를 test1_2.jar 파일로 묶고,
test2와 test3 패키지를 묶어 test2_3.jar 파일로 묶는다.
javadoc 을 만들고,
lib폴더와 jar 파일들을 zip으로 묶는다.














<project name="ant" default="test1_2" basedir=".">

      

       <tstamp/>

       <!-- property -->

       <property name="src" location="src"/>

       <property name="build" location="build"/>

       <property name="lib" location="lib"/>

       <property name="dist" location="dist"/>

       <property name="doc" location="doc"/>

            

       <!-- compile -->

       <target name="compile" description="compile">

             <mkdir dir="${build}"/>

             <javac srcdir="${src}" destdir="${build}"

                classpath="${lib}/log4j-1.2.8.jar"/>

       </target>

      

       <!-- test1 test2 jar 묶는다 -->

       <target name="test1_2" depends="compile"

             description="test1 and test2 packaging">

             <mkdir dir="${dist}"/>

             <jar jarfile="${dist}/test1_2.${DSTAMP}.jar">

                    <fileset dir="${build}">

                           <exclude name="test3/*.*"/>

                    </fileset>

             </jar>

       </target>

      

       <!-- test2 test3 jar 묶는다 -->

       <target name="test2_3" depends="compile"

             description="test2 and test3 packaging">

             <mkdir dir="${dist}"/>

             <jar jarfile="${dist}/test2_3.${DSTAMP}.jar">

                    <fileset dir="${build}">

                           <exclude name="test1/*.*"/>

                    </fileset>

             </jar>

       </target>

      

       <!-- doc -->

       <target name="doc" depends="test1_2, test2_3">

             <mkdir dir="${doc}"/>

             <javadoc destdir="${doc}">

                    <fileset dir="${src}"/>

             </javadoc>

       </target>

      

       <!-- zip -->

       <target name="zip" depends="test1_2, test2_3">

             <copy todir="${dist}/lib">

                    <fileset dir="${lib}"/>

             </copy>

             <zip destfile="test_${DSTAMP}.zip">

                    <fileset dir="${dist}"/>

             </zip>

       </target>

      

       <!-- delete -->

       <target name="delete" depends="doc, zip">

             <delete dir="${build}"/>

       </target>

      

</project>


 
※ 설명 :
<!-- project -->
그냥 Run As 했을 경우, default 로 설정된 target이 실행된다.
default : Run as 시, 기본적으로 사용할 target name
basedir : base directory. 현재 디렉터리(.)이다.

<!-- property -->
property : 속성을 지정한다. 대소문자 구별.
<property name="src" location="src" />
src 라는 이름의 속성으로 경로(./src)를 지정한다.
다른 부분에서 이 속성을 참조하려면 "${src}" 라고 쓴다.
<javac srcdir="${src}" destdir="${build}" />
( value 와 location )
value : the value of the property.
location : Sets the property to the absolute filename of the given file. If the value of this attribute is an absolute path, it is left unchanged (with / and \ characters converted to the current platforms conventions). Otherwise it is taken as a path relative to the project's basedir and expanded.


<!-- compile -->
<mkdir dir="${build}"/>
build 라는 디렉터리를 만든다.
<javac srcdir="${src}" destdir="${build}" classpath="${lib}/log4j-1.2.8.jar"/>
src 디렉터리(하위 디렉터리 포함)의 java 파일을 컴파일해 build 디렉터리에 저장하고,
클래스패스에는 log4j-1.2.8.jar가 포함된다.

<!-- test1 test2 jar 묶는다 -->
<jar jarfile="${dist}/test1_2.${DSTAMP}.jar">
    <fileset dir="${build}">
         <exclude name="test3/*.*"/>
    </fileset>
</jar>

property 윗부분에 <tstamp/> 가 있다.
이는 DSTAMP, TSTAMP, TODAY 프로퍼티를 설정하는 것이다.
· DSTAMP : yyyyMMdd
· TSTAMP : hhmm
· TODAY  : MMM dd yyy
build 디렉터리에서 test3 패키지의 파일들을 제외(exclude)한 파일들을 jar로 묶어
dist 에 test1_2.날짜.jar 형태로 저장한다.
(ex. test1_2.20070802.jar)
fileset dir 하의 include, exclude는 여러 개 가능하다.

<!-- doc -->
<javadoc destdir="${doc}">
    <fileset dir="${src}"/>
</javadoc>

src 디렉터리의 파일들을 읽어 javadoc문서를 만들어 doc 디렉터리에 저장한다.

<!-- zip -->
<copy todir="${dist}/lib">
    <fileset dir="${lib}"/>
</copy>

lib 디렉터리를 dist/lib 에 복사한다.
<zip destfile="test_${DSTAMP}.zip">
    <fileset dir="${dist}"/>
</zip>

dist 디렉터리의 파일들을 zip으로 묶는다.
zip 파일이름은 test_날짜.zip  (ex. test_20070802.zip)

<!-- delete -->
<delete dir="${build}"/>
build 디렉터리를 삭제한다.


결과 :
Buildfile: C:\Users\kyh\workspace\ant\ant\build.xml

compile:

    [mkdir] Created dir: C:\Users\kyh\workspace\ant\ant\build

    [javac] Compiling 4 source files to C:\Users\kyh\workspace\ant\ant\build

test1_2:

    [mkdir] Created dir: C:\Users\kyh\workspace\ant\ant\dist

      [jar] Building jar: C:\Users\kyh\workspace\ant\ant\dist\test1_2.20070802.jar

compile:

test1_2:

test2_3:

      [jar] Building jar: C:\Users\kyh\workspace\ant\ant\dist\test2_3.20070802.jar

doc:

    [mkdir] Created dir: C:\Users\kyh\workspace\ant\ant\doc

  [javadoc] Generating Javadoc

  [javadoc] Javadoc execution

  [javadoc] Loading source file C:\Users\kyh\workspace\ant\ant\src\test1\AntTest.java...

  [javadoc] Loading source file C:\Users\kyh\workspace\ant\ant\src\test2\AntTest2.java...

  [javadoc] Loading source file C:\Users\kyh\workspace\ant\ant\src\test2\AntTest2_1.java...

  [javadoc] Loading source file C:\Users\kyh\workspace\ant\ant\src\test3\AntTest3.java...

  [javadoc] Constructing Javadoc information...

  [javadoc] Standard Doclet version 1.6.0_02

  [javadoc] Building tree for all the packages and classes...

  [javadoc] Building index for all the packages and classes...

  [javadoc] Building index for all classes...

zip:

     [copy] Copying 1 file to C:\Users\kyh\workspace\ant\ant\dist\lib

      [zip] Building zip: C:\Users\kyh\workspace\ant\ant\test_20070802.zip

delete:

   [delete] Deleting directory C:\Users\kyh\workspace\ant\ant\build

BUILD SUCCESSFUL

Total time: 2 seconds



사용자 삽입 이미지

반응형

★ Ant 란?

Java 기반의 build 도구로서, file 형식은 XML 이다.
make 와는 달리 플랫폼 독립적인 Java 클래스를 사용하기 때문에 OS에 독립적이다.
이클립스는 Ant 플러그인을 기본으로 내장하므로 따로 설치할 필요 없다.


★ build.xml 생성

사용자 삽입 이미지
← 왼쪽과 같이 파일이 존재한다고 가정한다.
프로젝트(ant)를 선택하고 컨텍스트 메뉴에서 New > File 을 선택한다.


↓ 아래와 같은 창이 뜨면
File Name 에 build.xml 을 입력한다.
자동으로 ant 파일로 인식되어 Package Explorer 에 ant 파일로 표시된다.
(Window > Preference 에서 좌측 Ant 선택, 우측의 Names 에 build.xml 이 있다. 여기에 ,abc.xml 이런식으로 추가입력하면 abc.xml 파일 생성시 ant 파일로 인식된다.)

사용자 삽입 이미지

























사용자 삽입 이미지

← 개미 모양의 build.xml 파일을 볼 수 있을 것이다.




↓ 에디터 창에서 파일을 작성한 후,
Outline View 를 보면 아래와 같이 나타난다.
ant 를 클릭하고 컨텍스트 메뉴에서 Run As를 클릭한다.
Ant Build는 default로 지정된 target이 실행된다.
Ant Build... 를 선택하면 다이얼로그 창이 뜬다.

사용자 삽입 이미지


















사용자 삽입 이미지


↑ Ant Build... 을 선택했을 때의 다이얼로그.
(클릭하면 제대로 된 그림을 볼 수 있을 것이다.)
target name 앞에 체크 박스를 선택하는 순서대로 실행된다.
아랫부분의 Target execution order 란에 선택한 순서대로 표시된다.
순서를 바꾸고 싶으면 체크를 해제한 후 다시 선택하거나,
우측의 Order 버튼을 선택해 위 아래로 위치를 변경하면 된다.

중간에
Sort targets : 체크시, target name이 알파벳 순서대로 정렬된다.
Hide Internal Targets not selected for execution :
Hide Internal Targets 는 description이 없는 타깃을 말한다.
그러므로 체크하면 description이 없는 타깃은 목록에서 사라진다.
반응형

우아한 Metal 룩앤필의 Swing이 처음 모습을 드러냈을 때, 미적인 면에서 그 주된 경쟁 상대는 Windows 95 인터페이스였습니다. 약 10년 전의 GUI 수준으로 볼 때 Metal은 당시 일반적인 인터페이스에 비해 매력적이고 우아한 대안이었습니다.

자바 SE 5에서 업데이트된 Ocean 테마는 Metal이 지금까지도 선택 받는 데 기여했으나, 이제는 플랫폼을 넘나드는 Swing의 외관을 전면적으로 개편해야 할 시점입니다.

Nimbus 룩앤필의 세계로 오십시오. Synth에 기반한 새롭고 현대적인 룩앤필의 Nimbus는 애플리케이션에 매우 세련된 느낌을 부여합니다. 또한 Nimbus는 정적 비트맵이 아니라, 온전히 Java 2D 벡터 그래픽을 이용해서 만들어졌기 때문에 크기가 매우 작고(불과 56KB!), 임의의 해상도에서 렌더링이 가능합니다.

사용자 삽입 이미지

그림 3: Metal 테마의 SwingSet3
 
사용자 삽입 이미지


그림 4: Nimbus 테마의 SwingSet3
 

호환성 때문에 Metal은 여전히 Swing의 기본 룩앤필이지만 애플리케이션에서 Nimbus를 사용하도록 업데이트하는 작업은 너무나 간단합니다. 즉, 코드 한 줄로 충분합니다.

UIManager.setLookAndFeel("com.sun.java.swing.plaf..nimbus.NimbusLookAndFeel");

또한 명령줄에 -Dswing.defaultlaf=com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel을 추가하면 Nimbus를 기본 룩앤필로 지정할 수 있습니다. 보다 영구적으로 이 속성을 설정하려면 다음과 같은 코드를

swing.defaultlaf=com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel

<JAVA_HOME>/lib/swing.properties 파일에 추가합니다. swing.properties 파일이 없으면 새로 만들어야 합니다.

Nimbus에 관한 더 자세한 정보는 Nimbus early access 페이지를 참고하십시오.



이 글의 영문 원본은
Nimbus Look and Feel in Java SE 6 Update 10 Beta
에서 보실 수 있습니다.

반응형

이제 JavaFX SDK 기술 Preview가 릴리스되었으므로 자신만의 "사용자 지정 노드"를 빠르게 만드는 방법을 설명하겠습니다. JavaFX에서 사용자 지정 노드는 위젯, 가젯, UI 구성 요소 등 어느 것이나 모두 의미할 수 있으나 목적은 동일합니다. 다시 사용 가능한 JavaFX 프로그램용 UI를 만들 수 있도록 하는 것입니다. 오늘의 예는 사용자 지정 노드(2개)를 만드는 방법을 보여줍니다. 다음 스크린샷을 참조하십시오.

 

그런데 현재 이 예에 구현된 코드가 단순해진 것은 Edgar Merino 덕분입니다. 이 코드를 사용해보려면 Java Web Start 링크를 클릭하십시오. JRE 6 이상이 필요합니다. 또한 자바 SE 6 업데이트 10을 설치하면 배포 시간이 단축됩니다.



JavaFX SDK Packages are Taking Shape 게시물에서 언급한 것처럼 JavaFX는 UI를 개발할 때 그래픽 "노드 중심" 방식을 채택하고 있으므로 JavaFX 사용자 인터페이스의 거의 대부분은 노드(Node)입니다.  사용자 지정 노드를 만들려는 경우 CustomNode 클래스를 확장하여 원하는 특성과 동작을 지정합니다.  아래 코드는 이 예에서 이미지를 표시하고 마우스 이벤트에 응답(예: 마우스를 위에 갖다대면 좀 더 투명해지고 텍스트가 표시되는 이벤트)하는 사용자 지정 노드를 만드는 코드입니다. 

주: javafx.ext.swing 패키지에 있는 Button 클래스를 사용하지 않는 이유가 궁금하실 것입니다. 이유는 Button 클래스는 Node가 아니라 Component이기 때문이며, 위에 언급한 대로 노드 중심 방식으로 변화되는 방향을 따르는 것이 가장 좋다고 생각합니다. 어떤 부분에서는 노드를 하위 클래스로 만드는 버튼이 나타납니다. 이 경우에는 ButtonNode 클래스가 더 이상 필요하지 않을 수 있습니다.

ButtonNode.fx


/*
*  ButtonNode.fx -
*  A node that functions as an image button
*
*  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
*  and Edgar Merino (http://devpower.blogsite.org/) to demonstrate how
*  to create custom nodes in JavaFX
*/


package com.javafxpert.custom_node;

import javafx.animation.*;
import javafx.input.*;
import javafx.scene.*;
import javafx.scene.effect.*;
import javafx.scene.geometry.*;
import javafx.scene.image.*;
import javafx.scene.paint.*;
import javafx.scene.text.*;
import javafx.scene.transform.*;

public class ButtonNode extends CustomNode {
 
/**
   * The title for this button
   */

 
public attribute title:String;

 
/**
   * The Image for this button
   */

 
private attribute btnImage:Image;

 
/**
   * The URL of the image on the button
   */

 
public attribute imageURL:String on replace {
    btnImage
=
     
Image {
        url
: imageURL
     
};
 
}
   
 
/**
   * The percent of the original image size to show when mouse isn't
   * rolling over it.  
   * Note: The image will be its original size when it's being
   * rolled over.
   */

 
public attribute scale:Number = 0.9;

 
/**
   * The opacity of the button when not in a rollover state
   */

 
public attribute opacityValue:Number = 0.8;

 
/**
   * The opacity of the text when not in a rollover state
   */

 
public attribute textOpacityValue:Number = 0.0;

 
/**
   * A Timeline to control fading behavior when mouse enters or exits a button
   */

 
private attribute fadeTimeline =
   
Timeline {
      toggle
: true
      keyFrames
: [
       
KeyFrame {
          time
: 600ms
          values
: [
            scale
=> 1.0 tween Interpolator.LINEAR,
            opacityValue
=> 1.0 tween Interpolator.LINEAR,
            textOpacityValue
=> 1.0 tween Interpolator.LINEAR
         
]
       
}
     
]
   
};

 
/**
   * This attribute is interpolated by a Timeline, and various
   * attributes are bound to it for fade-in behaviors
   */

 
private attribute fade:Number = 1.0;
 
 
/**
   * This attribute represents the state of whether the mouse is inside
   * or outside the button, and is used to help compute opacity values
   * for fade-in and fade-out behavior.
   */

 
private attribute mouseInside:Boolean;

 
/**
   * The action function attribute that is executed when the
   * the button is pressed
   */

 
public attribute action:function():Void;
   
 
/**
   * Create the Node
   */

 
public function create():Node {
   
Group {
     
var textRef:Text;
      content
: [
       
Rectangle {
          width
: bind btnImage.width
          height
: bind btnImage.height
          opacity
: 0.0
       
},
       
ImageView {
          image
: btnImage
          opacity
: bind opacityValue;
          scaleX
: bind scale;
          scaleY
: bind scale;
          translateX
: bind btnImage.width / 2 - btnImage.width * scale / 2
          translateY
: bind btnImage.height - btnImage.height * scale
          onMouseEntered
:
           
function(me:MouseEvent):Void {
              mouseInside
= true;
              fadeTimeline
.start();
           
}
          onMouseExited
:
           
function(me:MouseEvent):Void {
              mouseInside
= false;
              fadeTimeline
.start();
              me
.node.effect = null
           
}
          onMousePressed
:
           
function(me:MouseEvent):Void {
              me
.node.effect = Glow {
                level
: 0.9
             
};
           
}
          onMouseReleased
:
           
function(me:MouseEvent):Void {
              me
.node.effect = null;
           
}
          onMouseClicked
:
           
function(me:MouseEvent):Void {
              action
();
           
}
       
},
        textRef
= Text {
          translateX
: bind btnImage.width / 2 - textRef.getWidth() / 2
          translateY
: bind btnImage.height - textRef.getHeight()
          textOrigin
: TextOrigin.TOP
          content
: title
          fill
: Color.WHITE
          opacity
: bind textOpacityValue
          font
:
           
Font {
              name
: "Sans serif"
              size
: 16
              style
: FontStyle.BOLD
           
}
       
},
     
]
   
};
 
}
}  



위의 ButtonNode.fx 코드 목록에서는 다음 내용을 짚고 넘어가겠습니다.

  • ButtonNode 클래스는 CustomNode를 확장합니다.
  • 이 새로운 클래스는 사용자 지정 노드에 표시될 이미지와 텍스트를 저장하는 속성을 채용합니다.
  • create() 함수는 사용자 지정 노드의 UI 모양과 동작에 관한 선언 표현식을 반환합니다.
  • javafx.scene.effect 패키지의 Glow 효과는 이미지를 클릭할 경우 이미지에 빛나는 효과를 줄 때 사용됩니다.
  • 이미지의 투명도, 이미지의 크기, 사용자 지정 노드의 제목은 마우스를 누르거나 버튼을 놓을 때 전환됩니다. Timeline은 이러한 전환이 점진적으로 이루어지도록 하는 데 사용됩니다.
  • 투명도를 조정하고 Glow 효과를 적용한 후에 onMouseClicked 함수가 목록의 앞 부분에 정의된 action() 함수 속성을 호출합니다. 그러면 사용자 지정 노드가 Button과 유사하게 동작합니다.

"메뉴"에 ButtonNode 인스턴스 배열

Setting the "Stage" for the JavaFX SDK 게시물에서 설명한 것처럼 HBox 클래스는 javafx.scene.layout 패키지에 있으며, 이 패키지 안의 다른 노드를 배열하는 노드입니다. 아래와 같은 MenuNode 사용자 지정 노드는 ButtonNode 인스턴스를 수평으로 배열하고, javafx.scene.effects 패키지의 Reflection 클래스는 해당 버튼 아래에 멋진 반사 효과를 추가합니다. 코드는 다음과 같습니다.

MenuNode.fx

/*
 *  MenuNode.fx -
 *  A custom node that functions as a menu
 *
 *  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
 *  to demonstrate how to create custom nodes in JavaFX
 */


package com.javafxpert.custom_node;
 
import javafx.scene.*;
import javafx.scene.effect.*;
import javafx.scene.layout.*;

public class MenuNode extends CustomNode {

 
/*
   * A sequence containing the ButtonNode instances
   */

 
public attribute buttons:ButtonNode[];
   
 
/**
   * Create the Node
   */

 
public function create():Node {
   
HBox {
      spacing
: 10
      content
: buttons
      effect
:
       
Reflection {
          fraction
: 0.50
          topOpacity
: 0.8
       
}
   
}    
 
}
}  


사용자 지정 노드 사용

이제 사용자 지정 노드를 정의했으므로 간단한 프로그램에서 이 노드를 사용하는 방법을 보여드리겠습니다. 이 블로그를 따라해보신 분은 "JavaFX가 UI와 모델을 바인딩하는 방식"을 알게 되었을 것입니다. 이 간단한 예에서는 사용자 지정 노드를 만드는 방법을 알리는 데 중점을 두기 때문에 모델을 만들어서 이 모델에 UI를 바인딩하는 복잡한 작업까지 보여드리지는 않겠습니다. 대신, ButtonNode 인스턴스를 클릭할 때마다 문자열을 콘솔에 인쇄하는 간단한 작업을 보여드리겠습니다. 이번 예의 기본 프로그램의 코드는 다음과 같습니다.

MenuNodeExampleMain.fx

/*
 *  MenuNodeExampleMain.fx -
 *  An example of using the MenuNode custom node
 *
 *  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
 *  to demonstrate how to create custom nodes in JavaFX
 */

package com.javafxpert.menu_node_example.ui;

import javafx.application.*;
import javafx.scene.paint.*;
import javafx.scene.transform.*;
import java.lang.System;
import com.javafxpert.custom_node.*;

Frame {
 
var stageRef:Stage;
 
var menuRef:MenuNode;
  title
: "MenuNode Example"
  width
: 500
  height
: 400
  visible
: true
  stage
:
    stageRef
= Stage {
      fill
: Color.BLACK
      content
: [
        menuRef
= MenuNode {
          translateX
: bind stageRef.width / 2 - menuRef.getWidth() / 2
          translateY
: bind stageRef.height - menuRef.getHeight()
          buttons
: [
           
ButtonNode {
              title
: "Play"
              imageURL
: "{__DIR__}icons/play.png"
              action
:
               
function():Void {
                 
System.out.println("Play button clicked");
               
}
           
},
           
ButtonNode {
              title
: "Burn"
              imageURL
: "{__DIR__}icons/burn.png"
              action
:
               
function():Void {
                 
System.out.println("Burn button clicked");
               
}
           
},
           
ButtonNode {
              title
: "Config"
              imageURL
: "{__DIR__}icons/config.png"
              action
:
               
function():Void {
                 
System.out.println("Config button clicked");
               
}
           
},
           
ButtonNode {
              title
: "Help"
              imageURL
: "{__DIR__}icons/help.png"
              action
:
               
function():Void {
                 
System.out.println("Help button clicked");
               
}
           
},
         
]
       
}
     
]
   
}
}

앞서 언급한 대로 사용자가 해당 ButtonNode를 마우스로 클릭할 때마다 호출된 함수에 action 속성이 할당됩니다. 그리고 __DIR__ 표현식은 CLASS 파일이 있는 디렉토리로 평가됩니다. 이 경우 그래픽 이미지는 com/javafxpert/menu_node_example/ui/icons 디렉토리에 있습니다.

이 기사의 이미지를 다운로드한 후 이 그래픽으로 이 예에서 소개한 대로 작성하고 실행할 수 있습니다. 이 이미지는 프로젝트의 클래스 경로에서 확장할 수 있는 zip 파일입니다.

이 파일은 JavaFX SDK Technology Preview에 유용한 사용자 지정 노드 라이브러리를 작성하여 이 블로그의 JFX Custom Nodes 카테고리에 게시하기 위해 만든 것입니다. 사용자 지정 노드와 관련하여 아이디어가 있거나 자신이 개발한 사용자 지정 노드를 공유하려면 lat-inc.com의 jim.weaver로 연락해주십시오.

이 게시물을 실행한 후에 Weiqi Gao가 Java WebStart Works On Debian GNU/Linux 4.0 AMD64 게시물에 몇 가지 좋은 소식을 올렸습니다. JavaFX 스크립트 설명서의 기술 검토를 훌륭하게 해주셔서 저는 Weiqi(발음: 웨이치) 씨가 매우 좋습니다. ;-)

감사합니다.
Jim Weaver
JavaFX Script: Dynamic Java Scripting for Rich Internet/Client-side Applications

지금 바로 the book's Apress site에서 eBook(PDF)을 다운로드할 수 있습니다.

이 글의 영문 원본은
Rolling Your Own JavaFX "Custom Nodes": A Graphical Menu Example
에서 보실 수 있습니다.

+ Recent posts