测试完成后,我们开始着手架构分析(测试先行)
在这个简单的系统中,我们把模块分成3块
第一:监听者,无非是很多的线程,用来监听各式各样的文件以及要满足各式各样的监听规则
第二:执行者,当监听者要去触发事件时,交给哪个执行者,注意,监听者可以有很多个执行者
第三:容器,它负责维护监听者和执行者,以及它们的生命周期管理
监听者们统一继承一个 CommonListener
package wxy.tool.filewatcher.Listener;
import wxy.tool.filewatcher.FileWatcherNative;
import wxy.tool.filewatcher.Exception.ListenError;
public abstract class CommonListener implements Runnable {
private long handle;
private int filter;
private String path;
private Boolean subtree;
public CommonListener(String path,Boolean subtree,int filter) {
this.path = path;
this.subtree = subtree;
this.filter=filter;
}
abstract protected void whenChange();
public void run() {
try {
handle = FileWatcherNative.FindFirstChangeNotification(
path, subtree, filter);
int returnState;
while(true){
FileWatcherNative.FindNextChangeNotification(handle);
returnState = FileWatcherNative.WaitForSingleObject(
handle, FileWatcherNative.INFINITE);
if(FileWatcherNative.WAIT_OBJECT_0 == returnState)
whenChange();
else
throw new ListenError("监听超时或者被取消");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
import wxy.tool.filewatcher.FileWatcherNative;
import wxy.tool.filewatcher.Exception.ListenError;
public abstract class CommonListener implements Runnable {
private long handle;
private int filter;
private String path;
private Boolean subtree;
public CommonListener(String path,Boolean subtree,int filter) {
this.path = path;
this.subtree = subtree;
this.filter=filter;
}
abstract protected void whenChange();
public void run() {
try {
handle = FileWatcherNative.FindFirstChangeNotification(
path, subtree, filter);
int returnState;
while(true){
FileWatcherNative.FindNextChangeNotification(handle);
returnState = FileWatcherNative.WaitForSingleObject(
handle, FileWatcherNative.INFINITE);
if(FileWatcherNative.WAIT_OBJECT_0 == returnState)
whenChange();
else
throw new ListenError("监听超时或者被取消");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
所以的监听者都必须继承这个父类,它把run里的公共方法抽象出来了
下面我们写2个监听者,第一个可以监听文件的名字改变,第二个可以监听是否有写入数据的行为
package wxy.tool.filewatcher.Listener;
public class ChangeFileNameListener extends CommonListener{
public ChangeFileNameListener(String path,Boolean subtree) {
super(path,subtree,0x00000001);
}
@Override
protected void whenChange() {
System.out.println(this+" want do something");
}
}
public class ChangeFileNameListener extends CommonListener{
public ChangeFileNameListener(String path,Boolean subtree) {
super(path,subtree,0x00000001);
}
@Override
protected void whenChange() {
System.out.println(this+" want do something");
}
}
package wxy.tool.filewatcher.Listener;
import wxy.tool.filewatcher.MainContainer;
public class LastWriteListener extends CommonListener {
private MainContainer container;
public LastWriteListener(String path,Boolean subtree) {
super(path, subtree, 0x00000010);
}
@Override
public void whenChange() {
container.fire(this);
}
public void setContainer(MainContainer container) {
this.container = container;
}
}
import wxy.tool.filewatcher.MainContainer;
public class LastWriteListener extends CommonListener {
private MainContainer container;
public LastWriteListener(String path,Boolean subtree) {
super(path, subtree, 0x00000010);
}
@Override
public void whenChange() {
container.fire(this);
}
public void setContainer(MainContainer container) {
this.container = container;
}
}
接着是Action,这里还是一个雏形
package wxy.tool.filewatcher.Action;
/**
* @author wxy
* 注意要考虑线程同步问题,这里的Action可能会被多个线程一起调用
*/
public interface Action {
public void excute();
}
/**
* @author wxy
* 注意要考虑线程同步问题,这里的Action可能会被多个线程一起调用
*/
public interface Action {
public void excute();
}
package wxy.tool.filewatcher.Action;
public class DefaultAction implements Action {
@Override
public void excute() {
System.out.println("excute default action");
}
}
public class DefaultAction implements Action {
@Override
public void excute() {
System.out.println("excute default action");
}
}
最后是这个容器,同样也只是雏形而已,只是添加监听者和绑定执行者
package wxy.tool.filewatcher;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import wxy.tool.filewatcher.Action.Action;
import wxy.tool.filewatcher.Action.DefaultAction;
import wxy.tool.filewatcher.Exception.NoListenerException;
import wxy.tool.filewatcher.Listener.ChangeFileNameListener;
import wxy.tool.filewatcher.Listener.CommonListener;
import wxy.tool.filewatcher.Listener.LastWriteListener;
public class MainContainer {
private ConcurrentHashMap<CommonListener,Thread> listenersMap =
new ConcurrentHashMap<CommonListener,Thread>();
private ConcurrentHashMap<CommonListener,Collection<Action>> listenerActionMap =
new ConcurrentHashMap<CommonListener,Collection<Action>>();
public void beginWatch(){
if(listenersMap.size()<1){
throw new NoListenerException("没有监听者");
}else{
Collection<Thread> listeners = listenersMap.values();
for(Thread listener : listeners){
listener.setDaemon(true);
listener.start();
}
}
}
public void addListener(CommonListener listener) {
listenersMap.put(listener,new Thread(listener));
bindActions(listener, new Action[]{new DefaultAction()});
}
public void bindActions(CommonListener listener,Action[] actions){
Collection<Action> actionQueue =
new ConcurrentLinkedQueue<Action>(Arrays.asList(actions));
listenerActionMap.put(listener, actionQueue);
}
public void fire(CommonListener listener){
for(Action action : listenerActionMap.get(listener)){
action.excute();
}
}
public static void main(String[] args) throws Exception {
MainContainer container = new MainContainer();
container.addListener(new ChangeFileNameListener("D:/",true));
LastWriteListener listener1 = new LastWriteListener("D:/",true);
listener1.setContainer(container);
container.addListener(listener1);
container.beginWatch();
Thread.sleep(Long.MAX_VALUE);
}
}
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import wxy.tool.filewatcher.Action.Action;
import wxy.tool.filewatcher.Action.DefaultAction;
import wxy.tool.filewatcher.Exception.NoListenerException;
import wxy.tool.filewatcher.Listener.ChangeFileNameListener;
import wxy.tool.filewatcher.Listener.CommonListener;
import wxy.tool.filewatcher.Listener.LastWriteListener;
public class MainContainer {
private ConcurrentHashMap<CommonListener,Thread> listenersMap =
new ConcurrentHashMap<CommonListener,Thread>();
private ConcurrentHashMap<CommonListener,Collection<Action>> listenerActionMap =
new ConcurrentHashMap<CommonListener,Collection<Action>>();
public void beginWatch(){
if(listenersMap.size()<1){
throw new NoListenerException("没有监听者");
}else{
Collection<Thread> listeners = listenersMap.values();
for(Thread listener : listeners){
listener.setDaemon(true);
listener.start();
}
}
}
public void addListener(CommonListener listener) {
listenersMap.put(listener,new Thread(listener));
bindActions(listener, new Action[]{new DefaultAction()});
}
public void bindActions(CommonListener listener,Action[] actions){
Collection<Action> actionQueue =
new ConcurrentLinkedQueue<Action>(Arrays.asList(actions));
listenerActionMap.put(listener, actionQueue);
}
public void fire(CommonListener listener){
for(Action action : listenerActionMap.get(listener)){
action.excute();
}
}
public static void main(String[] args) throws Exception {
MainContainer container = new MainContainer();
container.addListener(new ChangeFileNameListener("D:/",true));
LastWriteListener listener1 = new LastWriteListener("D:/",true);
listener1.setContainer(container);
container.addListener(listener1);
container.beginWatch();
Thread.sleep(Long.MAX_VALUE);
}
}