org.phaidra.apihooks.APIHooksAspect.java Source code

Java tutorial

Introduction

Here is the source code for org.phaidra.apihooks.APIHooksAspect.java

Source

/* The contents of this file are subject to the same license and copyright terms
 * as Fedora Commons (http://fedora-commons.org/).
 */
package org.phaidra.apihooks;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Properties;
import java.util.regex.Pattern;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.fcrepo.common.Constants;
import org.fcrepo.common.PID;
import org.fcrepo.server.Context;
import org.fcrepo.server.Server;
import org.fcrepo.server.errors.GeneralException;
import org.fcrepo.server.errors.ModuleInitializationException;
import org.fcrepo.server.errors.ServerException;
import org.fcrepo.server.errors.ServerInitializationException;
import org.fcrepo.server.management.DefaultManagement;
import org.fcrepo.server.storage.DOManager;
import org.fcrepo.server.storage.DOReader;
import org.fcrepo.server.storage.DOWriter;
import org.fcrepo.server.storage.types.Datastream;
import org.fcrepo.server.storage.types.DatastreamXMLMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Aspect
public class APIHooksAspect {

    private static final Logger logger = LoggerFactory.getLogger(APIHooksAspect.class);

    private static String fedoraHome;

    private APIHooks m_hooks;

    private DOManager m_manager;

    public APIHooksAspect() throws ServerInitializationException, ModuleInitializationException {

        // Read properties file.
        Properties properties = new Properties();
        try {
            properties.load(Thread.currentThread().getContextClassLoader()
                    .getResourceAsStream("META-INF/phaidra-fedora-glue.properties"));
            logger.debug("Properties file loaded:" + properties.toString());
            fedoraHome = properties.getProperty("org.phaidra.fedorahome");
        } catch (IOException e) {
            logger.error("Cannot read properties file, using default values.");
            fedoraHome = "/usr/local/fedora";
        }

        m_hooks = (APIHooks) Server.getInstance(new File(fedoraHome)).getModule("org.phaidra.apihooks.APIHooks");
        if (m_hooks == null) {
            throw new ModuleInitializationException("Can't get hooks module from Server.getModule",
                    "org.phaidra.apihooks.APIHooks");
        }

        m_manager = (DOManager) Server.getInstance(new File(fedoraHome))
                .getModule("org.fcrepo.server.storage.DOManager");

        if (m_manager == null) {
            throw new ModuleInitializationException("Can't get DOManager module from Server.getModule",
                    "org.fcrepo.server.storage.DefaultDOManager");
        }
    }

    private static void logCall(String pid, String datastreamID, int stackTraceIndex) {
        StackTraceElement[] stack = Thread.currentThread().getStackTrace();
        logger.debug("[pid = " + pid + " datastreamID = " + datastreamID + "] "
                + stack[stackTraceIndex].getClassName() + "." + stack[stackTraceIndex].getMethodName()
                + " called from " + stack[stackTraceIndex + 1].getClassName() + "."
                + stack[stackTraceIndex + 1].getMethodName() + "(" + stack[stackTraceIndex + 1].getLineNumber()
                + ")");
    }

    private static void logCall(String pid, String datastreamID) {
        logCall(pid, datastreamID, 4);
    }

    private static void logCall(String pid) {
        logCall(pid, "", 4);
    }

    @Pointcut("execution(void org.fcrepo.server.storage.SimpleDOWriter.addDatastream(..)) && args(datastream, addNewVersion) && !within(org.phaidra.apihooks.APIHooksAspect)")
    public void simpleDOWriterAddDatastream(Datastream datastream, boolean addNewVersion) {
    }

    @Pointcut("execution(* org.fcrepo.server.management.DefaultManagement.addDatastream(..)) "
            + "&& args(context, pid, dsID, altIDs, dsLabel, versionable, MIMEType, formatURI, dsLocation, controlGroup, dsState, checksumType, checksum, logMessage)"
            + "&& !within(org.phaidra.apihooks.APIHooksAspect)")
    public void addDatastream(Context context, String pid, String dsID, String[] altIDs, String dsLabel,
            boolean versionable, String MIMEType, String formatURI, String dsLocation, String controlGroup,
            String dsState, String checksumType, String checksum, String logMessage) {
    }

    /**
     * wormhole 
     */
    @Pointcut("simpleDOWriterAddDatastream(datastream, addNewVersion) && cflow(addDatastream(context, pid, dsID, altIDs, dsLabel, versionable, MIMEType, formatURI, dsLocation, controlGroup, dsState, checksumType, checksum, logMessage))")
    public void addDatastreamHook(Context context, String pid, String dsID, String[] altIDs, String dsLabel,
            boolean versionable, String MIMEType, String formatURI, String dsLocation, String controlGroup,
            String dsState, String checksumType, String checksum, String logMessage, Datastream datastream,
            boolean addNewVersion) {

    }

    @After("addDatastreamHook(context, pid, dsID, altIDs, dsLabel, versionable, MIMEType, formatURI, dsLocation, controlGroup, dsState, checksumType, checksum, logMessage, datastream, addNewVersion)")
    public void addDatastreamHook(Context context, String pid, String dsID, String[] altIDs, String dsLabel,
            boolean versionable, String MIMEType, String formatURI, String dsLocation, String controlGroup,
            String dsState, String checksumType, String checksum, String logMessage, Datastream datastream,
            boolean addNewVersion, JoinPoint thisJoinPoint) throws Throwable {

        logCall(pid, dsID);

        String hcontent = null;
        if (controlGroup.equals("X")) {
            hcontent = new String((((DatastreamXMLMetadata) datastream).xmlContent), "UTF8");
        }

        DOWriter w = (DOWriter) thisJoinPoint.getThis();
        String hv = m_hooks.runHook("addDatastream", w, context, pid,
                new Object[] { datastream.DatastreamID, datastream.DSMIME, hcontent, datastream.DSLabel });

        if (!hv.startsWith("OK"))
            throw new APIHooksException(hv);

    }

    @After("addDatastream(context, pid, dsID, altIDs, dsLabel, versionable, MIMEType, formatURI, dsLocation, controlGroup, dsState, checksumType, checksum, logMessage)")
    public void addDatastreamHookPostCommit(Context context, String pid, String dsID, String[] altIDs,
            String dsLabel, boolean versionable, String MIMEType, String formatURI, String dsLocation,
            String controlGroup, String dsState, String checksumType, String checksum, String logMessage,
            JoinPoint thisJoinPoint) throws Throwable {

        logCall(pid, dsID);

        DOWriter w = null;

        try {

            w = m_manager.getWriter(Server.USE_DEFINITIVE_STORE, context, pid);

            m_hooks.runHook("addDatastream_PostCommit", w, context, pid,
                    new Object[] { dsID, MIMEType, null, dsLabel });

            w.commit("Added a new datastream (addDatastream_PostCommit)");

        } catch (Exception e) {
            logger.info("Caught exception while running addDatastream_PostCommit-Hook: " + e.getMessage());
        } finally {
            // DefaultManagement.finishModification
            m_manager.releaseWriter(w);
        }

    }

    @Pointcut("execution(* org.fcrepo.server.management.DefaultManagement.modifyDatastreamByValue(..)) "
            + "&& args(context, pid, datastreamId, altIDs, dsLabel, mimeType, formatURI, dsContent, checksumType, checksum, logMessage, lastModifiedDate)"
            + "&& !within(org.phaidra.apihooks.APIHooksAspect)")
    public void modifyDatastreamByValue(Context context, String pid, String datastreamId, String[] altIDs,
            String dsLabel, String mimeType, String formatURI, InputStream dsContent, String checksumType,
            String checksum, String logMessage, Date lastModifiedDate) {
    }

    /**
     * wormhole 
     */
    @Pointcut("simpleDOWriterAddDatastream(datastream, addNewVersion) && cflow(modifyDatastreamByValue(context, pid, datastreamId, altIDs, dsLabel, mimeType, formatURI, dsContent, checksumType, checksum, logMessage, lastModifiedDate))")
    public void modifyDatastreamByValueHook(Context context, String pid, String datastreamId, String[] altIDs,
            String dsLabel, String mimeType, String formatURI, InputStream dsContent, String checksumType,
            String checksum, String logMessage, Date lastModifiedDate, Datastream datastream,
            boolean addNewVersion) {

    }

    @After("modifyDatastreamByValueHook(context, pid, datastreamId, altIDs, dsLabel, mimeType, formatURI, dsContent, checksumType, checksum, logMessage, lastModifiedDate, datastream, addNewVersion)")
    public void modifyDatastreamByValueHook(Context context, String pid, String datastreamId, String[] altIDs,
            String dsLabel, String mimeType, String formatURI, InputStream dsContent, String checksumType,
            String checksum, String logMessage, Date lastModifiedDate, Datastream datastream, boolean addNewVersion,
            JoinPoint thisJoinPoint) throws Throwable {

        logCall(pid, datastreamId);

        String hcontent = null;
        if (dsContent != null) {
            try {
                hcontent = new String(((DatastreamXMLMetadata) datastream).xmlContent, "UTF8");
            } catch (UnsupportedEncodingException e) {
                throw new APIHooksException("Error converting content to UTF-8: " + e.toString());
            }
        }

        DOWriter w = (DOWriter) thisJoinPoint.getThis();
        String hv = m_hooks.runHook("modifyDatastreamByValue", w, context, pid,
                new Object[] { datastream.DatastreamID, datastream.DSMIME, hcontent, datastream.DSLabel });

        if (!hv.startsWith("OK"))
            throw new APIHooksException(hv);

    }

    // FIXME: in fedora 3.5 <boolean force> becomes <Date lastModifiedDate>
    @Before("modifyDatastreamByValue(context, pid, datastreamId, altIDs, dsLabel, mimeType, formatURI, dsContent, checksumType, checksum, logMessage, lastModifiedDate)")
    public void modifyDatastreamByValueCheckExists(Context context, String pid, String datastreamId,
            String[] altIDs, String dsLabel, String mimeType, String formatURI, InputStream dsContent,
            String checksumType, String checksum, String logMessage, Date lastModifiedDate, JoinPoint thisJoinPoint)
            throws Throwable {

        logCall(pid, datastreamId);

        // Does this DS exists?
        DOReader r = m_manager.getReader(Server.GLOBAL_CHOICE, context, pid);
        for (String dsId : r.ListDatastreamIDs(null)) {
            if (dsId.equals(datastreamId))
                return;
        }

        // No, so create new..

        try {
            DefaultManagement mngmt = (DefaultManagement) thisJoinPoint.getThis();
            // Upload the file
            String dsLocation = mngmt.putTempStream(context, dsContent);
            // Add
            mngmt.addDatastream(context, pid, datastreamId, altIDs, dsLabel, true, mimeType, formatURI, dsLocation,
                    "X", "A", checksumType, checksum, logMessage);
        } finally {
            // This stream will be used by the original call to modifyDatastreamByValue
            dsContent.reset();
        }
    }

    @Pointcut("execution(void org.fcrepo.server.storage.SimpleDOWriter.commit(..)) && !within(org.phaidra.apihooks.APIHooksAspect)")
    public void simpleDOWriterCommit() {
    }

    @Pointcut("execution(* org.fcrepo.server.management.DefaultManagement.modifyObject(..)) "
            + "&& args(context, pid, state, label, ownerId, logMessage, lastModifiedDate)"
            + "&& !within(org.phaidra.apihooks.APIHooksAspect)")
    public void modifyObject(Context context, String pid, String state, String label, String ownerId,
            String logMessage, Date lastModifiedDate) {
    }

    /**
     * wormhole 
     */
    @Pointcut("simpleDOWriterCommit() && cflow(modifyObject(context, pid, state, label, ownerId, logMessage, lastModifiedDate))")
    public void modifyObjectHook(Context context, String pid, String state, String label, String ownerId,
            String logMessage, Date lastModifiedDate) {

    }

    @Around("modifyObjectHook(context, pid, state, label, ownerId, logMessage, lastModifiedDate)")
    public Object modifyObjectHook(Context context, String pid, String state, String label, String ownerId,
            String logMessage, Date lastModifiedDate, ProceedingJoinPoint thisJoinPoint) throws Throwable {

        logCall(pid);

        String hv = m_hooks.runHook("modifyObject", (DOWriter) thisJoinPoint.getThis(), context, pid,
                new Object[] { state, label, ownerId });
        if (!hv.startsWith("OK"))
            throw new APIHooksException(hv);

        return thisJoinPoint.proceed();
    }

    @Pointcut("execution(* org.fcrepo.server.management.DefaultManagement.modifyDatastreamByReference(..)) "
            + "&& args(context, pid, datastreamId, altIDs, dsLabel, mimeType, formatURI, dsLocation, checksumType, checksum, logMessage, lastModifiedDate)"
            + "&& !within(org.phaidra.apihooks.APIHooksAspect)")
    public void modifyDatastreamByReference(Context context, String pid, String datastreamId, String[] altIDs,
            String dsLabel, String mimeType, String formatURI, String dsLocation, String checksumType,
            String checksum, String logMessage, Date lastModifiedDate) {
    }

    /**
     * wormhole 
     */
    @Pointcut("simpleDOWriterAddDatastream(datastream, addNewVersion) && cflow(modifyDatastreamByReference(context, pid, datastreamId, altIDs, dsLabel, mimeType, formatURI, dsLocation, checksumType, checksum, logMessage, lastModifiedDate))")
    public void modifyDatastreamByReferenceHook(Context context, String pid, String datastreamId, String[] altIDs,
            String dsLabel, String mimeType, String formatURI, String dsLocation, String checksumType,
            String checksum, String logMessage, Date lastModifiedDate, Datastream datastream,
            boolean addNewVersion) {

    }

    @After("modifyDatastreamByReferenceHook(context, pid, datastreamId, altIDs, dsLabel, mimeType, formatURI, dsLocation, checksumType, checksum, logMessage, lastModifiedDate, datastream, addNewVersion)")
    public void modifyDatastreamByReferenceHook(Context context, String pid, String datastreamId, String[] altIDs,
            String dsLabel, String mimeType, String formatURI, String dsLocation, String checksumType,
            String checksum, String logMessage, Date lastModifiedDate, Datastream datastream, boolean addNewVersion,
            JoinPoint thisJoinPoint) throws Throwable {

        logCall(pid, datastreamId);

        String hv = m_hooks.runHook("modifyDatastreamByReference", (DOWriter) thisJoinPoint.getThis(), context, pid,
                new Object[] { datastreamId, datastream.DSMIME });

        if (!hv.startsWith("OK"))
            throw new APIHooksException(hv);

    }

    @Pointcut("execution(boolean org.fcrepo.server.storage.SimpleDOWriter.purgeRelationship(..)) && !within(org.phaidra.apihooks.APIHooksAspect)")
    public void simpleDOWriterPurgeRelationship() {
    }

    @Pointcut("execution(* org.fcrepo.server.management.DefaultManagement.purgeRelationship(..)) "
            + "&& args(context, subject, relationship, object, isLiteral, datatype)"
            + "&& !within(org.phaidra.apihooks.APIHooksAspect)")
    public void purgeRelationship(Context context, String subject, String relationship, String object,
            boolean isLiteral, String datatype) {
    }

    /**
     * wormhole 
     */
    @Pointcut("simpleDOWriterPurgeRelationship() && cflow(purgeRelationship(context, subject, relationship, object, isLiteral, datatype))")
    public void purgeRelationshipHook(Context context, String subject, String relationship, String object,
            boolean isLiteral, String datatype) {

    }

    @After("purgeRelationshipHook(context, subject, relationship, object, isLiteral, datatype)")
    public void purgeRelationshipHook(Context context, String subject, String relationship, String object,
            boolean isLiteral, String datatype, JoinPoint thisJoinPoint) throws Throwable {

        logCall(subject, "");

        String pid = FedoraHelper.getSubjectPID(subject);

        String hv = m_hooks.runHook("purgeRelationship", (DOWriter) thisJoinPoint.getThis(), context, pid,
                new Object[] { relationship, object, isLiteral, datatype });
        if (!hv.startsWith("OK"))
            throw new APIHooksException(hv);

    }

}