Personal tools

Ace:Expanding the Audit Manager

From Adapt

Jump to: navigation, search

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);
    }