Ace:Expanding the Audit Manager
From Adapt
Overview
The Audit Manager is designed to be somewhat easy to expand. Storage types are added by extending the StorageAccess class, registering your new driver in the StorageAccessFactory, and lastly creating a configuration page for your storage.
Extend StorageAccess
StorageAccess provides an abstract class that all storage types must implement. Methods to be implemented are listed below.
- void setParameters(Map m)
- Store parameters from the supplied map to configure an instance of your resource.
- String checkParameters(Map m, String path)
- Called to determine if user supplied parameters are valid.
- void remove(EntityManager em)
- String getPage()
- Return the name of a jsp file that is used for configuration.
- AuditIterable<FileBean> getWorkList(String startPath, PathFilter filter)
- InputStream getItemInputStream(String itemPath) throws IOException
Listing files to be audited
The getWorkList method returns an iterator containins file details. The audit thread uses this iterator to supply the list of files in a collection.
public AuditIterable<FileBean> getWorkList(final String startPath, final PathFilter filter) { return new AuditIterable<FileBean>() { @Override public Iterator<FileBean> iterator() { return new MyIterator(startPath, filter); } @Override public void cancel() { } }; } class MyIterator implements Iterator<FileBean> { private FileBean next; private Queue<File> dirsToProcess = new LinkedList<File>(); private Queue<File> filesToProcess = new LinkedList<File>(); private MessageDigest digest; private byte[] buffer = new byte[4096]; private File rootFile; private PathFilter filter; public MyIterator(String startPath, PathFilter filter, String digestAlgorithm) { this.filter = filter; try { digest = MessageDigest.getInstance(digestAlgorithm); rootFile = new File(getCollection().getDirectory()); File startFile; if ( startPath != null ) { startFile = new File( getCollection().getDirectory() + startPath); } else { startFile = rootFile; } if ( startFile.isDirectory() ) { dirsToProcess.add(startFile); } else if ( startFile.isFile() ) { filesToProcess.add(startFile); } loadNext(); } catch ( NoSuchAlgorithmException ex ) { throw new RuntimeException(ex); } } @Override public boolean hasNext() { return next != null; } @Override public FileBean next() { FileBean retValue = next; loadNext(); return retValue; } @Override public void remove() { } private void loadNext() { // see if wee need to process a directory or if there are files in queue while ( filesToProcess.isEmpty() && !dirsToProcess.isEmpty() ) { File directory = dirsToProcess.poll(); LOG.trace("Popping directory: " + directory); for ( File f : directory.listFiles() ) { LOG.trace("Found item " + f); // Determine file type and validate with filter that we should process this object. if ( f.isDirectory() && filter.process(extractPathList(f), true) ) { LOG.trace("Adding matching directory: " + f); dirsToProcess.add(f); } else if ( f.isFile() && filter.process(extractPathList(f), false) ) { LOG.trace("Adding matching file: " + f); filesToProcess.add(f); } } } // now see why we ended loop // we have files if ( !filesToProcess.isEmpty() ) { next = processFile(filesToProcess.poll()); } else { next = null; } } private String[] extractPathList(File file) { int substrLength = rootFile.getPath().length(); // build directory path List<String> dirPathList = new ArrayList<String>(); File currFile = file; while ( !currFile.equals(rootFile) ) { String pathToAdd = currFile.getPath().substring(substrLength); pathToAdd = pathToAdd.replace(File.separatorChar, '/'); dirPathList.add(pathToAdd); currFile = currFile.getParentFile(); } return dirPathList.toArray(new String[dirPathList.size()]); } @SuppressWarnings("empty-statement") private FileBean processFile(File file) { DigestInputStream dis = null; FileBean fb = new FileBean(); fb.setPathList(extractPathList(file)); LOG.trace("Processing file: " + file); digest.reset(); try { dis = new DigestInputStream(new FileInputStream(file), digest); while ( dis.read(buffer) >= 0 ) { ; } byte[] hashValue = digest.digest(); dis.close(); fb.setHash(HashValue.asHexString(hashValue)); } catch ( IOException ie ) { LOG.error("Error reading file: " + file, ie); fb.setError(true); fb.setErrorMessage(Strings.exceptionAsString(ie)); } finally { IO.release(dis); return fb; } } }
Create Configuration Page
Register your resource
In edu.umiacs.ace.monitor.audit.StorageAccessFactory, you will need to add a line in the static block near the top. Add a new line to insert your new driver into the list of available drivers. implementationMap contains a mapping of string (descriptive name) to the implementing class.
static { implementationMap.put("irods", IrodsAccess.class); implementationMap.put("local", LocalFileAccess.class); implementationMap.put("srb", SrbAccess.class); }