/* * DirectoryMonitor.java * * Created 26.05.2007. * * eaio: NativeCall - calling operating system methods from Java * Copyright (c) 2004-2007 Johann Burkard () * * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package com.eaio.nativecall.monitor; import java.io.File; import java.io.IOException; import java.util.Arrays; import sun.misc.ServiceConfigurationError; import com.eaio.nativecall.Holder; import com.eaio.nativecall.IntCall; import com.eaio.nativecall.NativeCall; /** * Monitors a directory for changes. Does not rely on polling. * * @author Johann Burkard * @version $Id: DirectoryMonitor.java 138 2008-02-21 22:45:48Z Johann $ * @see Call * native methods in a DLL from Java without JNI * @see NativeCall – call native methods from Java without JNI */ public class DirectoryMonitor { private static final Integer DESIRED_ACCESS = new Integer(0x80000000); // GENERIC_READ private static final Integer SHARE_MODE = new Integer(0x01 | 0x02 | 0x04); // READ, WRITE, DELETE private static final Integer CREATION_DISPOSITION = new Integer(3); // OPEN_EXISTING private static final Integer FLAGS_AND_ATTRIBUTES = new Integer(0x2000000); // BACKUP_SEMANTICS private static final Integer NOTIFY_FILTER = new Integer(0x01 | 0x02); // CHANGE_FILE_NAME, CHANGE_DIR_NAME protected final File directory; /** * Constructor for DirectoryMonitor. * * @param dir * the directory to monitor. The directory must exist. * @throws ServiceConfigurationError * @throws IOException * @throws UnsupportedOperationException * @throws UnsatisfiedLinkError * @throws SecurityException * @throws IllegalArgumentException * if the directory does not exist or is not a directory */ public DirectoryMonitor(File dir) throws SecurityException, UnsatisfiedLinkError, UnsupportedOperationException, IOException, ServiceConfigurationError { if (!dir.exists()) { throw new IllegalArgumentException(dir + " does not exist"); } if (!dir.isDirectory()) { throw new IllegalArgumentException(dir + " is not a directory"); } this.directory = dir; NativeCall.init(); } /** * Starts watching the directory and returns once it's contents have * changed. * * @throws IOException */ public void monitor() throws IOException { IntCall createFile = null; IntCall closeHandle = null; IntCall readDirectoryChanges = null; int dirHandle = 0; try { createFile = new IntCall("CreateFileA"); closeHandle = new IntCall("CloseHandle"); readDirectoryChanges = new IntCall("ReadDirectoryChangesW"); dirHandle = createFile.executeCall(new Object[] { directory.getCanonicalPath(), DESIRED_ACCESS, SHARE_MODE, null, CREATION_DISPOSITION, FLAGS_AND_ATTRIBUTES, null }); Holder returnedBufferLength = new Holder(new Integer(0)); byte[] buffer = new byte[1024]; Arrays.fill(buffer, (byte) 0xff); Holder fileNotifyInformation = new Holder(buffer); readDirectoryChanges.executeBooleanCall(new Object[] { new Integer(dirHandle), fileNotifyInformation, new Integer(buffer.length), Boolean.FALSE, NOTIFY_FILTER, returnedBufferLength, null, null }); } finally { if (closeHandle != null) { if (dirHandle != 0) { closeHandle.executeBooleanCall(new Integer(dirHandle)); } closeHandle.destroy(); } if (readDirectoryChanges != null) { readDirectoryChanges.destroy(); } if (createFile != null) { createFile.destroy(); } } } }