검색결과 리스트
글
아시다시피 Java 에서 Win32 API 를 호출하려면, JNI 를 사용해야 합니다.
Java Native Interface 이던가요? 약어는 가물가물 하네요. 귀차니즘...
아무튼 이번에는 Java 의 JNI 를 이용하여, 폴더 모니터를 만들어 보도록 하겠습니다.
폴더 모니터가 무언가 하니, 특정 폴더에 파일이 추가되거나, 삭제되거나 이름이 변경되거나 하는 등...
변화가 있을 때, Notify 해 주는 녀석을 만들어 보자.. 이 말입니다.
JNI 를 Java 에서 사용하는 방법(?)은 다음과 같습니다.
1. Java 파일을 열심히 만든다.
- 코딩하란 소리입니다.
2. 앞서 작성한 Java 소스파일을 컴파일 한다.
3. javah 를 이용하여, *.h 파일을 생성한다.
- c 에서 사용할 헤더파일을 만들라는 것입니다.
4. 앞에서 만든 header 파일을 구현한, dll 파일을 생성한다.
- *.h 에 정의된 함수들을 구현한 dll 파일을 생성한다는 말입니다.
5. 끗!
간단한가요?
직접 한번 만들어 보도록 해보죠.
1. Java 파일을 열심히 만든다.
package com;
public class FolderWatcher implements Runnable {
// win32
private final static int WAIT_OBJECT_0 = 0x00000000;
private final static int WAIT_TIMEOUT = 258;
// Filter
public final static int FILTER_CHANGE_FILE_NAME = 0x00000001;
public final static int FILTER_CHANGE_DIR_NAME = 0x00000002;
public final static int FILTER_CHANGE_ATTRIBUTES = 0x00000004;
public final static int FILTER_CHANGE_SIZE = 0x00000008;
public final static int FILTER_CHANGE_LAST_WRITE = 0x00000010;
public final static int FILTER_CHANGE_SECURITY = 0x00000100;
// win32 api
private native int FindFirstChangeNotification(String folder, boolean watchSubtree, int filter);
private native boolean FindNextChangeNotification(int hChangeHandle);
private native boolean FindCloseChangeNotification(int hChangeHandle);
private native int WaitForMultipleObjects(int nCount, int handle, boolean waitAll, int milliSeconds);
// jni
static { System.loadLibrary("FolderWatcher"); }
// listener
private IFolderChangeListener listener = null;
private boolean isWatching = false;
private int handle = 0;
private volatile Object lockObj = new Object();
private String folderPath = "";
private boolean watchSubfolder = false;
private int filter;
private Thread watchThread = null;
//============
// 생성자
//============
public FolderWatcher(IFolderChangeListener listener) {
this.listener = listener;
}
public boolean start(String folderPath, boolean watchSubfolder, int filter) {
synchronized (this.lockObj) {
// 이미 실행중인 경우
if(isWatching == true) { return true; }
// setting
this.folderPath = folderPath;
this.watchSubfolder = watchSubfolder;
this.filter = filter;
// Thread 실행
this.watchThread = new Thread(this);
this.watchThread.setDaemon(true);
this.watchThread.start();
return true;
}
}
@Override
public void run(){
this.isWatching = true;
handle = FindFirstChangeNotification(this.folderPath, this.watchSubfolder, this.filter);
if(handle == -1) {
System.out.println("FindFirstChangeNotification function failed.");
return;
}
if(handle == 0) {
System.out.println("ERROR: FindFirstChangeNotification function failed.");
return;
}
while(this.isWatching == true) {
System.out.println("Waiting for notification...");
int waitStatus = WaitForMultipleObjects(1, handle, false, 0xFFFFFFFF);
switch(waitStatus)
{
case WAIT_OBJECT_0:
if(FindNextChangeNotification(handle) == true) {
callback();
}
break;
case WAIT_TIMEOUT:
System.out.println("No changes in the timeout period.");
break;
default:
System.out.println("ERROR: Unhandled dwWaitStatus.");
break;
}
}
}
public boolean stop() {
synchronized (this.lockObj) {
if(this.isWatching == false) { return true; }
//stopWatch();
FindCloseChangeNotification(this.handle);
this.isWatching = false;
this.watchThread.interrupt();
return true;
}
}
private void callback() {
if(this.listener != null) {
this.listener.folderChanged(this, this.folderPath);
}
}
}
// win32 api
private native int FindFirstChangeNotification(String folder, boolean watchSubtree, int filter);
private native boolean FindNextChangeNotification(int hChangeHandle);
private native boolean FindCloseChangeNotification(int hChangeHandle);
private native int WaitForMultipleObjects(int nCount, int handle, boolean waitAll, int milliSeconds);
// jni
static { System.loadLibrary("FolderWatcher"); }
입니다. 나머진 늘 보는 Java 코드입니다.
저기서 native 란, 눈치 빠른 분들은 아셨겠지만 외부 dll 에 정의된 함수라고 알려주는 것입니다.
즉, 이 소스코드에서는 함수 원형만 제공할 뿐이죠.
뒤에 따라 나오는 static { System.loadLibrary("FolderWatcher"); } 는 dll 을 불러오겠다는 말입니다.
이때 주의해야 하는 것은, dll 파일 명이 xxxx.dll 일 경우 xxxx 만 적어야 한다는 것입니다.
다시 말하지만, dll 의 파일명(확장자를 제외한)입니다.
2. 앞서 작성한 Java 소스파일을 컴파일 한다.
다들 잘 하실거라고 믿습니다.
3. javah 를 이용하여, *.h 파일을 생성한다.
잘 보셔야 합니다.
javah -classpath ./ com.FolderWatcher
이렇게 하면, 현재 위치에 FolderWatcher.h 비슷한 이름의 파일이 생깁니다.
만약 패키지명이 com.win32.api 였다면,,,
javah -classpath ./ com.win32.api.FolderWatcher
아시겠나요?
뒤에 오는 FolderWatcher 는 *.class 파일명이 아닌, 바로 Java 의 Class 명이라는 것입니다.
다시 말하지만, 파일명이 아니라 Class 명 입니다.
4. 앞에서 만든 header 파일을 구현한, dll 파일을 생성한다.
저는 Visual Studio 2008 로 만들었습니다.
C++ 에서
#include "FolderWatcher.h"
#include <windows.h>
/*
* Class: pCloud_win32_FolderWatcher
* Method: FindFirstChangeNotification
* Signature: (Ljava/lang/String;ZI)I
*/
JNIEXPORT jint JNICALL Java_pCloud_win32_FolderWatcher_FindFirstChangeNotification
(JNIEnv * env, jobject obj, jstring path, jboolean watchSubtree, jint filter)
{
jchar* new_path = (*env)->GetStringChars(env, path, NULL);
OutputDebugString((LPCWSTR)new_path);
return (jint)FindFirstChangeNotification((LPCWSTR)new_path, (BOOL)watchSubtree, filter);
}
/*
* Class: pCloud_win32_FolderWatcher
* Method: FindNextChangeNotification
* Signature: (I)I
*/
JNIEXPORT jboolean JNICALL Java_pCloud_win32_FolderWatcher_FindNextChangeNotification
(JNIEnv * env, jobject obj, jint changeHandle)
{
return FindNextChangeNotification((HANDLE)changeHandle);
}
/*
* Class: pCloud_win32_FolderWatcher
* Method: FindCloseChangeNotification
* Signature: (I)I
*/
JNIEXPORT jboolean JNICALL Java_pCloud_win32_FolderWatcher_FindCloseChangeNotification
(JNIEnv * env, jobject obj, jint changeHandle)
{
return FindCloseChangeNotification((HANDLE)changeHandle);
}
/*
* Class: pCloud_win32_FolderWatcher
* Method: WaitForMultipleObjects
* Signature: (IIZI)I
*/
JNIEXPORT jint JNICALL Java_pCloud_win32_FolderWatcher_WaitForMultipleObjects
(JNIEnv * env, jobject obj, jint count, jint changeHandle, jboolean waitAll, jint milliSeconds)
{
HANDLE handle = (HANDLE)changeHandle;
return WaitForMultipleObjects(1, &handle, (BOOL)waitAll, (DWORD)milliSeconds);
}
5. 끗!
이제 dll 을 적당한 위치에 넣고나서 java 를 실행하면, 정상적으로 프로그램이 돌아가는 것을 보실 수 있습니다.
'Java' 카테고리의 다른 글
FolderMonitoring - 파일 변경 감지하는 방법 (0) | 2011.09.30 |
---|---|
Java로 나만의 프로토콜 만들기 (1) | 2011.06.16 |
Runtime.getRuntime().exec() 호출시 종료되지 않는 문제 (6) | 2011.06.01 |
[팁] JNI 의 jstring 을 LPCWSTR(wchar_t)로 변환하기 (0) | 2011.05.25 |
RECENT COMMENT