2005년 8월 17일자 테크 팁 J2SE 5.0 그 이후와 Mustang에 기여하기에서 우리는 Java SE 6을 시작하는 방법을 배운 바 있다. 플랫폼은 아직 프리 베타 버전이지만 미리 방향을 살펴보고 몇 가지 기능을 시험해 보기에는 충분하며, 새로운 기능은 리소스 번들의 사용을 보다 효과적으로 제어할 수 있게 해준다.
리소스 번들은 애플리케이션의 로컬라이제이션에 사용된다. 그 사용법은 2005년 1월 19일자 테크팁 리소스 번들 로딩에 소개되어 있다. 기본적으로, 리소스 번들은 리소스를 로컬라이즈하기 위한 다양한 스트링을 매핑하여 텍스트 스트링이나 아이콘이 다양한 언어로 해석되는 이미지와 트랜잭션을 표시할 수 있도록 해준다.
리소스 번들의 사용은 java.util package 패키지에 있는 ResourceBundle 클래스에 의해 관리되며, 리소스 번들로 작업할 경우의 기본 프로세스는 다음 프로그램에서 보는 것처럼 ResourceBundle의 getBundle() 메소드를 통해 번들을 얻는 것이다.
import java.util.*;
public class Test1 {
public static void main(String args[]) {
Locale locale = Locale.ENGLISH;
ResourceBundle myResources =
ResourceBundle.getBundle("MyResources", locale);
String string = myResources.getString("HelpKey");
System.out.println("HelpKey: " + string);
}
}
Test1 프로그램은 MyResources라 불리는 번들을 얻는다. 그런 다음, 번들로부터 HelpKey라는 이름의 리소스를 얻어서 리소스의 값을 프린트한다.
MyResources는 다음의 클래스 파일일 수도 있고,
import java.util.*;
public class MyResources extends ListResourceBundle {
public Object[][] getContents() {
return new Object[][] {
{"OkKey", "OK"},
{"CancelKey", "Cancel"},
{"HelpKey", "Help"},
{"YesKey", "Yes"},
{"NoKey", "No"},
};
}
}
또는 다음과 같은 키 값의 쌍을 가지는 MyResources.properties라는 이름의 파일일 수도 있다.
OkKey=OK CancelKey=Cancel HelpKey=Help YesKey=Yes NoKey=No
그러나, 리소스 번들을 XML 파일로 만들려면 어떻게 해야 할까? 우선, java.util.Properties 클래스는 파일을 로드하는 두 가지 방법을 제공한다. 첫 번째 방법은 load() 메소드를 통해 key=value 타입 파일을 읽어 들이는 것이고, 두 번째 방법은 loadFromXML() 메소드를 통해 XML 파일의 속성을 로드하는 것이다. Control이라는 이름의 Mustang 내의 ResourceBundle의 새로운 이너 클래스(inner class) 덕분에 리소스 번들을 XML 파일로 저장할 수 있다.
이 시점에서 사용자는 Mustang project home page(영문)에서 제공하는 최신의 Mustang 스냅샷 릴리즈를 설치하고 싶을 수도 있겠다.
ResourceBundle.Control 클래스는 ResourceBundle.getBundle()이 번들을 검색하고 로드할 때 호출되는 일련의 callback 메소드를 제공한다. 여러분은 자체 Control 클래스를 제공함으로써 기본값 로딩 및 캐싱 동작을 오버라이드할 수 있다.
그러한 커스텀 Control 클래스를 구현하기 위해서는 getFormats()와 newBundle() 메소드를 오버라이드하기만 하면 된다. getFormats() 메소드는 여러분이 XML을 포맷으로 지원한다는 사실을 알려줄 것이고, 그러면 newBundle()은 해당 번들을 찾게 된다. 기본 Control 클래스 내에는 기본 번들 이름을 실제 리소스 이름으로 전환하기 위한 보조 메소드가 있다.
커스텀 ResourceBundle.Control 구현과 함께 XMLResourceBundle이라 불리는 ResourceBundle의 서브클래스가 포함되어 있다. 이 서브클래스는 XML 파일을 로드하고 이를 ResourceBundle로 처리하는 데 사용된다.
다음은 Control 클래스와 ResourceBundle에 대한 전체 클래스 정의식이다.
import java.io.*;
import java.net.*;
import java.util.*;
public class XMLResourceBundleControl extends
ResourceBundle.Control {
private static String XML = "xml";
public List getFormats(String baseName) {
return Collections.singletonList(XML);
}
public ResourceBundle newBundle(String baseName,
Locale locale, String format, ClassLoader loader,
boolean reload)
throws IllegalAccessException,
InstantiationException, IOException {
if ((baseName == null) || (locale == null) ||
(format == null) || (loader == null)) {
throw new NullPointerException();
}
ResourceBundle bundle = null;
if (format.equals(XML)) {
String bundleName = toBundleName(baseName, locale);
String resourceName =
toResourceName(bundleName, format);
URL url = loader.getResource(resourceName);
if (url != null) {
URLConnection connection = url.openConnection();
if (connection != null) {
if (reload) {
connection.setUseCaches(false);
}
InputStream stream = connection.getInputStream();
if (stream != null) {
BufferedInputStream bis =
new BufferedInputStream(stream);
bundle = new XMLResourceBundle(bis);
bis.close();
}
}
}
}
return bundle;
}
private static class XMLResourceBundle extends
ResourceBundle {
private Properties props;
XMLResourceBundle(InputStream stream) throws IOException {
props = new Properties();
props.loadFromXML(stream);
}
protected Object handleGetObject(String key) {
return props.getProperty(key);
}
public Enumeration getKeys() {
Set handleKeys = props.stringPropertyNames();
return Collections.enumeration(handleKeys);
}
}
public static void main(String args[]) {
ResourceBundle bundle = ResourceBundle.getBundle("Test2",
new XMLResourceBundleControl());
String string = bundle.getString("HelpKey");
System.out.println("HelpKey: " + string);
}
}
커스텀 Control 클래스에는 3행의 테스트 프로그램이 포함되어 있다.
ResourceBundle bundle = ResourceBundle.getBundle("Test2",
new XMLResourceBundleControl());
String string = bundle.getString("HelpKey");
System.out.println("HelpKey: " + string);
여기서 중요한 행이 바로 첫 번째 행인데, 반드시 커스텀 control을 getBundle() 메소드에 패스해야 한다. 그런 다음, 다른 번들과 동일한 방식으로 번들을 사용하면 된다.
다음은 Test2.xml이라는 이름의 XML 리소스 번들 파일의 형태이다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="OkKey">OK</entry>
<entry key="CancelKey">Cancel</entry>
<entry key="HelpKey">Help</entry>
<entry key="YesKey">Yes</entry>
<entry key="NoKey">No</entry>
</properties>
XMLResourceBundleControl 프로그램을 실행하면 다음과 같은 결과물이 산출된다.
> java XMLResourceBundleControl
HelpKey: Help
getTimeToLive() 및 needsReload() 메소드는 상기 ResourceBundle.Control의 구현에 표시되어 있지 않다.
public long getTimeToLive(String baseName,
Locale locale)
public boolean needsReload(String baseName,
Locale locale,
String format,
ClassLoader loader,
ResourceBundle bundle,
long loadTime)
getTimeToLive() 메소드는 ResourceBundle.Control 아래에 로드된 리소스 번들에 대해 ‘time-to-live’ 값을 반환하고, 리소스 번들은 다음에 사용할 때 성능을 높이기 위해 캐시에 보관된다. 이는 동일 클래스 로더에서 번들을 로드하기 위한 두 번째 호출이 이미 로드되고 캐시된 번들을 발견하게 된다는 것을 의미한다. 양의 time-to-live 값은 번들이 재검증(revalidate) 없이 캐시에 머무를 수 있는 밀리초의 수를 지정한다. getTimeToLive()의 기본 반환 값은 TTL_NO_EXPIRATION_CONTROL으로, 이는 expiration control을 디스에이블 한다. 번들이 캐시되는 것을 원치 않을 경우에는 getTimeToLive()가 ResourceBundle.Control.TTL_DONT_CACHE를 반환하도록 한다. 0이 반환될 경우 번들은 캐시되지만 getBundle()이 호출될 때마다 번들이 마지막 호출로부터 재검증된다. 캐시를 소거하려면 ResourceBundle의 정적(static) clearCache() 메소드를 호출한다. 특정 클래스 로더를 통해 로드된 번들을 소거하려면 옵션 ClassLoader 인자를 사용하고, 지정되지 않은 경우에는 호출자의 클래스 로더를 사용하면 된다.
needsReload() 메소드는 캐시 내의 만료된 번들을 재로드할 필요가 있는지 여부를 결정한다. true의 반환 값은 번들을 재로드할 필요가 있음을, false는 필요가 없음을 의미한다. 또한, Control 클래스가 needsReload() 메소드를 오버라이드하도록 하여 리소스 번들을 재로드할 필요가 있는지 여부를 제어할 수 있다. 예를 들어, 번들을 항상 재로드하기를 원한다면 needsReload() 메소드가 항상 true를 반환하도록 한다. needsReload()가 항상 true를 반환할 경우에는 반드시 getTimeToLive() 메소드가 0을 반환하도록 해야 한다. 그렇지 않을 경우 데이터가 필요 이상으로 오랫동안 캐시되는 현상이 발생하게 된다.
리소스 번들에서 강화된 기능과 Mustang 내의 기타 국제화(internationalization) 기능에 관한 자세한 내용은 썬 소프트웨어 아키텍트 John O’Conner의 블로그 Overview of Mustang's internationalization features(영문)를 참조하기 바란다.
"Java SE" 카테고리의 다른 글
- 리스너 리스트를 위한 WEAKHASHMAP 사용하기 (댓글 1개 / 트랙백 0개) 2006/03/08
- J2SE 5.0의 Java 2D API 기능 강화 (댓글 2개 / 트랙백 0개) 2006/05/12
- 3D 화면(scene)에 빛 효과 주기 (댓글 1개 / 트랙백 0개) 2004/07/30
- 다이얼로그 Modality (댓글 1개 / 트랙백 0개) 2006/06/09
- 쿠키 처리 (댓글 22개 / 트랙백 3개) 2007/07/23
- 사용자 데이터그램 프로토콜의 프로그래밍 (댓글 1개 / 트랙백 0개) 2004/06/30
- 락(LOCKS) (댓글 1개 / 트랙백 0개) 2005/09/22
- Java Web Start 퍼시스턴스 (댓글 3개 / 트랙백 0개) 2006/12/24
- AFFINETRANSFORM 이해하기 (댓글 3개 / 트랙백 0개) 2003/09/09
- 사용자 인터페이스에서 Action 사용하기 (댓글 5개 / 트랙백 2개) 2007/02/22
댓글을 달아 주세요
좋은 정보 감사해요~
2007/09/19 05:00