달력

02

« 2012/02 »

  •  
  •  
  •  
  • 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
  •  
  •  
  •  
The Java Developers Almanac 1.4 책에 해당하는 소스 사이트이다.


구글에서 간단한 자바 소스를 찾다보면 많이 나오게 되는 사이트이다.
책의 내용을 본 적은 없지만 구글 검색 엔진 결과의 상위에 랭크가 되는 걸 보면 상당히 유용한 사이트이 인거 같다.

실제로 간단한 소스 코드가 잘 정리되어 있다.

TAG java
Posted by korcslewis
자바가 Generic 프로그래밍 방식을 지원하면서 많은 자바 유틸 클래스중 Collection 객체들이 generic을 이용한다.

여기서 잠시 다루어 보려는 HashMap 컬렉션 유틸리티 객체도 generic을 이용한 코딩을 할 수 있다.
이와 같이 HashMap 클래스의 정의를 HashMap<K, V>로 하고 있다.

K : Key
V : Value

형태인데 key와 value에 generic을 이용하면 자바 클래스및 사용자 클래스를 줄 수 있다. 하지만 보통은 HashMap을 이용한 간단한 샘플 코드는 Integer 또는 String 을 이용한 코드가 대부분이다. 예를 들면 다음과 같다.

public class HashMap1
  {
  public static void main( String[] args )
    {
    HashMap map = new HashMap();
    map.add( new Integer( 2 ), "two" );
    map.add( new Integer( 4 ), "four" );
    System.out.println( map );
    System.out.println();

    System.out.println( "Enumerate the HashMap" );
    Enumeration e = map.elements();
    while ( e.hasMoreElements() )
      System.out.println( e.nextElement() );
    System.out.println();

    System.out.println( "Iterate through the HashMap" );
    for ( HashMapIterator i = map.begin(); !i.atEnd(); i.advance() )
      System.out.println( i.get() + ", key = " + i.key() + ", value = " + i.value() );
    System.out.println();

    System.out.println( "Demonstrate access" );
    System.out.println( "map.get( 2 ) = " + map.get( new Integer( 2 ) ) );
    System.out.println( "map.get( 5 ) = " + map.get( new Integer( 5 ) ) );
    System.out.println( "map = " + map );
    System.out.println();

    System.out.println( "Show that duplicates cannot be added." );
    Object value = map.add( new Integer( 8 ), "eight" );
    if ( value != null )
      System.out.println( "Could not add 8." );
    else
      System.out.println( "Added 8." );
    System.out.println( "map = " + map );

    value = map.add( new Integer( 4 ), "FOUR" );
    if ( value != null )
      System.out.println( "Could not add 4." );
    else
      System.out.println( "Added 4." );
    System.out.println( "map = " + map );
    System.out.println();

    System.out.println( "Demonstrate modification" );
    map.put( new Integer( 4 ), "FOUR" );
    System.out.println( "map = " + map );
    }
  }


위의 코드가 문제가 된다는 것은 아니다. 다만 HashMap의 Key에 해당하는 클래스가 두 개의 좌표값을 가진 클래스인 경우를 생각해 보자. UserKey라는 클래스는 두 개의 좌표(x, y) 값을 가진 간단한 클래스이다.

/**
 * @author Sang-Hyup Lee
 *
 */
public class UserKey {

private int x;
private int y;
/**
* @param x
* @param y
*/
public UserKey(int x, int y) {
super();
this.x = x;
this.y = y;
}

/**
* @return the x
*/
public int getX() {
return x;
}

/**
* @param x the x to set
*/
public void setX(int x) {
this.x = x;
}

/**
* @return the y
*/
public int getY() {
return y;
}

/**
* @param y the y to set
*/
public void setY(int y) {
this.y = y;
}
}

다음은 Value 클래스에 해당하는 UserValue 객체를 만들어보자.

import java.util.UUID;

/**
 * @author Sang-Hyup Lee
 *
 */
public class UserValue {

private int x, y;
private String uniKey;
public UserValue(int x, int y) {
this.x = x;
this.y = y;
this.uniKey = "" + UUID.randomUUID();
}
/**
* @return the uniKey
*/
public String getUniKey() {
return uniKey;
}

/**
* @param uniKey the uniKey to set
*/
public void setUniKey(String uniKey) {
this.uniKey = uniKey;
}

/**
* @return the x
*/
public int getX() {
return x;
}

/**
* @param x the x to set
*/
public void setX(int x) {
this.x = x;
}

/**
* @return the y
*/
public int getY() {
return y;
}

/**
* @param y the y to set
*/
public void setY(int y) {
this.y = y;
}

}

위의 두 개의 key, value 클래스를 이용하여 HashMap 테스트를 위한 JUnit 코드를 만들어보자. 아래의 UnikeyHashMap junit 코드의 결과값을 예상해 보자.

import java.util.HashMap;

import junit.framework.TestCase;

/**
 * @author Sang-Hyup Lee
 *
 */
public class UnikeyHashMap extends TestCase {

private HashMap<UserKey, UserValue> userHashMap = new HashMap<UserKey, UserValue>();
protected void setUp() throws Exception {
super.setUp();
for ( int x=0; x < 10; x++ ) {
int y = x + 1;
UserKey userKey = new UserKey(x, y);
UserValue sohiPoint = new UserValue(x, y);

userHashMap.put(userKey, sohiPoint);
}
}
public void testUnikeyHashMap() {
UserKey targetUserKey = new UserKey(2, 3);
/*
UserValue userValue = null;
if ( userHashMap.get(targetUserKey) != null ) {
userValue = userHashMap.get(targetUserKey);
}
*/
assertNotNull(userHashMap.get(targetUserKey));
// assertEquals(2, foundSohi.getX());
// assertEquals(3, foundSohi.getY());
}

}

주석문으로 처리된 부분은 UserValue가 정상적으로 찾았을 때를 대비해서 최종 체크하기 위한 코드이다. 적절한 형태로 사용해도 된다.

여기서 중요한 건 testUnikeyHashMap() 테스트가 정상적으로 동작할까? 하는 것이다.
결과는 에러를 리턴한다. 즉, userHashMap.get(targetUserKey)의 결과값이 null 이란 것이다. 일반적인 생각에는 Key를 주어진 Value를 찾아야 한다.
HashMap 클래스의 get 메소드를 따라가보면 문제가 발생한 곳은 파라미터로 받는 key object의 equals 메소드 구현에 있다는 것을 알 수 있다.

이미 이러한 문제는 실무에서 사용할 일이 많았던 거 같다. 즉 HashMap과 같은 Key를 가진 컬렉션 객체에 다중의(Multi) 값을 가진 key 객체를 사용하고 싶은 요구사항인 것이다.
Apache commons collections 오픈소스에 이에 대한 해답이 있다. MultiKey라는 클래스이다.

사용법은 다음과 같이 정의하고 있다.

Example usage:

 // populate map with data mapping key+locale to localizedText
 Map map = new HashMap();
 MultiKey multiKey = new MultiKey(key, locale);
 map.put(multiKey, localizedText);

 // later retireve the localized text
 MultiKey multiKey = new MultiKey(key, locale);
 String localizedText = (String) map.get(multiKey);

간단하다. 실제로 아파치 라이센스를 따르니 해당 소스를 가져와도 상관이 없다. 해당 전체 소스 코드를 살펴볼 필요가 있다.

여기서는 MultiKey 클래스를 이용해서 UnikeyHashMap 테스트 코드를 다음과 같이 수정해 보자.

import java.util.HashMap;

import junit.framework.TestCase;

/**
 * @author Sang-Hyup Lee
 *
 */
public class UnikeyHashMap extends TestCase {

private HashMap<MultiKey, UserValue> userHashMap = new HashMap<MultiKey, UserValue>();
protected void setUp() throws Exception {
super.setUp();
for ( int x=0; x < 10; x++ ) {
int y = x + 1;
MultiKey userKey = new MultiKey(x, y);
UserValue sohiPoint = new UserValue(x, y);

userHashMap.put(userKey, sohiPoint);
}
}
public void testUnikeyHashMap() {
MultiKey targetUserKey = new MultiKey(2, 3);
UserValue userValue = null;
if ( userHashMap.get(targetUserKey) != null ) {
userValue = userHashMap.get(targetUserKey);
}
assertNotNull(userHashMap.get(targetUserKey));
assertEquals(2, userValue.getX());
assertEquals(3, userValue.getY());
}

}

UserKey에 해당하는 Key 클래스를 MultiKey로 바꾼 것 말고는 실제로 코드를 수정한 것은 아니다. testUnikeyHashMap 메소드의 세 개의 unit test 메소드가 정상적으로 실행될 것이다. 그리고 실제로 x, y 좌표값에 해당하는 value 객체도 얻어진 것을 확인할 수 있다.

Posted by korcslewis
2009/08/13 14:40

[링크]JDK6 한글문서 Java SE2009/08/13 14:40

JDK6 문서를 한글화해둔 사이트가 있다.
아마도 일본 사이트를 번역해 둔 사이트인 듯 하다.
그래도 참조할 부분이 있다.



TAG jdk, jdk6
Posted by korcslewis
2009/07/17 15:40

JUnit을 이용한 UI 테스트 Java SE2009/07/17 15:40

흔히, GUI가 있는 프로그램은 일일이 개발자가 눈으로 보거나 이벤트를 날려보는 식으로 테스트가 진행된다.
쉽지 않은 일이기에 TDD 에서는 이것마저 테스트가 가능하다고 한다. 하지만 이것 역시나 쉽지 않은 것이 GUI 프로그램인 경우에는 아무리 생각해 보아도 TDD를 적용하기 힘들다는 생각을 버리기 힘들다.

그리고 최근 사내에서 TDD를 전파하는 중인데 웹 애플리케이션을 많이 하는 곳이 아니고 핸드셋 단말을 많이 개발하는 곳이어서 아무래도 UI 이슈가 많은 곳이다.
그러다보니 TDD를 적용해 보기에 어려움이 많은 부분이 있다. 그래서인지 설득력있게 이야기해 보아도 쉽게 적용하는 개발자를 보질 못했다.
더군다나 나역시 로직컬한 부분에서는 TDD를 적용해 오긴 했지만 UI에 TDD를 적용해 보진 않았다.

그런중에 안드로이드 애플리케이션을 개발해야 하는데, 아무래도 UI 이슈가 많아진다.
그리고 개발하고자 하는 프로젝트가 2D Graphics 영역이어서 일일이 랜더링해야 하는 코드가 많아져 graphics 쪽으로 공부를 하는 중이다.
그런 중에 책의 소스코드를 unit test 할 수 있는 방법이 없을까?하는 생각으로 간단하게 UI를 JUnit 을 이용하여 테스트해 보았다.
작은 시간이니 하나씩 UI에 적용할 방법을 찾는 것도 좋은 방법이란 생각이 든다^^

먼저, ApplicationFrame.java 라는 정말로 심플한 UI 코드를 보자. Frame이 중앙에 모니터의 중앙에 위치하도록 center() 라는 메소드를 가지고 있다.

import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

/**
 * @author Sang-Hyup, Lee
 *
 */
public class ApplicationFrame extends Frame {

 public ApplicationFrame() {
  super("ApplicationFrame v1.0");
 }
 
 public ApplicationFrame(String title) {
  super(title);
  createUI();
 }

 protected void createUI() {
  // TODO Auto-generated method stub
  setSize(500, 400);
  center();
 
  addWindowListener(new WindowAdapter() {
   public void windowClosing(WindowEvent e) {
    dispose();
    System.exit(0);
   }
  });
 }

 public void center() {
  // TODO Auto-generated method stub
  Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
  Dimension frameSize = getSize();
 
  int x = (screenSize.width - frameSize.width) / 2;
  int y = (screenSize.height - frameSize.height) / 2;
 
  setLocation(x, y);
 }
 
}


 여기서 테스트를 해 보고 싶은 것이 모니터의 실질적인 width, height 값과 중앙에 위치했을 때 center() 메소드에서 사용한 알고리즘이 맞는가? 하는 것이다.
간단한 알고리즘이어서 오류가 발생할 경우는 거의 없지만 TDD 개발 책에서도 대부분은 이렇게 심플한 예제로 설명하니 부담이 오히려 없을 듯 하다.

만약, 자신의 모니터의 width, height 값을 정확하게 알아본 후 다음의 테스트 코드를 적용해 볼 수 있을 것이다.


import java.awt.Dimension;
import java.awt.Point;
import java.awt.Toolkit;

import junit.framework.TestCase;

import com.mediachorus.java2d.graphics.frame.ApplicationFrame;

/**
 * @author Sang-Hyup, Lee
 *
 */
public class ScreenSizeTest extends TestCase {

 public void testScreenSize() {
  Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

  assertEquals(1280, screenSize.width);
  assertEquals(1024, screenSize.height);
 }
 
 public void testGetLocation() {
  ApplicationFrame appFrame = new ApplicationFrame("This is test frame");
 
  appFrame.center();
 
  Point point = appFrame.getLocation();
 
  assertEquals(390, point.x);
  assertEquals(312, point.y);
 
  assertEquals(390.0d, point.getX());
  assertEquals(312.0d, point.getY());
 }
 
}


모니터가 1280 * 1024 인 경우 해당 Dimension 클래스를 이용한 width, height 값을 통해서 알 수 있고, testGetLocation() 테스트 메소드를 통해서 center() 메소드가 실제로 정상적으로 작동하는지 검증할 수 있다.

간단한 UI 테스트를 통한 TDD 적용이다. 위의 코드를 이용해서 각자 모니터, center() 알고리즘의 검증, 계산 등을 해보면 좋은 경험이 될 것이다.
이런 테스트 코드를 가지고 있으면 좋은 점 또 하나는 일일이 로그를 찍어보지 않아도 해당하는 값들을 예측할 수 있다는 것이다.

Posted by korcslewis
2009/07/15 17:43

Swing 튜토리얼 - JComponent Java SE2009/07/15 17:43

링크와 함께 원문을 실어 놓는다.
어디가에 계실 번역자님~~~ 글을 복사한 것에 따른 문의가 있으면 언제든지 연락주세요...
링크로 바꿀께요^^;; 다음에 원문을 혹시나 찾지 못할까봐ㅎㅎ

코드 분석을 위해 새삼스럽게 Java swing 쪽을 잠시 보고 있는데 나름 부담되었는데 도움이 되었다^^


출처 : http://java.sun.com/docs/books/tutorial/uiswing/components/jcomponent.html

JComponent클래스
최상위 컨테이너를 제외하고 이름이 J로 시작하는 모든 Swing콤포넌트는 JComponent클래스를 상속한다.
예를 들면, JPanel, JScrollPane, JButton, JTable등은 모두 JComponent클래스를 상속했다.
그러나, JFrame, JDialog는 그렇지 않은 데, 그것들은 최상위 컨테이너 이다.
JComponent클래스는 Container클래스를 상속하며, Container컨테이너 클래스는 다시 Component클래스를 상속한다.

Component클래스는 레이아웃 힌트를 제공하는 것부터 그리기, 이벤트를 제공하는 것까지 모든 것을 포함한다.

Container클래스는 콤포넌트를 컨테이너에 추가하고, 레이아웃을 설정하는 것을 지원한다.

이 문서의 API 표는 JComponent클래스 뿐만이 아니라, Component, Container클래스의 가장 자주 사용되는 메소드들을 요약했다.


JComponent클래스의 기능

JComponent클래스의 기능은 다음 카테고리로 나눌 수 있다.
  • 툴팁
  • 그리기와 테두리
  • 프로그램 전체에 영향을 끼치는 룩앤필
  • 사용자정의 속성
  • 레이아웃 지원
  • 노약자, 장애인을 위한 접근성 지원
  • 드랙앤드롭 지원
  • 이중 버퍼링
  • 키바인딩(Key bindings)
툴팁
setToolTipText메소드로 문자열을 지정하면, 콤포넌트 사용자에게 도움말을 제공할 수 있다.
커서가 콤포넌트 위에서 머물면, 콤포넌트 옆의 작은 창에 지정된 문자열이 보인다.
더  자세한 정보는 How to Use Tool Tips 을 참조한다.
그리기와 테두리
setBorder메소드는 콤포넌트가 가장자리에 보여주는 테두리를 설정할 수 있도록 한다.
콤포넌트 안쪽을 그리기 위해서는 paintComponent메소드를 오버라이드 하면 된다.
자세한 내용은 How to Use Borders와  Performing Custom Painting을 참조한다.
프로그램 전체에 영향을 끼치는 룩앤필
모든 JComponent객체는 그에 해당된는 ComponentUI객체를 가지고 있으며,
ComponentUI객체는 그리기와 이벤트 처리, 크기조절등의 역할을 행한다.
정확히 어떤 ComponentUI객체가 사용되는 지는 현재의 룩앤필에 따라 다르다.
UIManager.setLookAndFeel메소드를 사용해서 현재의 룩앤필을 설정할 수 있다.
자세한 내용은 How to Set the Look and Feel을 참조한다.
사용자정의 속성
모든 JComponent객체를 한 개 이상의 속성(이름/객체 쌍)과 연관시킬 수 있다.
예를 들면, 레이아웃 관리자는 속성을 사용해서 레이아웃 관리자가 관리하는 모든 콤포넌트와 제약 객체(constraints object)를 연관시킬 수 있다. putClientProperty메소드를 이용해서 속성을 설정하고, getClientProperty를 이용해서 속성을 가져온다.
속성에 대한 일반적인 정보를 얻고 싶으면 Properties를 참고한다.
레이아웃 지원
AWT의 Component클래스는 getPreferredSize, getAlignmentX와 같은 레이아웃 힌트 메소드는 제공하지만,  이러한 레이아웃 힌트를 설정할 수 있는 방법을 제공하지 않는다. JComponent클래스느 레이아웃 힌트를 설정하는 메소드를 제공한다. setMinimumSize, setMaximumSize, setAlignmentX, setAlignmentY 메소드가 그것이다.
더 자세한 정보는 Laying Out Components Within a Container를 참조한다.
노약자, 장애인을 위한 접근성 지원
JComponent클래스는 스크린 리더가 콤포넌트로부터 정보를 가져가는 것을 돕는 등의 접근기술을 도와주는 API와 기본기능이 있다.
How to Support Assistive Technologies을 참조한다.
드래그앤드드롭 지원
JComponent클래스는 콤포넌트의 이전 처리기(transfer handler)를 설정하는 API를 제공한다.
이전 처리기는 Swing 드래그앤드드롭의 기반이 된다.
자세한 사항은 Introduction to Drag and Drop and Data Transfer을 참조한다.
이중 버퍼링
이중 버퍼링(double buffering) 화면에서 부드러운 그리기 동작을 보여준다.
Performing Custom Painting을 참조한다.
키 바인딩
이 기능을 사용하면 사용자가 키보드의 특정 키를 누를 때 콤포넌트가 반응하도록 만들 수 있다.
예를 들면, 많은 룩앤필의 경우 버튼이 포커스를 가지고 있을 때, 스페이스 키를 누르는 것은 마우스로 클릭하는 것과 동일한 효과를 가진다. 룩앤필은 자동적으로 스페이스키를 누르는 것과 버튼의 결과적인 효과를 바인딩(결속) 시켜준다.
더 자세한 정보는 How to Use Key Bindings을 참조한다.

JComponent API

JComponent클래스는 많은 새로운 메소드를 제공하며, Component클래스와 Container클래스로부터 많은 메소드를 상속 받았다. 다음 표는 가장 많이 사용하는 메소드를 요약했다.
  • 콤포넌트 외양을 커스터마이징
  • 콤포넌트 상태를 설정하거나 가져오기
  • 이벤트 처리하기
  • 콤포넌트 그리기
  • 포함계층구조를 처리하기
  • 콤포넌트 레이아웃
  • 크기와 위치정보를 가져오기
  • 크기와 위치를 지정하기
콤포넌트 외양을 커스터마이스징
메소드용도
void setBorder(Border) 
Border getBorder()
콤포넌트의 테두리를 설정하거나 가져온다.
자세한 내용은 How to Use Borders 을 참조한다.
void setForeground(Color)
void setBackground(Color)
콤포넌트의 전면색상 혹은 배경색상을 설정한다.
전면색상은 주로 콤포넌트 안에 문자를 그려넣는 데 사용되는 색상이다. 배경색상은 콤포넌트가 불투명하다는 전제하에서 콤포넌트의 뒷배경영역의 색상이다.

Color getForeground() 
Color getBackground()
콤포넌트의 전면색상 혹은 배경색상을 가져온다.
void setOpaque(boolean) 
boolean isOpaque()
콤포넌트가 불투명(opaque)한지 여부를 설정하거나 가져온다.
불투명한 콤포넌트는 그 배경을 배경색상을 채워넣는다.
void setFont(Font) 
Font getFont()
콤포넌트의 글꼴을 설정하거나 가져온다.
만약 콤포넌트의 글꼴이 설정되지 않았다면, 부모콤포넌트의 글꼴이 반환된다.
void setCursor(Cursor)
Cursor getCursor()
커서를 갖다대었을 때 표시되는 커서모양을 설정하거나 가져온다. 예를 들면 aPanel.setCursor( Cursor.getPredefinedCursor( Cursor.WAIT_CURSOR));
콤포넌트의 상태 설정하기
메소드용도
void setComponentPopupMenu(String)JComponent객체의 JPopupMenu설정하기.
바인딩을 등록하고 필요한 리스너를 추가해서 적절한 타이밍에 JPopMenu객체가 보여지게 하는 것은 UI가 담당한다.
JPopMenu가 보여지는 시점은 룩앤필에 따라 다르다. 어떤 룩앤필은 마우스 이벤트에 보여줄 것이고, 어떤 이벤트는 키바인딩을 가능하게 할 것이다.
popup이 null이고, getIngeritsPopupMenu가 true를 반환하면, getComponentPopupMenu메소드는 부모객체로 위임될 것이다. 이 방식으로 자식 콤포넌트가 부모 콤포넌트의 popupmenu를 상속할 수 있다.
void setTransferHandler(TransferHandler)
TransferHandler getTransferHandler()
transferHandler속성을 설정하거나 제거한다.
TransferHandler는 드래그앤드드롭 혹은 클립보드 로 (부터)의 잘라내기, 복사, 붙여넣기를 통해서 데이터를 교환하는 것을 지원한다.
더 자세한 내용은 Introduction to Drag and Drop and Data Transfer을 참조한다.
void setToolTipText(String)툴팁에 보여줄 문자열을 설정한다.
더 많은 정보는 How to Use Tool Tips을 참조한다.
void setName(String) 
String getName()
콤포넌트의 이름을 설정하거나 가져온다.
이  메소드는 텍스트를 표시하지 않는 콤포넌트와 문자열을 연결시킬 때 유용할 수 있다.
boolean isShowing()콤포넌트가 화면에 보여지는 지를 결정한다.
이것의 의미는 콤포넌트가 visible이어야 하고, visible하고 show된 컨테이너에 포함되어야 한다는 의미이다.
void setEnabled(boolean) 
boolean isEnabled()
콤포넌트가 활성화 여부를 설정하거나 가져온다.
활성화된 콤포넌트는 사용자 입력에 반응하고 이벤트를 생성할 수 있다.
void setVisible(boolean) 
boolean isVisible()
콤포넌트가 visible인지를 설정하고 가져온다.
최상위 콤포넌트를 제외한 모든 콤포넌트는 초기값으로 visible하다.
이벤트 처리
(자세한 사항은
Writing Event Listeners을 참조한다.)
메소드용도
void addHierarchyListener(hierarchyListener l) 
void removeHierarchyListener(hierarchyListener l) 
계층구조가 변경되었다는 이벤트를 처리하기 위한 지정된 hierarchy listener를 추가하거나 제거한다.
리스너가 null이면, 예외를 발생시키지 않으며, 아무런 행동도 취해지지 않는다.
void addMouseListener(MouseListener) 
void removeMouseListener(MouseListener)
마우스 리스너(mouse listener)를 추가하거나 제거한다.
마우스 리스너는 사용자가 마우스를 사용해서 콤포넌트와 상호작용을 할 때 통보받는다.
void addMouseMotionListener(MouseMotionListener) 
void removeMouseMotionListener(MouseMotionListener)
마우스 동작 리스너(mouse motion listener )를 추가하거나 제거한다.
마우스 동작 리스너� 사용자가 해당 콤포넌트 안엣 마우스커서를 움직일 대 통보받는다.
void addKeyListener(KeyListener) 
void removeKeyListener(KeyListener)
키 리스터(key listener)를 추가하거나 제거한다.
키 리스너는 콤포넌트가 키보드 포커스를 가지고 있고, 사용자가 키보드를 타이핑하면 통보받는다.
void addComponentListener(ComponentListener) 
void removeComponentListener(ComponentListener)
콤포넌트 리스너(component listener )를 추가하거나 제거한다.
콤포넌트 리스너는 콤포넌트가  숨겨지거나, 보여지거나, 이동하거나, 크기변경이 될 때 통보받는다.
boolean contains(int, int) 
boolean contains(Point)
지정된 점(point)가 콤포넌트 내부에 있는 지 결정한다.
파라메터는 콤포넌트 좌표 시스템으로 지정되어야 한다.
정수값은 각각 x, y값을 나타낸다.
Component getComponentAt(int, int)
Component getComponentAt(Point)
입력된 x, y지점을 포함하는 콤포넌트를 반환한다.
만약 콤포넌트가 겹쳐져 있다면 가장 왼쪽위 콤포넌트를 반환한다.
이것은 Component.contains()메소드의 인덱스가 0에 제일 가까운 콤포넌를 찾아내는 것으로 결정한다.
Component setComponentZOrder(component comp, int index)
지정된 콤포넌트를 컨테이너의 지정된 z축 인덱스로 이동시킨다.

만약 콤포넌트가 다른 컨이너의 자식객체이면, 그 콤포넌트는 이 컨테이너에 추가되기 전에 이전의 컨테이너에서 제거된다.
java.awt.Container.add(Component, int)메소드와 중요한 차이점은 이 메소드는 이전 컨테이너에서 콤포넌트를 제거할 때, 허용되고 필요하지 않다면 removeNotify메소드를 호출하지 않는다는 것이다. 이 방식으로 만약 콤포넌트가 키보드 포커스를 가지고 있다면, 새로운 위치로 이동했을 때에도 키보드 포커스를 유지한다.

참고:  z축은  콤포넌트가 그려지는 순서를 결정한다. z축 값이 제일 큰 콤포넌트가 먼저 그려지고, 낮은 z축 값이 가장 낮은 콤포넌트가 가장 늦게 그려진다. 콤포넌트가 겹쳐진다면, z축 값이 낮은 콤포넌트가 z축 값이 높은 콤포넌트 위에 그려진다.

Component getComponentZOrder(component comp)
컨테이너 내부의 콤포넌트의 z축 값을 반환한다. z축에서 위에 있을 수록 인덱스 값은 낮다.
z축 값이 가장 낮은 콤포넌트는 가장 늦게 모든 자식 콤포넌트 위에 그려진다.
콤포넌트 그리기
(자세한 사항은
Performing Custom Painting을 참조한다.)
메소드용도
void repaint() 
void repaint(int, int, int, int)
콤포넌트의 전체가 다시 그려지도록 요청한다.
4개의 int형 파라메터는 다시 그릴 경계선을 지정하며, x, y, 폭, 높이를 의미한다.
void repaint(Rectangle)콤포넌트 내의 지정된 영역이 다시 그려지도록 요청한다.
void reval!idate()콤포넌트와 해당 컨테이너가 레이아웃을 다시 잡도록 요청한다. 콤포넌트가 visible된 이후에 명시적으로 크기조절, 정열 힌트 변경 조절, 포함계층구조 변경등을 하지 않았다면 이 메소드를 호출할 필요할 필요가 없다.
reval!idate메소드를 호출한 다음에는 항상 repaint메소드를 호출하도록 한다.
void paintComponent(Graphics)콤포넌트를 그린다.
이 메소드를 오버라이드해서 사용자정의 콤포넌트의 그리기를 구현한다.
포함계층구조 다루기
(더 자세한 내용은 최상위 컨테이너를 참조한다.
)
메소드
용도
Component add(Component) 
Component add(Component, int) 
void add(Component, Object)
지정된 콤포넌트를 이 컨테이너에 추가한다. 파라메터가 1개  사용되는 것은 콤포넌트를 컨테이너의 끝에 추가한다. int형 파라메터는 컨테이너 내의 새로운 콤포넌트의 위치를 표시한다. Object형 파라메터는 현재의 레이아웃 관리자에게 레이아웃 제한을 제공한다.
void remove(int) 
void remove(Component)
void removeAll()
이 컨테이너에서 1개 혹은 모든 콤포넌트를 제거한다.
int형 파라메터는 콤포넌트를 제거할 컨테이너 내부의 위치를 나타낸다.
JRootPane getRootPane()Get the root pane that contains the component.
Container getTopLevelAncestor()Get the topmost container for the component — a Window, Applet!, or null if the component has not been added to any container.
Container getParent()Get the component's immediate container.
int getComponentCount()Get the number of components in this container.
Component getComponent(int) 
Component[] getComponents()
Get the one of or all of the components in this container. The int argument indicates the position of the component to get.
Component getComponentZOrder(int)
Component[] getComponentZOrder()
Returns the z-order index of the component inside the container. The higher a component is in the z-order hierarchy, the lower its index. The component with the lowest z-order index is painted last, above all other child components.
Laying Out Components 
(see
Laying Out Components Within a Container for more information)
MethodPurpose
void setPreferredSize(Dimension) 
void setMaximumSize(Dimension) 
void setMinimumSize(Dimension)
Set the component's preferred, maximum, or minimum size, measured in pixels. The preferred size indicates the best size for the component. The component should be no larger than its maximum size and no smaller than its minimum size. Be aware that these are hints only and might be ignored by certain layout managers.
Dimension getPreferredSize() 
Dimension getMaximumSize() 
Dimension getMinimumSize()
Get the preferred, maximum, or minimum size of the component, measured in pixels. Many JComponent classes have setter and getter methods. For those non-JComponent subclasses, which do not have the corresponding setter methods, you can set a component's preferred, maximum, or minimum size by creating a subclass and overriding these methods.
void setAlignmentX(float) 
void setAlignmentY(float)
Set the alignment along the x- or y- axis. These values indicate how the component would like to be aligned relative to other components. The value should be a number between 0 and 1 where 0 represents alignment along the origin, 1 is aligned the furthest away from the origin, and 0.5 is centered, and so on. Be aware that these are hints only and might be ignored by certain layout managers.
float getAlignmentX() 
float getAlignmentY()
Get the alignment of the component along the x- or y- axis. For non-JComponent subclasses, which do not have the corresponding setter methods, you can set a component's alignment by creating a subclass and overriding these methods.
void setLayout(LayoutManager) 
LayoutManager getLayout()
Set or get the component's layout manager. The layout manager is responsible for sizing and positioning the components within a container.
void applyComponentOrientation(ComponentOrientation)void setComponentOrientation(ComponentOrientation)Set the ComponentOrientation property of this container and all the components contained within it. See Setting the Container's Orientation for more information.
Getting Size and Position Information 
MethodPurpose
int getWidth() 
int getHeight()
Get the current width or height of the component measured in pixels.
Dimension getSize() 
Dimension getSize(Dimension)
Get the component's current size measured in pixels. When using the one-argument version of this method, the caller is responsible for creating the Dimension instance in which the result is returned.
int getX() 
int getY()
Get the current x or y coordinate of the component's origin relative to the parent's upper left corner measured in pixels.
Rectangle getBounds()
Rectangle getBounds(Rectangle)
Get the bounds of the component measured in pixels. The bounds specify the component's width, height, and origin relative to its parent. When using the one-argument version of this method, the caller is responsible for creating the Rectangle instance in which the result is returned.
Point getLocation() 
Point getLocation(Point) 
Gets the current location of the component relative to the parent's upper left corner measured in pixels. When using the one-argument version of getLocation method, the caller is responsible for creating the Point instance in which the result is returned.
Point getLocationOnScreen()Returns the position relative to the upper left corner of the screen.
Insets getInsets()Get the size of the component's border.
Specifying Absolute Size and Position 
(see
Doing Without a Layout Manager (Absolute Positioning) for more information)
MethodPurpose
void setLocation(int, int) 
void setLocation(Point)
Set the location of the component, in pixels, relative to the parent's upper left corner. The twoint arguments specify x and y, in that order. Use these methods to position a component when you are not using a layout manager.
void setSize(int, int) 
void setSize(Dimension)
Set the size of the component measured in pixels. The two int arguments specify width and height, in that order. Use these methods to size a component when you are not using a layout manager.
void setBounds(int, int, int, int) 
void setBounds(Rectangle)
Set the size and location relative to the parent's upper left corner, in pixels, of the component. The four int arguments specify x, y, width, and height, in that order. Use these methods to position and size a component when you are not using a layout manager.
Posted by korcslewis
"데이터베이스 테이블을 클래스 형태로 구현시 이슈" 글에서 잠시 언급했던 것 중에 '중복제거'와 관련된 알고리즘을 소개한다. 물론 자료구조나 알고리즘 수업을 들어본 사람이 있으면 쉽게 구현이 가능하다. 사실 현업에 오래있는 동안 이러한 로직을 잘 사용하지 않으면 기억이 잘 나지 않는다.

나 역시 그런 면이 있었는데, 그냥 혼자서 곰곰히 생각해 본 대로 구현해 보았다.
이전 글에서 실제로 예제를 들을 수 있었으면 좋겠다고 언급한 적이 있는데, 이번 예제에서는 테이터 베이스의 클래스를 예로 들진 않았다. 하지만 샘플 코드를 통해서 알 수 있는 것은 테이블을 자바 클래스로 매핑을 하였다면 필시 테이블의 PK에 해당하는 키를 하나의 properties로 표현하였을 것이다. 즉, 중복제거에 필요한 column을 표현한 것인데 이를 샘플예제의 array index 라고 생각하면 된다. 이를 통해서 응용을 하여 실제 업무에 사용해도 무방하리라 생각된다.

본 샘플예제에서 한 가지 개선할 점은 결과 배열의 크기를 미리 예측하기 힘들어 원본 배열과 동일한 크기를 할당한다는 것이다. 자바는 동적 배열을 지원함으로 크기를 미리 알 수 있다면 불필요한 메모리 크기를 사용하지 않아도 된다. 이에 대해서는 좋은 아이디어가 있으면 함께 해 주었으면 좋겠다.

그리고 참고적으로 실무에선 데이터베이스의 테이블을 클래스 매핑시켜 이러한 중복제거를 사용시에는 배열을 이용할 경우가 없을 것이다. 대부분 List 형태로의 Collection을 이용함으로 이러한 처리는 오히려 배열을 사용하는 것보다는 쉽게 구현이 가능할 뿐만 아니라 메모리 할당에 대해서도 고민할 필요가 없을 것이다.

자, 이제 실제로 테스트 코드를 살펴보자.

/**
 * DuplicationRemoveTest.java
 */
package net.wiseant.test.algorithm;

import java.util.Random;

import junit.framework.TestCase;

/**
 * @author Sang Hyup Lee
 * @version 1.0
 *
 */
public class DuplicationRemoveTest extends TestCase {

    private Random random;
    private int min = 1;
    private int max = 10;
    
    private static int ARRAY_LENGTH = 20;
    
    private int getRandomNumber()
    {
        return random.nextInt((max - min) + 1) + min;
    }
    
    int[] array = new int[ARRAY_LENGTH];
    
    /* (non-Javadoc)
     * @see junit.framework.TestCase#setUp()
     */
    protected void setUp() throws Exception {
        super.setUp();
        random = new Random();
        
        for ( int i=0; i < array.length; i++ ) {
            array[i] = getRandomNumber();
            System.out.println("array[" + i + "] : " + array[i]);
        }
    }
    
    public void testDuplicationRemove() {
        int[] duplicationRemoveArray = new int[ARRAY_LENGTH];
        int index = 0;
        
        System.out.println("============ PROCESS ============");
        
        for ( int k=0; k < array.length; k++ ) {
            if ( index == 0 ) {
                duplicationRemoveArray[index] = array[k];
                index++;
            } else {
                boolean isDuplication = false;
                for ( int m=0; m < duplicationRemoveArray.length; m++ ) {
                    if ( array[k] == duplicationRemoveArray[m] ) {
                        isDuplication = true;
                        break;
                    }
                }
                
                if ( isDuplication ) {
                    System.out.println("Duplication number : " + array[k]);
                } else {
                    duplicationRemoveArray[index] = array[k];
                    index++;
                }
            }
        }
        
        System.out.println("============ RESULT ============");
        
        for ( int j=0; j < duplicationRemoveArray.length; j++ ) {
            if ( duplicationRemoveArray[j] == 0 ) break;
            System.out.println("duplicationRemoveArray[" + j + "] : " + duplicationRemoveArray[j]);
        }
    }

}



위의 소스 코드는 TDD 형태로 구현되어져 있다. TDD에 대해서는 다음에 기회가 있으면 언급을 하기로 하고 그냥 이렇게도 TDD를 사용할 수 있다는 것도 Tip 이라고 할 수 있겠다.

위의 소스 코드의 한 예를 살펴보면 다음과 같다.

array[0] : 2
array[1] : 3
array[2] : 2
array[3] : 2
array[4] : 1
array[5] : 2
array[6] : 8
array[7] : 7
array[8] : 9
array[9] : 4
array[10] : 1
array[11] : 3
array[12] : 1
array[13] : 3
array[14] : 1
array[15] : 4
array[16] : 7
array[17] : 1
array[18] : 8
array[19] : 9
============ PROCESS ============
Duplication number : 2
Duplication number : 2
Duplication number : 2
Duplication number : 1
Duplication number : 3
Duplication number : 1
Duplication number : 3
Duplication number : 1
Duplication number : 4
Duplication number : 7
Duplication number : 1
Duplication number : 8
Duplication number : 9
============ RESULT ============
duplicationRemoveArray[0] : 2
duplicationRemoveArray[1] : 3
duplicationRemoveArray[2] : 1
duplicationRemoveArray[3] : 8
duplicationRemoveArray[4] : 7
duplicationRemoveArray[5] : 9
duplicationRemoveArray[6] : 4


결과를 가만히 살펴보면 중복된 숫자를 디스플레이하고 최종 중복이 제거된 배열의 결과를 디스플레이 하고 있다. 실제로 동작하는 코드에서는 크기가 정해진 배열에 랜덤으로 1~10에 해당하는 숫자를 발생시켜 원본 배열 - array - 에 저장해 두고 이를 결과 배열 - duplicationRemoveArray - 에 중복이 제거된 숫자만을 저장한다.

로직은 그렇게 어려운 것이 아니니 더 이상의 설명은 필요가 없으리라 본다. 끝으로 실제업무에선 List와 같은 Collection 객체를 사용하게 될 경우가 많다고 했는데, 필요시에 이와 같이 테스트 후에 적용해 보는 것이 좋다는 생각이 든다.
Posted by korcslewis
2009/05/14 14:57

from String to InpuStream Java SE2009/05/14 14:57

부제 : 자바 문자열로부터 InputStream 얻어오기

String text = "자바";
InputStream inputStream = new ByteArrayInputStream(text.getBytes());

또는

InputStream inputStream = new ByteArrayInputStream(text.getBytes("utf-8"));

text.getBytes() 인자로는 Charset, CharsetName(String) 을 넣어 적절한 형태로 사용가능.


[참고]
이렇게 간단하지만 검색의 내용이 된다.


Posted by korcslewis
java.io 패키지에 FileFilter와 FilenameFilter 인터페이스가 존재한다. 이 둘은 각각 인터페이스를 implements하여 구현한 코드를 File.listFiles(FileFilter filter) 를 이용할 때 사용하게 된다. 일단 여기서는 FilenameFilter를 이용하여 일정한 확장자를 가진 파일만 file list로 얻어오는 예제를 살펴보자.

먼저, FilenameFilter를 이용한 JPEGFileFilter.java 클래스를 만들어본다.

package net.wiseant.io.util;

import java.io.File;
import java.io.FilenameFilter;

/**
 * @author SangHyup Lee
 * @version 1.0
 *
 */
public class JPEGFileFilter implements FilenameFilter {

    /* (non-Javadoc)
     * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
     */
    public boolean accept(File dir, String name) {
        // TODO Auto-generated method stub
        return name.endsWith(".jpg");
    }

}


JPEG파일의 확장자가 jpg인 파일에 대해서 true를 리턴해 준다고 생각하면 된다. 다음은 이를 이용한 간단한 파일 리스트를 얻어오는 테스트 프로그램을 작성해 보자. '.JPG' 파일은 자바에서는 대소문자를 구분함으로 제외된다.

이제 해당 디렉토리의 파일 리스트를 얻어올 때 JPEGFileFilter를 이용하여 확장자가 jpg 인 파일만 얻어오자.

package net.wiseant.junit.io;

import java.io.File;

import net.wiseant.io.util.JPEGFileFilter;

import junit.framework.TestCase;

/**
 * @author Sang Hyup Lee
 * @version 1.0
 *
 */
public class FilenameFilterTest extends TestCase {

    private String workDirectory = "";
    
    /* (non-Javadoc)
     * @see junit.framework.TestCase#setUp()
     */
    protected void setUp() throws Exception {
        super.setUp();
        workDirectory = "D:\\Photos";
    }

    public void testJPEGFileFilter() {
        File currentDirectory = new File(workDirectory);
        File[] fileList = null;
        JPEGFileFilter jpegFileFilter = new JPEGFileFilter();
        
        if ( currentDirectory.exists() && currentDirectory.isDirectory() ) {
            fileList = currentDirectory.listFiles(jpegFileFilter);
        }
        
        assertEquals(7, fileList.length);
    }
    
}


FilenameFilter를 implements 하여 구현한 코드는 반드시 public boolean accept(File dir, String name) 메소드를 구현해야 하는데 이를 잘 이용하면 이 외에도 다양한 방법으로 파일 리스트를 얻어올 수 있다.
Posted by korcslewis
자바 IO를 이용한 FileReader 예제 소스이다. 파일이 .txt 파일이면 정상적으로 파일의 내용을 한 줄씩 읽어들여 화면에 디스플레이해 준다(사실은 표준출력한다).

import java.io.*;

public class FileReader {
    public static void main (String[] args) {
        System.out.println ("Program to demonstrate reading from a file");
        
        BufferedReader br = null;
        String fileName = args[0];
        
        // If an error occurs, go to the "catch" block
        try {
            // FileInputStream fis = new FileInputStream (fileName);
            FileReader fis = new FileReader (fileName);
            br = new BufferedReader (fis);
        
            // continue to read lines while there are still some left to read
            while ( br.ready() ) {
                System.out.println (br.readLine());
            }
        
            // Close the input stream
            br.close();
        } catch (Exception e) {
            // Handle any error in opening the file
            System.err.println("File input error");
        }
    } // End of main method
    
} // End of the class FileReader
Posted by korcslewis
JavaMail API를 이용하여 메일을 발송하는 예제의 대부분은 SMTP 서버를 통해서 단순하게 메일을 보내는 것이다.
하지만 사내에서 SMTP를 사용하여 메일을 전송하거나, 별도의 서비스를 위해서 SMTP 서버를 사용하는 경우에는 SMTP 서버에 계정을 이용하여 발송하기 때문에 계정에 대한 패스워드가 존재한다. 또한 SMTP 서버를 패스워드 없이 오픈해 놓으면 스팸 메일을 발송하는 원인이 될 수 있다.

그래서 SMTP 서버로 메일을 발송할 때 보안설정이 되어 있는 형태로의 자바메일 발송예제가 필요한 것이다.
다음 두 개의 소스 코드가 존재한다.


[MyAuthenticator.java]
package net.wiseant.mail;

import javax.mail.Authenticator;

/**
 * @author SangHyup LEE
 *
 */
public class MyAuthenticator extends Authenticator {

    private String id;
    private String pw;

    public MyAuthenticator(String id, String pw) {
        this.id = id;
        this.pw = pw;
    }

    protected javax.mail.PasswordAuthentication getPasswordAuthentication() {
        return new javax.mail.PasswordAuthentication(id, pw);
    }

}

소스 코드에서 보는 바와 같이 java mail API의 Authenticator 클래스를 extends 하여 구현한 예제이다. 간략하게 생성자의 인자로 id와 password를 받는다. 그러면 해당 서버의 아이디와 패스워드로 인증된 객체를 생성하는 것이다.

[SMTPTest.java]
/**
 * 
 */
package net.wiseant.mail;

import java.util.Properties;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

/**
 * @author SangHyup LEE
 *
 */
public class SMTPTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String host = "mail.wiseant.net";//smtp 서버
        String subject = "메일제목";
        String content = "메일내용";
        String from = "wiseant@wiseant.net"; //보내는 사람
        String to = "korcslewis@gmail.com";
        
        try{
            // 프로퍼티 값 인스턴스 생성과 기본세션(SMTP 서버 호스트 지정)
            Properties props = new Properties();
            
            props.put("mail.smtp.host", host);
            props.put("mail.smtp.auth", "true");
            
            MyAuthenticator auth = new MyAuthenticator("wiseant@wiseant.net", "password");
            
            Session mailSession = Session.getDefaultInstance(props, auth);
            // sess.getPasswordAuthentication(host);
            
            Message msg = new MimeMessage(mailSession);
            msg.setFrom(new InternetAddress(from));//보내는 사람 설정
            InternetAddress[] address = {new InternetAddress(to)};
            
            msg.setRecipients(Message.RecipientType.TO, address);//받는 사람설정
            
            msg.setSubject(subject);// 제목 설정
            msg.setSentDate(new java.util.Date());// 보내는 날짜 설정
            msg.setContent(content,"text/html;charset=euc-kr"); // 내영 설정 (HTML 형식)
            
            Transport.send(msg); // 메일 보내기
            
            System.out.println("메일 발송을 완료하였습니다.");
        } catch ( MessagingException ex ) {
            System.out.println("mail send error : " + ex.getMessage());
        } catch ( Exception e ) {
            System.out.println("error : " + e.getMessage());
        }
    }

}


SMTPTest.java 코드는 SMTP 서버의 인증후, 실제 메일을 발송하는 예제이다. Java Mail API를 사용하여 보내는 예제와 거의 동일하다. 다만 MyAuthenticator 클래스의 인스턴스를 생성하여 보내고자 하는 SMTP 서버로부터 보안 설정을 확인 후, 수행하는 것이 다를 뿐이다.
Posted by korcslewis