1 40 41 package com.sun.jmx.examples.scandir; 42 43 import static com.sun.jmx.examples.scandir.ScanManager.getNextSeqNumber; 44 import com.sun.jmx.examples.scandir.ScanManagerMXBean.ScanState; 45 import static com.sun.jmx.examples.scandir.ScanManagerMXBean.ScanState.*; 46 import static com.sun.jmx.examples.scandir.config.DirectoryScannerConfig.Action.*; 47 import com.sun.jmx.examples.scandir.config.XmlConfigUtils; 48 import com.sun.jmx.examples.scandir.config.DirectoryScannerConfig; 49 import com.sun.jmx.examples.scandir.config.DirectoryScannerConfig.Action; 50 import com.sun.jmx.examples.scandir.config.ResultRecord; 51 import java.io.File ; 52 import java.io.FileFilter ; 53 import java.io.IOException ; 54 import java.util.Arrays ; 55 import java.util.Collections ; 56 import java.util.EnumSet ; 57 import java.util.HashSet ; 58 import java.util.LinkedList ; 59 import java.util.Set ; 60 import java.util.logging.Level ; 61 import java.util.logging.Logger ; 62 import javax.management.AttributeChangeNotification ; 63 import javax.management.InstanceNotFoundException ; 64 import javax.management.ListenerNotFoundException ; 65 import javax.management.MBeanNotificationInfo ; 66 import javax.management.Notification ; 67 import javax.management.NotificationBroadcasterSupport ; 68 import javax.management.NotificationEmitter ; 69 import javax.management.NotificationFilter ; 70 import javax.management.NotificationListener ; 71 72 105 public class DirectoryScanner implements 106 DirectoryScannerMXBean, NotificationEmitter { 107 108 115 public static final String FILE_MATCHES_NOTIFICATION = 116 "com.sun.jmx.examples.scandir.filematch"; 117 118 121 private static final Logger LOG = 122 Logger.getLogger(DirectoryScanner.class.getName()); 123 124 private volatile ScanState state = STOPPED; 127 128 private final NotificationBroadcasterSupport broadcaster; 133 134 private final File rootFile; 138 139 private final DirectoryScannerConfig config; 143 144 final Set <Action> actions; 148 149 final ResultLogManager logManager; 156 157 178 public DirectoryScanner(DirectoryScannerConfig config, 179 ResultLogManager logManager) 180 throws IllegalArgumentException { 181 if (logManager == null) 182 throw new IllegalArgumentException ("log=null"); 183 if (config == null) 184 throw new IllegalArgumentException ("config=null"); 185 if (config.getName() == null) 186 throw new IllegalArgumentException ("config.name=null"); 187 188 broadcaster = new NotificationBroadcasterSupport (); 189 190 this.config = XmlConfigUtils.xmlClone(config); 193 194 rootFile = validateRoot(config.getRootDirectory()); 198 199 if (config.getActions() == null) 203 actions = Collections.emptySet(); 204 else 205 actions = EnumSet.copyOf(Arrays.asList(config.getActions())); 206 this.logManager = logManager; 207 } 208 209 public void stop() { 211 setStateAndNotify(STOPPED); 213 } 214 215 public String getRootDirectory() { 217 return rootFile.getAbsolutePath(); 218 } 219 220 221 public ScanState getState() { 223 return state; 224 } 225 226 public DirectoryScannerConfig getConfiguration() { 228 return config; 229 } 230 231 public String getCurrentScanInfo() { 233 final ScanTask currentOrLastTask = currentTask; 234 if (currentOrLastTask == null) return "Never Run"; 235 return currentOrLastTask.getScanInfo(); 236 } 237 238 private volatile ScanTask currentTask = null; 241 242 public void scan() { 244 final ScanTask task; 245 246 synchronized (this) { 247 final LinkedList <File > list; 248 switch (state) { 249 case RUNNING: 250 case SCHEDULED: 251 throw new IllegalStateException (state.toString()); 252 case STOPPED: 253 case COMPLETED: 254 list = new LinkedList <File >(); 256 list.add(rootFile); 257 break; 258 default: 259 throw new IllegalStateException (String.valueOf(state)); 260 } 261 262 currentTask = task = new ScanTask(list,this); 265 266 setStateAndNotify(SCHEDULED); 278 } 279 task.execute(); 280 } 281 282 void actOn(File file) { 288 289 final Set <Action> taken = new HashSet <Action>(); 292 boolean logresult = false; 293 294 for (Action action : actions) { 297 switch (action) { 298 case DELETE: 299 if (deleteFile(file)) { 300 taken.add(DELETE); 303 } 304 break; 305 case NOTIFY: 306 if (notifyMatch(file)) { 307 taken.add(NOTIFY); 310 } 311 break; 312 case LOGRESULT: 313 logresult = true; 318 break; 319 default: 320 LOG.fine("Failed to execute action: " +action + 321 " - action not supported"); 322 break; 323 } 324 } 325 326 if (logresult) { 328 taken.add(LOGRESULT); 329 if (!logResult(file,taken.toArray(new Action[taken.size()]))) 330 taken.remove(LOGRESULT); } 332 333 LOG.finest("File processed: "+taken+" - "+file.getAbsolutePath()); 334 } 335 336 private boolean deleteFile(File file) { 338 try { 339 344 System.out.println("DELETE not implemented for safety reasons."); 345 return true; 346 } catch (Exception x) { 347 LOG.fine("Failed to delete: "+file.getAbsolutePath()); 348 } 349 return false; 350 } 351 352 private boolean notifyMatch(File file) { 354 try { 355 final Notification n = 356 new Notification (FILE_MATCHES_NOTIFICATION,this, 357 getNextSeqNumber(), 358 file.getAbsolutePath()); 359 360 broadcaster.sendNotification(n); 367 return true; 368 } catch (Exception x) { 369 LOG.fine("Failed to notify: "+file.getAbsolutePath()); 370 } 371 return false; 372 } 373 374 private boolean logResult(File file,Action[] actions) { 376 try { 377 logManager.log(new ResultRecord(config, actions,file)); 378 return true; 379 } catch (Exception x) { 380 LOG.fine("Failed to log: "+file.getAbsolutePath()); 381 } 382 return false; 383 } 384 385 386 private static class ScanTask { 390 391 private final LinkedList <File > list; 397 private final DirectoryScanner scan; 398 399 private volatile long scanned=0; 402 private volatile long matching=0; 403 404 private volatile String info="Not started"; 405 406 ScanTask(LinkedList <File > list, DirectoryScanner scan) { 407 this.list = list; this.scan = scan; 408 } 409 410 public void execute() { 411 scan(list); 412 } 413 414 private void scan(LinkedList <File > list) { 415 scan.scan(this,list); 416 } 417 418 public String getScanInfo() { 419 return info+" - ["+scanned+" scanned, "+matching+" matching]"; 420 } 421 } 422 423 private void scan(ScanTask task, LinkedList <File > list) { 430 setStateAndNotify(RUNNING); 431 task.info = "In Progress"; 432 try { 433 434 final FileFilter filter = config.buildFileFilter(); 437 438 while (!list.isEmpty() && state == RUNNING) { 445 446 final File current = list.poll(); 449 450 task.scanned++; 452 453 if (current.isFile()) { 460 task.matching++; 461 actOn(current); 462 } 463 464 if (current.isDirectory()) { 469 470 final File [] content = current.listFiles(filter); 472 if (content == null) continue; 473 474 list.addAll(0,Arrays.asList(content)); 476 } 477 } 478 479 if (list.isEmpty()) { 484 task.info = "Successfully Completed"; 485 setStateAndNotify(COMPLETED); 486 } 487 } catch (Exception x) { 488 task.info = "Failed: "+x; 491 if (LOG.isLoggable(Level.FINEST)) 492 LOG.log(Level.FINEST,"scan task failed: "+x,x); 493 else if (LOG.isLoggable(Level.FINE)) 494 LOG.log(Level.FINE,"scan task failed: "+x); 495 setStateAndNotify(STOPPED); 496 } catch (Error e) { 497 state=STOPPED; 503 task.info = "Error: "+e; 504 505 throw e; 508 } 509 } 510 511 514 public void addNotificationListener(NotificationListener listener, 515 NotificationFilter filter, Object handback) 516 throws IllegalArgumentException { 517 broadcaster.addNotificationListener(listener, filter, handback); 518 } 519 520 private final void setStateAndNotify(ScanState desired) { 525 final ScanState old = state; 526 if (old == desired) return; 527 state = desired; 528 final AttributeChangeNotification n = 529 new AttributeChangeNotification (this, 530 getNextSeqNumber(),System.currentTimeMillis(), 531 "state change","State",ScanState.class.getName(), 532 String.valueOf(old),String.valueOf(desired)); 533 broadcaster.sendNotification(n); 534 } 535 536 537 541 public MBeanNotificationInfo [] getNotificationInfo() { 542 return new MBeanNotificationInfo [] { 543 new MBeanNotificationInfo ( 544 new String [] {FILE_MATCHES_NOTIFICATION}, 545 Notification .class.getName(), 546 "Emitted when a file that matches the scan criteria is found" 547 ), 548 new MBeanNotificationInfo ( 549 new String [] {AttributeChangeNotification.ATTRIBUTE_CHANGE}, 550 AttributeChangeNotification .class.getName(), 551 "Emitted when the State attribute changes" 552 ) 553 }; 554 } 555 556 559 public void removeNotificationListener(NotificationListener listener) 560 throws ListenerNotFoundException { 561 broadcaster.removeNotificationListener(listener); 562 } 563 564 567 public void removeNotificationListener(NotificationListener listener, 568 NotificationFilter filter, Object handback) 569 throws ListenerNotFoundException { 570 broadcaster.removeNotificationListener(listener, filter, handback); 571 } 572 573 private static File validateRoot(String root) { 579 if (root == null) 580 throw new IllegalArgumentException ("no root specified"); 581 if (root.length() == 0) 582 throw new IllegalArgumentException ("specified root \"\" is invalid"); 583 final File f = new File (root); 584 if (!f.canRead()) 585 throw new IllegalArgumentException ("can't read "+root); 586 if (!f.isDirectory()) 587 throw new IllegalArgumentException ("no such directory: "+root); 588 return f; 589 } 590 591 } 592 593 594 | Popular Tags |