📄 directoryscanner.java
字号:
case DELETE: if (deleteFile(file)) { // Delete succeeded: add DELETE to the set of // actions carried out. taken.add(DELETE); } break; case NOTIFY: if (notifyMatch(file)) { // Notify succeeded: add NOTIFY to the set of // actions carried out. taken.add(NOTIFY); } break; case LOGRESULT: // LOGRESULT was configured - log actions carried out. // => we must execute this action as the last action. // simply set logresult=true for now. We will do // the logging later logresult = true; break; default: LOG.fine("Failed to execute action: " +action + " - action not supported"); break; } } // Now is time for logging: if (logresult) { taken.add(LOGRESULT); if (!logResult(file,taken.toArray(new Action[taken.size()]))) taken.remove(LOGRESULT); // just for the last trace below... } LOG.finest("File processed: "+taken+" - "+file.getAbsolutePath()); } // Deletes a matching file. private boolean deleteFile(File file) { try { // file.delete() is commented so that we don't do anything // bad if the example is mistakenly run on the wrong set of // directories. // /* file.delete(); */ System.out.println("DELETE not implemented for safety reasons."); return true; } catch (Exception x) { LOG.fine("Failed to delete: "+file.getAbsolutePath()); } return false; } // Notifies of a matching file. private boolean notifyMatch(File file) { try { final Notification n = new Notification(FILE_MATCHES_NOTIFICATION,this, getNextSeqNumber(), file.getAbsolutePath()); // This method *is not* called from any synchronized block, so // we can happily call broadcaster.sendNotification() here. // Note that verifying whether a method is called from within // a synchronized block demends a thoroughful code reading, // examining each of the 'parent' methods in turn. // broadcaster.sendNotification(n); return true; } catch (Exception x) { LOG.fine("Failed to notify: "+file.getAbsolutePath()); } return false; } // Logs a result with the ResultLogManager private boolean logResult(File file,Action[] actions) { try { logManager.log(new ResultRecord(config, actions,file)); return true; } catch (Exception x) { LOG.fine("Failed to log: "+file.getAbsolutePath()); } return false; } // Contextual object used to store info about current // (or last) scan. // private static class ScanTask { // List of Files that remain to scan. // When files are discovered they are added to the list. // When they are being handled, they are removed from the list. // When the list is empty, the scanning is finished. // private final LinkedList<File> list; private final DirectoryScanner scan; // Some statistics... // private volatile long scanned=0; private volatile long matching=0; private volatile String info="Not started"; ScanTask(LinkedList<File> list, DirectoryScanner scan) { this.list = list; this.scan = scan; } public void execute() { scan(list); } private void scan(LinkedList<File> list) { scan.scan(this,list); } public String getScanInfo() { return info+" - ["+scanned+" scanned, "+matching+" matching]"; } } // The actual scan logic. Switches state to RUNNING, // and scan the list of given dirs. // The list is a live object which is updated by this method. // This would allow us to implement methods like "pause" and "resume", // since all the info needed to resume would be in the list. // private void scan(ScanTask task, LinkedList<File> list) { setStateAndNotify(RUNNING); task.info = "In Progress"; try { // The FileFilter will tell us which files match and which don't. // final FileFilter filter = config.buildFileFilter(); // We have two condition to end the loop: either the list is // empty, meaning there's nothing more to scan, or the state of // the DirectoryScanner was asynchronously switched to STOPPED by // another thread, e.g. because someone called "stop" on the // ScanManagerMXBean // while (!list.isEmpty() && state == RUNNING) { // Get and remove the first element in the list. // final File current = list.poll(); // Increment number of file scanned. task.scanned++; // If 'current' is a file, it's already been matched by our // file filter (see below): act on it. // Note that for the first iteration of this loop, there will // be one single file in the list: the root directory for this // scanner. // if (current.isFile()) { task.matching++; actOn(current); } // If 'current' is a directory, then // find files and directories that match the file filter // in this directory // if (current.isDirectory()) { // Gets matching files and directories final File[] content = current.listFiles(filter); if (content == null) continue; // Adds all matching file to the list. list.addAll(0,Arrays.asList(content)); } } // The loop terminated. If the list is empty, then we have // completed our task. If not, then somebody must have called // stop() on this directory scanner. // if (list.isEmpty()) { task.info = "Successfully Completed"; setStateAndNotify(COMPLETED); } } catch (Exception x) { // We got an exception: stop the scan // task.info = "Failed: "+x; if (LOG.isLoggable(Level.FINEST)) LOG.log(Level.FINEST,"scan task failed: "+x,x); else if (LOG.isLoggable(Level.FINE)) LOG.log(Level.FINE,"scan task failed: "+x); setStateAndNotify(STOPPED); } catch (Error e) { // We got an Error: // Should not happen unless we ran out of memory or // whatever - don't even try to notify, but // stop the scan anyway! // state=STOPPED; task.info = "Error: "+e; // rethrow error. // throw e; } } /** * MBeanNotification support - delegates to broadcaster. */ public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException { broadcaster.addNotificationListener(listener, filter, handback); } // Switch this object state to the desired value an send // a notification. Don't call this method from within a // synchronized block! // private final void setStateAndNotify(ScanState desired) { final ScanState old = state; if (old == desired) return; state = desired; final AttributeChangeNotification n = new AttributeChangeNotification(this, getNextSeqNumber(),System.currentTimeMillis(), "state change","State",ScanState.class.getName(), String.valueOf(old),String.valueOf(desired)); broadcaster.sendNotification(n); } /** * The {@link DirectoryScannerMXBean} may send two types of * notifications: filematch, and state attribute changed. **/ public MBeanNotificationInfo[] getNotificationInfo() { return new MBeanNotificationInfo[] { new MBeanNotificationInfo( new String[] {FILE_MATCHES_NOTIFICATION}, Notification.class.getName(), "Emitted when a file that matches the scan criteria is found" ), new MBeanNotificationInfo( new String[] {AttributeChangeNotification.ATTRIBUTE_CHANGE}, AttributeChangeNotification.class.getName(), "Emitted when the State attribute changes" ) }; } /** * MBeanNotification support - delegates to broadcaster. */ public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { broadcaster.removeNotificationListener(listener); } /** * MBeanNotification support - delegates to broadcaster. */ public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException { broadcaster.removeNotificationListener(listener, filter, handback); } // Validates the given root directory, returns a File object for // that directory. // Throws IllegalArgumentException if the given root is not // acceptable. // private static File validateRoot(String root) { if (root == null) throw new IllegalArgumentException("no root specified"); if (root.length() == 0) throw new IllegalArgumentException("specified root \"\" is invalid"); final File f = new File(root); if (!f.canRead()) throw new IllegalArgumentException("can't read "+root); if (!f.isDirectory()) throw new IllegalArgumentException("no such directory: "+root); return f; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -