org.opensaas.jaudit.service.spring.AuditExecutor.java Source code

Java tutorial

Introduction

Here is the source code for org.opensaas.jaudit.service.spring.AuditExecutor.java

Source

/**
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE
 * You may obtain a copy of the License at
 *
 *   http://www.gnu.org/licenses/lgpl-3.0.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.opensaas.jaudit.service.spring;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.persistence.Id;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.opensaas.jaudit.AuditSubject;
import org.opensaas.jaudit.LifeCycleAudit;
import org.opensaas.jaudit.service.AuditService;

/**
 * AuditExecutor is used...
 */
public class AuditExecutor {

    private static final Logger LOGGER = Logger.getLogger(AuditExecutor.class.getName());

    private AuditService auditService;

    /**
     * Create an audit record detailing that a particular operation has taken
     * place.
     * 
     * @param jp
     *            The join point currently being fired.
     * @param annotation
     *            The required annotation that triggers this join point.
     * @return The result of executing the method wrapped by this join point.
     * @throws Throwable
     *             When there is an error.
     */
    public Object recordAction(final ProceedingJoinPoint jp, final LifeCycleAudit annotation) throws Throwable {
        LOGGER.log(Level.FINE, "joinpoint={0}, target={2}, args={1}",
                new Object[] { jp.getSignature().toLongString(), Arrays.toString(jp.getArgs()), jp.getTarget() });

        // make the call
        final Object retval = jp.proceed();

        final AuditSubject auditSubject = getAuditSubject(jp, annotation, retval);
        String description = annotation.description();
        if (description == null || description.length() < 1) {
            description = annotation.type().name();
        }
        auditService.createLifeCycleAuditEvent(annotation.type(), auditSubject, description);

        return retval;
    }

    /**
     * Set the auditService to the given value.
     * 
     * @param auditService
     *            the auditService to set
     */
    public final void setAuditService(final AuditService auditService) {
        this.auditService = auditService;
    }

    private AuditSubject getAuditSubject(final JoinPoint jp, final LifeCycleAudit lcAuditAnnotation,
            final Object returnValue) {

        final Object[] args = jp.getArgs();
        if (args == null || args.length < 1) {
            LOGGER.log(Level.WARNING,
                    "JoinPoint has no arguments.  Cannot create a LifeCycle audit event without an argument.  jp={0}",
                    jp);
            return null;
        }

        final Object subject = args[0];
        if (subject == null) {
            LOGGER.log(Level.WARNING,
                    "JoinPoint has a null subject.  Cannot create a LifeCycle audit event without a non-null subject.  jp={0}",
                    jp);
            return null;
        }

        final AuditSubject auditSubject = new AuditSubject();

        if (lcAuditAnnotation.subjectType() != null && !lcAuditAnnotation.subjectType().equals(Void.class)) {
            auditSubject.setSubjectType(lcAuditAnnotation.subjectType().toString());
        } else {
            auditSubject.setSubjectType(subject.getClass().getName());
        }

        final Method[] methods = subject.getClass().getMethods();

        // First, try JPA annotations. In the future, we might try something
        // else.

        Method idMethod = null;

        for (final Method m : methods) {
            final Id annotation = m.getAnnotation(Id.class);
            if (annotation != null) {
                idMethod = m;
                break;
            }
        }
        if (idMethod == null) {
            // try getId() next
            for (final Method m : methods) {
                if ("getId".equalsIgnoreCase(m.getName()) && m.getParameterTypes().length == 0
                        && !m.getReturnType().equals(Void.TYPE)) {
                    idMethod = m;
                }
            }
        }

        if (idMethod == null || idMethod.getParameterTypes().length > 0
                || idMethod.getReturnType().equals(Void.TYPE)) {
            LOGGER.log(Level.WARNING,
                    "Cannot determine an ID method for subject class of type {0}. Will default to hashcode id.",
                    subject.getClass());
            auditSubject.setSubjectId(Integer.toHexString(subject.hashCode()));
            return auditSubject;
        }

        final boolean isAccessible = idMethod.isAccessible();
        if (!isAccessible) {
            idMethod.setAccessible(true);
        }

        try {
            Object id = idMethod.invoke(subject);
            if (id == null && returnValue != null && returnValue.getClass().isAssignableFrom(subject.getClass())) {
                id = idMethod.invoke(returnValue);
            }
            if (id != null) {
                auditSubject.setSubjectId(id.toString());
            } else {
                LOGGER.log(Level.WARNING,
                        "Cannot uniquely identify subject {0} as the id returned by method {1} is null.  Will default to hashcode id.",
                        new Object[] { subject, idMethod });
                auditSubject.setSubjectId(Integer.toHexString(subject.hashCode()));
            }
        } catch (Exception e) {
            LOGGER.log(Level.WARNING,
                    "Cannot execute ID method {0} on subject {1}.  Message={2}  Will default to hashcode id.",
                    new Object[] { idMethod, subject, e.getMessage() });
            LOGGER.log(Level.WARNING, "Cannot execute id method (CONTINUED)", e);
            auditSubject.setSubjectId(Integer.toHexString(subject.hashCode()));
        } finally {
            if (!isAccessible) {
                idMethod.setAccessible(false);
            }
        }

        return auditSubject;
    }
}