Tips and Notes on Java

자바 언어에 대한 팁을 생각나는 대로 적고 있습니다.
1. Jar URL 유감
자바는 Jar를 URL로 사용할 수 있게 하고 있으며 이에 대한 연결을 JarURLConnection을 통해 구현하고 있습니다.
그런데 문제는 JarURLConnection이 수행 성능의 개선을 위해 URL로부터 다운 로드한 Jar 파일을 무한정 캐시하고 있다는 점입니다.

따라서 class loader 등의 구현에서 jar URL 방식은 classloader를 가비지컬렉트하더라도 url connection 구현 쪽에서 jar 파일을 계속해서 캐시하게 되므로, 윈도우의 경우 파일에 대한 잠금도 발생하고, jar 파일을 변경하더라도 반영이 되지 않게 됩니다.

jar 파일의 경우에는 URLClassLoader 역시 사용하지 않는 것이 좋겠구요.
Jar를 사용한 ClassLoader를 구현할 때에는 URL을 사용하지 않고 직접 JarFile (혹은 ZipFile)을 사용하여 구현하는 것이 방법이 되겠습니다.

아래 링크는 Jar URL의 이 특성 때문에 jar 파일이 삭제가 안 되는 것을 피해가기 위해 jar 파일을 나중에 자동으로 지워지도록 하는 delete on close 모드를 JarFile이나 ZipFile에 추가하였다는 내용입니다.(모드 인자로 OPEN_READ | OPEN_DELETE 를 함께 주면 이렇게 됩니다.)
그렇게 하더라도 나중에... 정확한 시점은 알 수 없이, 열었던 Jar 파일을 닫으면서 삭제는 해주겠지만, ClassLoader와 같은 경우에는 도움이 되는 내용은 아닙니다.

2. Joshua Bloch의 Collection
java.util 패키지의 컬렉션을 주도적으로 정의한 사람이 Joshua Bloch라는 것은 잘 알려진 사실입니다.
Collection 라이브러리들이 얼마나 잘 정의되어 있는지 가끔 그 내적 완결성에 놀라게 됩니다. 그만큼 주도면밀한 성격을 가진 사람이 아니었을까 싶습니다.
Collections나 Arrays와 같은 유틸리티를 모아둔 클래스를 보면, 컬렉션의 핵심으로 잘 정의되지 못하지만, 너무 자주 사용될 기능들을 이렇게 치밀하게 helper class에 모아둔 것을 보면 역시 패키지와 클래스들만으로도 내적 연관성을 두어 하나의 완결된 우주를 구성하려 하는 게 아닌가 하는 생각이 들 정도입니다.
가끔 Collection에 Bag이 포함되었으면 하는 때가 있긴 하지만... ^^;

3. HttpURLConnection Tip
http: URL을 openConnection()하면 얻을 수 있는 java.net.HttpURLConnection은 상당히 강력한 기능을 가지고 있는 HTTP 클라이언트입니다.

  connection.setDoOutput(true);
  connection.setRequestMethod("POST");
  OutputStream out = connection.getOutputStream();
이와 같이 하면 HTTP URL connection을 사용하여 POST 호출을 할 수 있습니다.
HttpURLConnection을 사용하여 이와 같은 호출을 한 후 결과를 받을 때, 정상적인 경우에는 getInputStream()을 통하여 받게 됩니다.
하지만, response code가 HTTP_OK가 아닌 경우에는 getErrorStream()을 통하여 실제 응답 데이터를 받게 되어 있으므로 주의해야 합니다.
따라서, 좀더 일반적인 방법을 HttpURLConnection의 응답을 처리하려면 다음과 같은 순서로 구현하면 됩니다.
  1. 먼저 getResponseCode()를 검사합니다.
  2. response code가 HTTP_OK (200)인 경우에는 getInputStream()을 열어 메시지를 받으면 됩니다.
  3. 그렇지 않은 경우, (예를 들면 SOAP Fault가 사용하는 INTERNAL_ERROR (500)인 경우) getResponseMessage()를 하여 응답 코드에 따라 오는 메시지를 가져오고, getErrorStream()을 열어 실제 응답 메시지를 받을 수 있습니다.
HttpURLConnection을 사용할 때 Timeout을 지정하는 방법은 다음과 같습니다. 이것은 JDK 1.4.x 이상에서만 지원하는 비표준 기능입니다.
openConnection()을 하기 전에 다음과 같이 시스템 속성을 지정합니다.
  System.setProperty("sun.net.client.defaultConnectTimeout", "30000");
  System.setProperty("sun.net.client.defaultReadTimeout", "30000");
이렇게 하면 connect하는 데 걸리는 timeout과 실제 fetch하는 데 걸리는 timeout을 지정할 수 있습니다. 값의 단위는 milli second입니다.
timeout이 발생하면 java.net.SocketTimeoutException이 던져지게 됩니다. 이를 catch하여 적절한 조처를 취하면 되겠지요.

4. Ant Javac Task and endorsed directory path
Ant는 자바 개발자라면 누구에게나 친숙할 빌드 툴입니다.
한번은 javac 컴파일러의 커맨드 라인이라면 다음과 같은 내용을 줘야 할 일이 생겼습니다.

  javac -J-Djava.endorsed.dirs=/some/where/endores/dir *.java

Ant의 javac task에서는 이것을 어떻게 처리할 수 있을까요? javac task에는 java task와 달리 sysproperty가 없습니다.
ant.bat을 수정하여 ant 자체에서 이 값을 지정하면 ant가 실행시키는 javac에서도 물론 이 속성이 지정되긴 합니다.
하지만, 원하는 task 한 곳에서만 지정될 필요가 있다면 이것은 현명한 방법은 아닙니다.
고심 끝에 찾은 해결책은 다음입니다.
    <javac srcdir="${src.dir}" 
	   destdir="${target.dir}"
	   includes="**/*.java"
	   deprecation="on"
	   debug="on"
	   optimize="off"
	   source="1.4"
	   compiler="extJavac">

      <compilerarg value="-J-Djava.endorsed.dirs=${endorsed.lib.dir}"/>
      <classpath>
	<path refid="compile.classpath"/>
      </classpath>
    </javac>
compiler를 extJavac를 선택하여 외부 javac 프로세스가 실행될 때 넘겨준 compiler argument를 처리하도록 하는 방법입니다.
생각해보면 javac task에서 sysproperty를 지원하게 하는 방법이 더 간단하고 통일성 있어 보이는군요. 시간이 나면(ㅠ_ㅠ;;) 수정해서 Ant 개발자에게 메일을 보내야겠네요.

5. JAAS Security debugging Tip
Security 관련 코딩을 할 때 현재의 Subject나 Permission, 혹은 ProtectionDomain에 대한 정보를 쉽게 추적할 수 없어 답답한 일이 발생합니다.
이럴 경우를 위해 Sun의 엔지니어들은 java.security.debug라는 시스템 속성을 두었습니다.

  java -Djava.security.debug="access,domain,stack,failure" SomeClass

access를 켜면 AccessControlContext에 접근할 때마다 로그를 남기게 됩니다. domain 옵션은 ProtectionDomain 내용을 모두 덤프할 것인가를 결정합니다.
stack 옵션은 access denial이 발생했을 때 Call Stack을 찍는 옵션이고, failure는 access denial 상황에서 실패한 ProtectionDomain을 덤프하는 옵션입니다.
다른 옵션들은 access 옵션이 켜졌을 때에만 동작하므로 access 옵션을 켰을 대에만 다른 옵션들이 적용됩니다.
각 옵션들에 대한 공식 설명은 다음과 같습니다. 이 내용은 sun.security.util.Debug 클래스에 있습니다.

	all           turn on all debugging
	access        print all checkPermission results
	combiner      SubjectDomainCombiner debugging
	jar           jar verification
	logincontext  login context results
	policy        loading and granting
	provider      security provider debugging
	scl           permissions SecureClassLoader assigns

	The following can be used with access:

	stack     include stack trace
	domain    dumps all domains in context
	failure   before throwing exception, dump stack
	          and domain that didn't have permission

	Note: Separate multiple options with a comma

6. JMX remoting debugging Tip
JMX remoting의 경우 JDK 1.4부터 포함된 logging API를 사용하여 추적할 수 있는 로그를 포함하고 있습니다.
따라서, javax.management.remote 의 로그 레벨을 ALL로 하면 해당하는 로그를 모두 볼 수 있습니다.


[Class Loader, Dynamic Proxy, XML, JDBC, JNDI, LDAP, Transaction, Security, Cryptography, SSL, Authentication, Login, Authorization, CORBA, RMI, RMI-IIOP, ... 본격적인 자바 개발자로 가기 위한 (책) 자바 2 SDK 1.4 시작 그리고 완성]

Yoon Kyung Koo <yoonforh at yahoo dot com>
이 페이지는 2004년 7월 22일에 처음 만들어졌습니다.
Last modified: Sat Dec 11 23:12:48 +0900 2004