*
* Note that if the thread is interrupted for whatever reason during a
* recursive search, the search will stop immediately. Consequently, the
* returned array may be incomplete. You can check the interrupted status
* with the Thread.isInterrupted() method. Alternatively, you can read and
* clear the interrupted status in a single operation using the
* Thread.interrupted() method.
*
* @param filter A file filter. You can pass in a java.io.FileFilter, a
* String (e.g. "*.txt"), or an array of Strings (e.g. String[]{"*.txt", "*.doc"}).
* Wildcard filters are supported. Note that the filter is only applied to
* files, not directories.
*
* @param wait Used to indicate whether to wait for the list to be fully
* populated before returning the response. When traversing very a large
* set of files, it maybe a good idea to process the files as they get added
* to the list. In this case you should set this parameter to false. If this
* parameter is set to false, a null entry will be added to the end of the
* list to indicate that the directory search is complete.
*
* Example:
boolean wait = false;
java.util.List files = directory.getChildren(true, null, wait);
if (wait){
for (int i=0; i
*
*/
public List getChildren(boolean RecursiveSearch, Object filter, boolean wait){
if (this.exists()){
if (RecursiveSearch){
//Create list to store items found in the directory
List items = new LinkedList();
//Create a file filter
FileFilter fileFilter = new FileFilter(filter);
//Spawn threads used to crawl through the file system
long directoryID = Long.valueOf(java.util.Calendar.getInstance().getTimeInMillis() + "" + new Random().nextInt(100000)).longValue();
int numThreads = 20; //<-- this should be set dynamically and self tuning
directorySearchInitialized = true;
DirectorySearch.deleteCache();
DirectorySearch search = new DirectorySearch(fileFilter, items, directoryID, numThreads);
for (int i=0; i files = new java.util.ArrayList();
for (String drive : drives.split("\n")){
drive = drive.trim();
if (drive.length()>0){
String[] arr = drive.split("\t");
files.add(new java.io.File("\\\\" + serverName + "\\" + arr[0]));
}
}
if (files.isEmpty()) return null;
else return files.toArray(new java.io.File[files.size()]);
}
}
catch(Exception e){
doNetView = true;
}
}
else{
doNetView = true;
}
//If we're still here, something went wrong with the JNI. Try using
//net view instead. Note that unlike the JNI, net view won't return
//hidden network drives.
if (doNetView){
javaxt.io.Shell cmd = new javaxt.io.Shell("net view " + serverName);
try{cmd.run();}catch(Exception e){}
java.util.List errors = cmd.getErrors();
errors.remove(null);
if (errors.isEmpty()){
String path = "\\\\" + serverName + "\\";
java.util.List output = cmd.getOutput();
//Remove empty lines from the standard output stream
java.util.List tmp = new java.util.Vector();
java.util.Iterator it = output.iterator();
while (it.hasNext()){
String row = it.next();
if (row==null || row.trim().length()==0){} else tmp.add(row);
}
output = tmp;
tmp = null;
//Parse the standard output stream and create a list of shared directories
java.util.ArrayList files = new java.util.ArrayList();
int x = 0;
int len = -1;
it = output.iterator();
while (it.hasNext()){
String row = it.next();
if (row.startsWith("---")){
String colHeader = (String) output.get(x-1);
if (colHeader.startsWith("Share name") && colHeader.contains("Type")){
len = colHeader.indexOf("Type");
}
}
else{
if (row.startsWith("The command completed successfully.")){
break;
}
if (len>0 && row.length()>len){
String type = row.substring(len);
type = type.substring(0, type.indexOf(" "));
if (type.equalsIgnoreCase("Disk")){
files.add(new java.io.File(path + row.substring(0, len).trim()));
}
}
}
x++;
}
//Convert the list of files into an array
if (files.isEmpty()) return null;
else return files.toArray(new java.io.File[files.size()]);
}
}
}
return null;
}
//**************************************************************************
//** listFiles
//**************************************************************************
/** Used to return a list of files found in this directory. */
protected Object[] listFiles(){
return listFiles(null);
}
//**************************************************************************
//** listFiles
//**************************************************************************
/** Used to return a list of files found in this directory.
*
* @param filter A file filter. You can pass in a java.io.FileFilter, a
* String (e.g. "*.txt"), or an array of Strings (e.g. String[]{"*.txt", "*.doc"}).
* Wildcard filters are supported. Note that the filter is only applied to
* files, not directories.
*
* @return An array of java.io.File or an array of Strings representing
* paths to files. If the input FileFilter is generated using a
* java.io.FileFilter, the method will return an array of java.io.File.
* Otherwise, this method will return an array of Strings for most cases.
* Note that any subdirectories that are found in this directory are ALWAYS
* included in the result, regardless of file filter.
*/
private Object[] listFiles(Object filter){
FileFilter fileFilter;
if (filter instanceof FileFilter) fileFilter = (FileFilter) filter;
else fileFilter = new FileFilter(filter);
String path = this.path + name;
//Get a list of shared drives on a windows server (e.g. "\\192.168.0.80")
if (isWindows && path.startsWith("\\\\")){
if (path.endsWith(PathSeparator)) path = path.substring(0, path.length()-1);
if (!path.substring(2).contains(PathSeparator)){
java.io.File[] sharedDrives = getSharedDrives(path);
if (sharedDrives!=null){
java.util.ArrayList files = new java.util.ArrayList();
for (java.io.File file : sharedDrives){
if (file.exists()){
if (fileFilter==null) {
files.add(file);
}
else{
if (fileFilter.accept(file)){
files.add(file);
}
}
}
}
return files.toArray(new java.io.File[files.size()]);
}
return null;
}
}
//Generate a list of files in this directory that match the file filter
java.util.List files = new java.util.ArrayList();
if (isWindows){
path = getPath();
String[] list = dir();
for (int i=0; i files = new java.util.ArrayList();
try{
String path = this.getPath();
//Execute a ls command to get a directory listing
String[] params = new String[]{"ls", "-ap", path};
javaxt.io.Shell cmd = new javaxt.io.Shell(params);
java.util.List output = cmd.getOutput();
cmd.run(true);
//Parse the output
String line;
while (true){
synchronized (output) {
while (output.isEmpty()) {
output.wait();
}
line = output.remove(0);
}
if (line!=null){
line = line.trim();
if (line.length()>0){
//System.out.println(line);
//boolean isDirectory = (line.endsWith("/"));
if (!line.equals("./") && !line.equals("../")){
files.add(line);
}
}
}
else{
break;
}
}
}
//Catch Exceptions thrown by cmd.run()
catch(java.io.IOException e){
}
catch(InterruptedException e){
Thread.currentThread().interrupt();
}
//Convert the Vector to an Array
String[] arr = new String[files.size()];
for (int i=0; i files = new java.util.ArrayList();
String dir = getPath();
//dir = this.toFile().getCanonicalPath() + PathSeparator;
//Try listing files using the JNI
boolean doDir = false;
if (File.loadDLL()){
try{
String list = File.GetFiles(dir + "*");
if (list!=null){
for (String name : list.split("\n")){
name = name.trim();
if (name.length()>0 && !(name.equals(".\\") || name.equals("..\\")))
files.add(name);
}
}
}
catch(Exception e){
doDir = true;
}
}
else{
doDir = true;
}
//If we're still here, list files using a command prompt
if (doDir)
try{
//Execute a windows shell command to get a directory listing
javaxt.io.Shell cmd = new javaxt.io.Shell("cmd.exe /c dir /OG " + (dir.contains(" ") ? "\"" + dir + "\"" : dir));
java.util.List output = cmd.getOutput();
cmd.run();
//Parse files returned from the directory listing
boolean parseFiles = false;
int colWidth = -1;
String line;
while (true){
synchronized (output) {
while (output.isEmpty()) {
output.wait();
}
line = output.remove(0);
}
if (line!=null){
if (line.length()==0 || line.startsWith(" ")){
if (parseFiles==true) parseFiles = false;
}
else{
if (parseFiles==false) parseFiles = true;
if (parseFiles){
if (colWidth<0){
int offset = 20;
//String date = line.substring(0, 20);
//Get File Type
String type = line.substring(offset);
if (type.trim().startsWith("<")){
offset += type.indexOf(">")+1;
type = type.substring(type.indexOf("<"), type.indexOf(">")+1);
}
else{
type = "";
}
boolean isDirectory = (type.contains(""));
boolean isSymLink = (type.contains(""));
boolean isJunction = (type.contains(""));
//Get File Name
String name = line.substring(offset);
while (name.substring(0, 1).equals(" ")){
name = name.substring(1);
offset++;
}
//Set Column Width
if (isDirectory || isSymLink || isJunction){
colWidth = offset;
}
else{
if (name.contains(" ")){
if (isNumeric(name.substring(0, name.indexOf(" ")))){
colWidth = offset + name.indexOf(" ")+1;
}
else{
colWidth = offset;
}
}
else{
colWidth = offset;
}
}
}
if (colWidth>0){
//String date = line.substring(0,20);
String name = line.substring(colWidth);
String type = line.substring(20, colWidth);
boolean isDirectory = (type.contains(""));
boolean isSymLink = (type.contains(""));
boolean isJunction = (type.contains(""));
if (isDirectory){
if (!name.equals(".") && !name.equals(".."))
files.add(name + this.PathSeparator);
}
else if (isSymLink || isJunction){
java.io.File file = null; //<--Note that we're serializing to a file which is going to slow things down...
if (name.contains("[") && name.contains("]")) {
String link = name.substring(name.indexOf("[")+1, name.indexOf("]"));
name = name.substring(0, name.indexOf("[")).trim();
file = new java.io.File(link);
}
else {
file = new java.io.File(dir, name);
}
if (file.isDirectory()) name += this.PathSeparator;
files.add(name);
}
else{
files.add(name);
}
}
}
}
}
else{
break;
}
}
}
catch(InterruptedException e){
Thread.currentThread().interrupt();
}
catch(RuntimeException e){
}
//Convert the list to an array
return files.toArray(new String[files.size()]);
}
//**************************************************************************
//** isNumeric
//**************************************************************************
/** Used to determine whether a string is a number. This is used in the
* dir() method when parsing output from a Windows "dir" command. This
* method is called to see if a string represents a file size (e.g. 12,345).
* Since the number is meant to represent a file size, an attempt it made
* to convert the string to a long instead of an int or double.
*/
private boolean isNumeric(String str){
try{
if (str.contains(",")) str = str.replace(",", "");
Long.parseLong(str);
return true;
}
catch(Exception e){
return false;
}
}
@Override
//**************************************************************************
//** toString
//**************************************************************************
/** Returns the full path to this directory, including the directory name.
*/
public String toString(){
return getPath();
}
@Override
public int hashCode(){
return getFile().hashCode();
}
//@Override
public int compareTo(Object obj){
if (obj==null) return -1;
else return -obj.toString().compareTo(getPath());
}
@Override
//**************************************************************************
//** equals
//**************************************************************************
/** Returns true if the given Object is a Directory (or java.io.File) that
* refers to the current directory.
*/
public boolean equals(Object obj){
if (obj instanceof Directory){
return getFile().equals(((Directory) obj).toFile());
}
else if (obj instanceof java.io.File){
if (((java.io.File) obj).isDirectory())
return getFile().equals(obj);
else
return false;
}
else{
return false;
}
}
//**************************************************************************
//** clone
//**************************************************************************
/** Creates a copy of this object. */
public Directory clone(){
return new Directory(this.toString());
}
//**************************************************************************
//** getEvents
//**************************************************************************
/** Used to start monitoring changes made to the directory. Changes include
* creating, modifying, or deleting files/folders found in this directory.
* Returns a list of Directory.Event(s). Caller can wait for new events
* using the wait() method like this:
java.util.List events = directory.getEvents();
while (true){
Directory.Event event;
synchronized (events) {
synchronized (events) {
while (events.isEmpty()) {
try {
events.wait();
}
catch (InterruptedException e) {}
}
event = (Directory.Event) events.remove(0);
}
}
if (event!=null){
System.out.println(event.toString());
if (event.getEventID()==event.RENAME){
System.out.println(
event.getOriginalFile() + " vs " +
event.getFile()
);
}
}
}
* Note that in this example, we are removing events from the list in the
* order that they occur. It is critical to remove events from the list to
* as quickly as possible to avoid potential memory issues. Use the stop()
* method to stop monitoring events. Obviously you will need to start the
* monitor in a separate thread in order to call the stop() method. Example:
//Start directory monitor
new Thread(() -> {
java.util.List events = directory.getEvents();
while (true){
...
}
}).start();
//Stop directory monitor
directory.stop();
*/
public List getEvents() throws Exception {
if (FileSystemWatcher==null){
FileSystemWatcher = new FileSystemWatcher(this);
new Thread(FileSystemWatcher).start();
}
return FileSystemWatcher.getEvents();
}
//**************************************************************************
//** Stop
//**************************************************************************
/** Used to stop any worker threads that may be running (recursive search or
* event monitor).
*/
public void stop(){
if (FileSystemWatcher!=null) FileSystemWatcher.stop();
try{
//for (int i=0; i<20; i++)
if (directorySearchInitialized) DirectorySearch.stop();
}
catch(Throwable e){}
}
//**************************************************************************
//** Finalize
//**************************************************************************
/** Method called by Java garbage collector to dispose operating system
* resource.
*/
protected void finalize() throws Throwable {
stop();
super.finalize();
}
//**************************************************************************
//** Event Class
//**************************************************************************
/** Used to encapsulate an event on the file system (e.g. create, update,
* rename, or delete).
*/
public static class Event {
private String file;
private String orgFile;
private java.util.Date date;
private String action;
public static final int DELETE = 0;
public static final int CREATE = 1;
public static final int RENAME = 2;
public static final int MODIFY = 3;
//************************************************************************
//** Constructor
//************************************************************************
/** Creates a new instance of FileSystemEvent by parsing a string
* returned from FileSystemWatcherNative.ReadDirectoryChangesW()
*/
protected Event(String event) {
if (event!=null){
event = event.trim();
if (event.length()==0) event = null;
}
if (event!=null){
try{
//Parse event string
String date = event.substring(1,event.indexOf("]")).trim();
String text = event.substring(event.indexOf("]")+1).trim();
String path = text.substring(text.indexOf(" ")).trim();
String action = text.substring(0,text.indexOf(" ")).trim();
//Set local variables
this.date = parseDate(date);
this.file = path;
this.action = action;
}
catch(Exception ex){
//ex.printStackTrace();
}
}
}
//************************************************************************
//** Constructor
//************************************************************************
/** Creates a new instance of FileSystemEvent for EventMonitor
*/
protected Event(String action, String file){
this.date = new java.util.Date();
this.action = action;
this.file = file;
}
//************************************************************************
//** parseDate
//************************************************************************
private java.util.Date parseDate(String date){
try{
return new java.text.SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy").parse(date);
}
catch(Exception e){
return null;
}
}
//************************************************************************
//** getAction
//************************************************************************
/** Returns a decription of the event (created, modified, deleted, etc.)
*/
public String getAction(){
return action;
}
protected void setAction(String action){
this.action = action;
}
//************************************************************************
//** getFile
//************************************************************************
/** Returns the path of the file or directory that was created, modified,
* or deleted.
*/
public String getFile(){
return file;
}
//************************************************************************
//** getOriginalFile
//************************************************************************
/** If a file or directory was moved or renamed, returns the path to the
* original file or directory.
*/
public String getOriginalFile(){
return orgFile;
}
protected void setOrgFile(String orgFile){
this.orgFile = orgFile;
}
//************************************************************************
//** getEventID
//************************************************************************
public final int getEventID(){
if (action.equalsIgnoreCase("create")) return this.CREATE;
if (action.equalsIgnoreCase("delete")) return this.DELETE;
if (action.equalsIgnoreCase("modify")) return this.MODIFY;
if (action.equalsIgnoreCase("rename")) return this.RENAME;
return -1;
}
//************************************************************************
//** getDate
//************************************************************************
/** Returns the date/time stamp when the event occurred.
*/
public java.util.Date getDate(){
return date;
}
//************************************************************************
//** toString
//************************************************************************
/** Returns a string representation of this event.
*/
public String toString(){
if (action.equalsIgnoreCase("rename"))
return "[" + date.toString() + "] " + action + " " + orgFile + " To " + file;
else
return "[" + date.toString() + "] " + action + " " + file;
}
public boolean equals(Object obj){
//return obj.toString().equalsIgnoreCase(action);
if (obj instanceof Event){
Event event = (Event) obj;
if (event.getFile().equals(this.file) &&
event.getDate().equals(this.date) &&
event.getAction().equals(this.action)){
return true;
}
}
return false;
}
} //End Event Class
//**************************************************************************
//** sort
//**************************************************************************
private void sort(List files, Directory dir){
try{
Collections.sort(files, new FileComparer(dir));
}
catch(Throwable e){
//java.lang.IllegalArgumentException: Comparison method violates its general contract!
}
}
//**************************************************************************
//** FileComparer Class
//**************************************************************************
/** Used to sort a list containing files/folders in alphabetical order.
* Note that directories are listed first.
*/
private class FileComparer implements Comparator {
private int z;
public FileComparer(Directory dir){
if (dir==null) z = 0;
else z = dir.toString().replace("\\", "/").length();
}
public final int compare(Object a, Object b){
String x = a.toString().toUpperCase();
String y = b.toString().toUpperCase();
x = x.replace("\\", "/").substring(z);
y = y.replace("\\", "/").substring(z);
//Check whether a or b is a file in the root directory.
if (!x.contains("/") || !y.contains("/")){
//If both a and b are files, compare file names. Use a multiplier
//to ensure that the file falls toward the end of the list.
if (!x.contains("/") && !y.contains("/")){
return (x.compareTo(y)) * 10000;
}
else{
return 100000;
}
}
else{
//Niether a or b are in the root directory
//Check whether a and b are in the same directory
String dir1 = x.substring(0, x.lastIndexOf("/"));
String dir2 = y.substring(0, y.lastIndexOf("/"));
if (!dir1.equals(dir2)){
return dir1.compareTo(dir2);
}
else{
//a and b are in the same directory
return x.compareTo(y);
}
}
}
} //End FileComparer Class
//******************************************************************************
//** FileFilter
//******************************************************************************
/**
* Used to filter files and file names using regular expressions or java.io
* FileFilters. Note that directories are always returned.
*
******************************************************************************/
private class FileFilter {
private java.io.FileFilter fileFilter = null;
private List regex = null;
public FileFilter(Object filter){
if (filter==null){
filter = "*";
}
if (filter instanceof java.io.FileFilter){
fileFilter = (java.io.FileFilter) filter;
}
if (filter instanceof String){
filter = new String[]{(String) filter};
}
if (filter instanceof String[]){
regex = new ArrayList();
String[] filters = (String[]) filter;
for (int i=0; i
Thread t = new Thread(new DirectorySearch(filter, files));
t.setName("DirectorySearch-"+id);
t.start();
*
* @param filter A file filter. *
* @param items A List (e.g. LinkedList) used to store items found in this
* directory.
*/
public DirectorySearch(FileFilter filter, List items, long directoryID, int numThreads) {
String parentThread = Thread.currentThread().getName();
//System.out.println(parentThread);
if (map==null) {
map = new ConcurrentHashMap();
}
if (getVars()==null){
createVars(filter, items, directoryID, numThreads);
}
if (lut==null) lut = new ConcurrentHashMap();
synchronized(lut){
if (lut.get(parentThread)==null)
lut.put(parentThread, directoryID);
else{
//System.out.println(parentThread + " entering wait state...");
while (!lut.isEmpty()) {
try {
lut.wait();
}
catch (InterruptedException e) {
//If interrupted, return immediately
Thread.currentThread().interrupt();
return;
}
}
//System.out.println(parentThread + " exited wait state!");
createVars(filter, items, directoryID, numThreads);
lut.put(parentThread, directoryID);
lut.notifyAll();
}
}
//System.out.println(parentThread + " " + lut.get(parentThread) + " vs " + directoryID);
}
//**************************************************************************
//** createVars
//**************************************************************************
/** Used to instantiate local variables used by this thread and it's siblings.
* The variables are all stored in a hashmap and accessed via a directoryID.
*/
private static void createVars(FileFilter filter, List items, long directoryID, int numThreads){
synchronized(map){
ConcurrentHashMap vars = new ConcurrentHashMap();
vars.put("items", items);
vars.put("filter", filter);
vars.put("pool", new java.util.LinkedList());
vars.put("path", new java.util.LinkedList());
vars.put("status", new java.util.LinkedList());
vars.put("threads", new LinkedList()); //<--list of active threads
vars.put("activatedThreads", new ConcurrentHashMap());
vars.put("numThreads", numThreads);
map.put(directoryID, vars);
}
}
//**************************************************************************
//** getVars
//**************************************************************************
/** Used to retrieve variables associated with this thread.
*/
private static ConcurrentHashMap getVars(){
String currentThread = Thread.currentThread().getName();
if (currentThread.startsWith("DirectorySearch_")){
Long directoryID = getDirectoryID();
return (ConcurrentHashMap) map.get(directoryID);
}
else{
if (lut==null) return null;
Long directoryID = null;
synchronized(lut){
directoryID = (Long) lut.get(currentThread);
}
//System.out.println(currentThread + " vs " + directoryID);
if (directoryID==null) return null;
else return (ConcurrentHashMap) map.get(directoryID);
}
}
//**************************************************************************
//** deleteCache
//**************************************************************************
public static void deleteCache(){
if (map!=null){
ConcurrentHashMap vars = getVars();
if (vars!=null){
synchronized(vars){
List path = (List) vars.get("path");
List items = (List) vars.get("items");
List status = (List) vars.get("status");
synchronized(path){ path.clear(); }
synchronized(items){ items.clear(); }
synchronized(status){ status.clear(); }
vars.remove("startTime");
vars.remove("root");
}
}
}
}
private static Long getDirectoryID(){
try{
String id = Thread.currentThread().getName();
id = id.substring(id.indexOf("_")+1);
id = id.substring(0,id.indexOf("-"));
//System.out.println(id + " vs " + Thread.currentThread().getName());
return Long.valueOf(id).longValue();
}
catch(Exception e){
return 0L;
}
}
//**************************************************************************
//** Stop
//**************************************************************************
/** Used to stop the current thread. */
public static void stop(){
updatePool(null);
}
//**************************************************************************
//** updatePool
//**************************************************************************
/** Used to add a new directory to the pool. */
public static void updatePool(Directory directory) {
ConcurrentHashMap vars = getVars();
Long startTime = null;
if (vars.get("startTime")!=null) startTime = (Long) vars.get("startTime");
//if start time is null, then this is the first time the pool has been modified
if (startTime==null){
synchronized(vars){
vars.put("startTime", getStartTime());
vars.put("root", directory);
vars.notifyAll();
}
}
boolean updatePool = true;
if (directory == null){
if (Thread.currentThread().getName().equalsIgnoreCase("Finalizer")){
updatePool = false;
}
}
if (updatePool){
List pool = (List) vars.get("pool");
synchronized (pool) {
pool.add(directory);
pool.notifyAll();
}
}
}
//**************************************************************************
//** Add File
//**************************************************************************
/** Used to add a file to the list of items found. */
private static void addFile(File file) {
ConcurrentHashMap vars = getVars();
List items = (List) vars.get("items");
synchronized (items) {
items.add(file);
items.notifyAll();
}
}
//**************************************************************************
//** Add Directory
//**************************************************************************
/** Used to add a directory to the list of items found. */
private static void addDirectory(Directory directory){
ConcurrentHashMap vars = getVars();
List items = (List) vars.get("items");
Directory root = (Directory) vars.get("root");
synchronized (items) {
if (!directory.equals(root)){
items.add(directory);
items.notifyAll();
}
}
}
private static void addPath(Directory directory) {
List path = (List) getVars().get("path");
synchronized (path) {
path.add(directory.toString());
}
}
private static void removePath(Directory directory) {
List path = (List) getVars().get("path");
synchronized (path) {
path.remove(directory.toString());
}
}
//**************************************************************************
//** Get Status
//**************************************************************************
/** Used to retrieve the status object. The status object is a List that
* will remain empty until all of the threads have completed searching
* the file system. While status.isEmpty() call status.wait();
*/
public static List getStatus(){
ConcurrentHashMap vars = getVars();
List status = (List) vars.get("status");
return status;
}
//**************************************************************************
//** Update Status
//**************************************************************************
/** Used to insert an entry into the status object. This is used to notify
* the client that all threads have completed searching the file system.
*/
private static void updateStatus(){
ConcurrentHashMap vars = getVars();
List status = (List) vars.get("status");
List items = (List) vars.get("items");
Long startTime = (Long) vars.get("startTime");
synchronized (status) {
status.add("ellapsedTime = " + getEllapsedTime(startTime) + " ms");
status.notifyAll();
//System.out.println(Thread.currentThread().getName() + " Updated Status!");
}
synchronized (items) {
items.add(null);
items.notifyAll();
}
((List) vars.get("pool")).clear();
((List) vars.get("path")).clear();
((List) vars.get("threads")).clear();
((ConcurrentHashMap) vars.get("activatedThreads")).clear();
//Update the lut
synchronized(lut){
long directoryID = getDirectoryID();
java.util.Iterator it = lut.keySet().iterator();
while (it.hasNext()){
String parentThread = (String) it.next();
if ((Long) lut.get(parentThread) == directoryID){
lut.remove(parentThread);
lut.notifyAll();
break;
}
}
}
}
//**************************************************************************
//** Get Items
//**************************************************************************
/** Used to retrieve a list of files and folders found in this directory.
*/
public static List getItems(){
return (List) getVars().get("items");
}
//**************************************************************************
//** Run
//**************************************************************************
/** Processes entries in the pool. Waits and add children to the array. */
public void run() {
//Get shared variables
ConcurrentHashMap vars = getVars();
if (vars==null) return; //<--This should never happen!
List threads = (List) vars.get("threads");
ConcurrentHashMap activatedThreads = (ConcurrentHashMap) vars.get("activatedThreads");
List path = (List) vars.get("path");
List pool = (List) vars.get("pool");
FileFilter filter = (FileFilter) vars.get("filter");
int numThreads = (Integer) vars.get("numThreads");
String threadID = Thread.currentThread().getName();
while (true) {
Directory dir;
//Wait for new directories to be added to the pool
synchronized (pool) {
while (pool.isEmpty()) {
try {
pool.wait();
}
catch (InterruptedException e) {
//If interrupted, return immediately
Thread.currentThread().interrupt();
return;
}
}
//Update the list of active threads
synchronized (threads){threads.add(threadID);}
synchronized (activatedThreads){
if (activatedThreads.get(threadID)==null){
activatedThreads.put(threadID, true);
}
}
Object obj = pool.get(0);
if (obj==null){
//System.out.println("Terminating Thread: " + threadID);
synchronized (threads){threads.remove(threadID);}
synchronized(activatedThreads){
activatedThreads.replace(threadID, false);
if (activatedThreads.size()==numThreads){
if (!activatedThreads.containsValue(true)){
updateStatus();
}
}
}
return;
}
else{
dir = (Directory) obj;
pool.remove(obj);
pool.notifyAll();
}
}
//Process directory
if (dir!=null) {
//Notify Path/Status Object of new task
addPath(dir);
//Add subdirectories to the processing pool and insert files into file array
Object[] items = dir.listFiles();
if (items!=null){
for (int i=0; i(interval*2)){
//System.out.println((startTime-lastUpdate) + " vs " + (interval));
List orgIndex = index;
List newIndex = createIndex();
for (int i=0; i0){
for (int i=0; i
* Also note that if you change the package or method name of this class, you
* need to use javah to regenerate a C header file and recompile the dll file.
* As far as I know, there is no way around it because of the way JVM binds to
* native dll.
*
*
******************************************************************************/
final class FileSystemWatcherNative {
static {}
public static native long FindFirstChangeNotification(String lpPathName,
boolean bWatchSubtree, int dwNotifyFilter) throws Exception;
public static native void FindNextChangeNotification(long hChangeHandle)
throws Exception;
public static native void FindCloseChangeNotification(long hChangeHandle)
throws Exception;
public static native int WaitForSingleObject(long hHandle, int dwTimeoutMilliseconds);
public static native String ReadDirectoryChangesW();
//**************************************************************************
//** Static Local Variables
//**************************************************************************
/** A constant value representing infinite. */
public static final int INFINITE = 0xFFFFFFFF; //(WinBase.h)
/** A wait return value indicating a failed wait. */
public static final int WAIT_FAILED = 0xFFFFFFFF;
/** A wait return value indicating that the specified object is a mutex object that was not released by the thread. */
public static final int WAIT_ABANDONED = 0x00000080;
/** A wait return value indicating The state of the specified object is signaled. */
public static final int WAIT_OBJECT_0 = 0x00000000;
/** The time-out interval elapsed, and the object's state is nonsignaled. */
public static final int WAIT_TIMEOUT = 0x00000102;
} // End FileSystemWatcherNative