@@ -34,26 +34,37 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil ;
/**
* 路径监听器<br>
* 路径监听器
*
* <p>
* 监听器可监听目录或文件<br>
* 如果监听的Path不存在, 则递归创建空目录然后监听此空目录<br>
* 递归监听目录时,并不会监听新创建的目录
*
* @author Looly
*
*/
public class WatchMonitor extends Thread implements Closeable , Serializable {
private static final long serialVersionUID = 1L ;
/** 事件丢失 */
/**
* 事件丢失
*/
public static final WatchEvent . Kind < ? > OVERFLOW = StandardWatchEventKinds . OVERFLOW ;
/** 修改事件 */
/**
* 修改事件
*/
public static final WatchEvent . Kind < ? > ENTRY_MODIFY = StandardWatchEventKinds . ENTRY_MODIFY ;
/** 创建事件 */
/**
* 创建事件
*/
public static final WatchEvent . Kind < ? > ENTRY_CREATE = StandardWatchEventKinds . ENTRY_CREATE ;
/** 删除事件 */
/**
* 删除事件
*/
public static final WatchEvent . Kind < ? > ENTRY_DELETE = StandardWatchEventKinds . ENTRY_DELETE ;
/** 全部事件 */
/**
* 全部事件
*/
public static final WatchEvent . Kind < ? > [ ] EVENTS_ALL = { //
OVERFLOW , //事件丢失
ENTRY_MODIFY , //修改
@@ -61,29 +72,47 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
ENTRY_DELETE //删除
} ;
/** 监听路径,必须为目录 */
/**
* 监听路径,必须为目录
*/
private Path path ;
/** 递归目录的最大深度, 当小于1时不递归下层目录 */
/**
* 递归目录的最大深度, 当小于1时不递归下层目录
*/
private int maxDepth ;
/** 监听的文件,对于单文件监听不为空 */
/**
* 监听的文件,对于单文件监听不为空
*/
private Path filePath ;
/** 监听服务 */
/**
* 监听服务
*/
private WatchService watchService ;
/** 监听器 */
/**
* 监听器
*/
private Watcher watcher ;
/** 监听事件列表 */
/**
* 监听事件列表
*/
private WatchEvent . Kind < ? > [ ] events ;
/** 监听是否已经关闭 */
/**
* 监听是否已经关闭
*/
private boolean isClosed ;
/** WatchKey 和 Path的对应表 */
/**
* WatchKey 和 Path的对应表
*/
private Map < WatchKey , Path > watchKeyPathMap = new HashMap < > ( ) ;
//------------------------------------------------------ Static method start
/**
* 创建并初始化监听
*
* @param url URL
* @param events 监听的事件列表
* @return 监听对象
@@ -94,6 +123,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 创建并初始化监听
*
* @param url URL
* @param events 监听的事件列表
* @param maxDepth 当监听目录时, 监听目录的最大深度, 当设置值为1( 或小于1) 时, 表示不递归监听子目录
@@ -105,6 +135,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 创建并初始化监听
*
* @param uri URI
* @param events 监听的事件列表
* @return 监听对象
@@ -115,6 +146,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 创建并初始化监听
*
* @param uri URI
* @param events 监听的事件列表
* @param maxDepth 当监听目录时, 监听目录的最大深度, 当设置值为1( 或小于1) 时, 表示不递归监听子目录
@@ -126,6 +158,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 创建并初始化监听
*
* @param file 文件
* @param events 监听的事件列表
* @return 监听对象
@@ -136,6 +169,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 创建并初始化监听
*
* @param file 文件
* @param events 监听的事件列表
* @param maxDepth 当监听目录时, 监听目录的最大深度, 当设置值为1( 或小于1) 时, 表示不递归监听子目录
@@ -147,6 +181,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 创建并初始化监听
*
* @param path 路径
* @param events 监听的事件列表
* @return 监听对象
@@ -157,6 +192,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 创建并初始化监听
*
* @param path 路径
* @param events 监听的事件列表
* @param maxDepth 当监听目录时, 监听目录的最大深度, 当设置值为1( 或小于1) 时, 表示不递归监听子目录
@@ -168,6 +204,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 创建并初始化监听
*
* @param path 路径
* @param events 监听事件列表
* @return 监听对象
@@ -178,6 +215,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 创建并初始化监听
*
* @param path 路径
* @param events 监听事件列表
* @param maxDepth 当监听目录时, 监听目录的最大深度, 当设置值为1( 或小于1) 时, 表示不递归监听子目录
@@ -188,8 +226,10 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
}
//--------- createAll
/**
* 创建并初始化监听,监听所有事件
*
* @param uri URI
* @param watcher {@link Watcher}
* @return {@link WatchMonitor}
@@ -200,6 +240,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 创建并初始化监听,监听所有事件
*
* @param url URL
* @param watcher {@link Watcher}
* @return {@link WatchMonitor}
@@ -214,6 +255,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 创建并初始化监听,监听所有事件
*
* @param file 被监听文件
* @param watcher {@link Watcher}
* @return {@link WatchMonitor}
@@ -224,6 +266,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 创建并初始化监听,监听所有事件
*
* @param path 路径
* @param watcher {@link Watcher}
* @return {@link WatchMonitor}
@@ -234,6 +277,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 创建并初始化监听,监听所有事件
*
* @param path 路径
* @param watcher {@link Watcher}
* @return {@link WatchMonitor}
@@ -246,8 +290,10 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
//------------------------------------------------------ Static method end
//------------------------------------------------------ Constructor method start
/**
* 构造
*
* @param file 文件
* @param events 监听的事件列表
*/
@@ -257,6 +303,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 构造
*
* @param path 字符串路径
* @param events 监听的事件列表
*/
@@ -266,6 +313,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 构造
*
* @param path 字符串路径
* @param events 监听事件列表
*/
@@ -307,6 +355,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
public void init ( ) throws WatchException {
//获取目录或文件路径
if ( false = = Files . exists ( this . path , LinkOption . NOFOLLOW_LINKS ) ) {
// 不存在的路径
final Path lastPathEle = FileUtil . getLastPathEle ( this . path ) ;
if ( null ! = lastPathEle ) {
final String lastPathEleStr = lastPathEle . toString ( ) ;
@@ -324,6 +373,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
throw new IORuntimeException ( e ) ;
}
} else if ( Files . isRegularFile ( this . path , LinkOption . NOFOLLOW_LINKS ) ) {
// 文件路径
this . filePath = this . path ;
this . path = this . filePath . getParent ( ) ;
}
@@ -364,6 +414,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 开始监听事件,阻塞当前进程
*
* @param watcher 监听
* @throws WatchException 监听异常,如果监听关闭抛出此异常
*/
@@ -371,38 +422,13 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
if ( isClosed ) {
throw new WatchException ( " Watch Monitor is closed ! " ) ;
}
// 按照层级注册路径及其子路径
registerPath ( ) ;
// log.debug("Start watching path: [{}]", this.path);
while ( false = = isClosed ) {
WatchKey wk ;
try {
wk = watchService . take ( ) ;
} catch ( InterruptedException | ClosedWatchServiceException e ) {
// log.warn(e);
return ;
}
final Path currentPath = watchKeyPathMap . get ( wk ) ;
WatchEvent . Kind < ? > kind ;
for ( WatchEvent < ? > event : wk . pollEvents ( ) ) {
kind = event . kind ( ) ;
if ( null ! = this . filePath & & false = = this . filePath . endsWith ( event . context ( ) . toString ( ) ) ) {
// log.debug("[{}] is not fit for [{}], pass it.", event.context(), this.filePath.getFileName());
continue ;
}
if ( kind = = StandardWatchEventKinds . ENTRY_CREATE ) {
watcher . onCreate ( event , currentPath ) ;
} else if ( kind = = StandardWatchEventKinds . ENTRY_MODIFY ) {
watcher . onModify ( event , currentPath ) ;
} else if ( kind = = StandardWatchEventKinds . ENTRY_DELETE ) {
watcher . onDelete ( event , currentPath ) ;
} else if ( kind = = StandardWatchEventKinds . OVERFLOW ) {
watcher . onOverflow ( event , currentPath ) ;
}
}
wk . reset ( ) ;
doTakeAndWatch ( watcher ) ;
}
}
@@ -434,6 +460,45 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
}
//------------------------------------------------------ private method start
/**
* 执行事件获取并处理
*
* @param watcher {@link Watcher}
*/
private void doTakeAndWatch ( Watcher watcher ) {
WatchKey wk ;
try {
wk = watchService . take ( ) ;
} catch ( InterruptedException | ClosedWatchServiceException e ) {
// 用户中断
return ;
}
final Path currentPath = watchKeyPathMap . get ( wk ) ;
WatchEvent . Kind < ? > kind ;
for ( WatchEvent < ? > event : wk . pollEvents ( ) ) {
kind = event . kind ( ) ;
// 如果监听文件,检查当前事件是否与所监听文件关联
if ( null ! = this . filePath & & false = = this . filePath . endsWith ( event . context ( ) . toString ( ) ) ) {
// log.debug("[{}] is not fit for [{}], pass it.", event.context(), this.filePath.getFileName());
continue ;
}
if ( kind = = StandardWatchEventKinds . ENTRY_CREATE ) {
watcher . onCreate ( event , currentPath ) ;
} else if ( kind = = StandardWatchEventKinds . ENTRY_MODIFY ) {
watcher . onModify ( event , currentPath ) ;
} else if ( kind = = StandardWatchEventKinds . ENTRY_DELETE ) {
watcher . onDelete ( event , currentPath ) ;
} else if ( kind = = StandardWatchEventKinds . OVERFLOW ) {
watcher . onOverflow ( event , currentPath ) ;
}
}
wk . reset ( ) ;
}
/**
* 注册监听路径
*/
@@ -443,13 +508,13 @@ public class WatchMonitor extends Thread implements Closeable, Serializable{
/**
* 将指定路径加入到监听中
*
* @param path 路径
* @param maxDepth 递归下层目录的最大深度
* @return {@link WatchKey}
*/
private void registerPath ( Path path , int maxDepth ) {
try {
final WatchKey key = path . register ( watchService, ArrayUtil . is Empty( this . events ) ? EVENTS_ALL : this . events ) ;
final WatchKey key = path . register ( this . watchService, ArrayUtil . defaultIf Empty( this . events , EVENTS_ALL ) ) ;
watchKeyPathMap . put ( key , path ) ;
if ( maxDepth > 1 ) {
//遍历所有子目录并加入监听