private AuditMode onApplicationAudit(
      AuditMode auditMode,
      AuditState auditInfo,
      String source,
      String description,
      NodeRef key,
      Object... args) {
    AuditMode effectiveAuditMode =
        auditModel.beforeExecution(auditMode, source, description, key, args);
    auditModel.getAuditRecordOptions(source);
    if (auditMode != AuditMode.NONE) {
      if (source.equals(SYSTEM_APPLICATION)) {
        throw new AuditException(
            "Application audit can not use the reserved identifier " + SYSTEM_APPLICATION);
      }

      auditInfo.setAuditApplication(source);
      auditInfo.setAuditConfiguration(auditConfiguration);
      auditInfo.setAuditMethod(null);
      auditInfo.setAuditService(null);
      auditInfo.setClientAddress(null);
      auditInfo.setDate(new Date());
      auditInfo.setFail(false);
      auditInfo.setFiltered(false);
      auditInfo.setHostAddress(auditHost);
      auditInfo.setPath(null);
      if (key != null) {
        auditInfo.setKeyStore(key.getStoreRef());
        auditInfo.setKeyGUID(key.getId());
        RecordOptions recordOptions = auditModel.getAuditRecordOptions(source);
        if (recordOptions != null && recordOptions.getRecordPath() == TrueFalseUnset.TRUE) {
          auditInfo.setPath(getNodePath(key));
        }
      }
      auditInfo.setKeyPropertiesAfter(null);
      auditInfo.setKeyPropertiesBefore(null);
      auditInfo.setMessage(description);
      if (args != null) {
        Serializable[] serArgs = new Serializable[args.length];
        for (int i = 0; i < args.length; i++) {
          if (args[i] == null) {
            serArgs[i] = null;
          } else if (args[i] instanceof Serializable) {
            serArgs[i] = (Serializable) args[i];
          } else {
            serArgs[i] = args[i].toString();
          }
        }
        auditInfo.setMethodArguments(serArgs);
      }
      auditInfo.setReturnObject(null);
      auditInfo.setSessionId(null);
      auditInfo.setThrowable(null);
      auditInfo.setTxId(AlfrescoTransactionSupport.getTransactionId());
      auditInfo.setUserIdentifier(AuthenticationUtil.getFullyAuthenticatedUser());
    }

    return effectiveAuditMode;
  }
  /**
   * Helper method to set audited information after method invocation and to determine if auditing
   * should take place based on the method return value.
   *
   * @param auditMode
   * @param auditInfo
   * @param mi
   * @param returnObject
   * @return - the audit mode.
   */
  private AuditMode postInvocation(
      AuditMode auditMode, AuditState auditInfo, MethodInvocation mi, Object returnObject) {
    if (returnObject == null) {
      auditInfo.setReturnObject(null);
    } else if (returnObject instanceof Serializable) {
      auditInfo.setReturnObject((Serializable) returnObject);
    } else {
      auditInfo.setReturnObject(returnObject.toString());
    }

    Auditable auditable = mi.getMethod().getAnnotation(Auditable.class);
    if (auditable.key() == Auditable.Key.RETURN) {
      if (returnObject != null) {
        if (returnObject instanceof NodeRef) {
          NodeRef key = (NodeRef) returnObject;
          auditInfo.setKeyStore(key.getStoreRef());
          auditInfo.setKeyGUID(key.getId());
          RecordOptions recordOptions = auditModel.getAuditRecordOptions(mi);
          if (recordOptions != null && recordOptions.getRecordPath() == TrueFalseUnset.TRUE) {
            auditInfo.setPath(getNodePath(key));
          }
        } else if (returnObject instanceof StoreRef) {
          auditInfo.setKeyStore((StoreRef) returnObject);
        } else if (returnObject instanceof ChildAssociationRef) {
          ChildAssociationRef car = (ChildAssociationRef) returnObject;
          auditInfo.setKeyStore(car.getChildRef().getStoreRef());
          auditInfo.setKeyGUID(car.getChildRef().getId());
          RecordOptions recordOptions = auditModel.getAuditRecordOptions(mi);
          if (recordOptions != null && recordOptions.getRecordPath() == TrueFalseUnset.TRUE) {
            auditInfo.setPath(nodeService.getPath(car.getChildRef()).toString());
          }
        } else {
          logger.warn(
              "Key argument is not a node, store or child assoc ref for return object on "
                  + publicServiceIdentifier.getPublicServiceName(mi)
                  + "."
                  + mi.getMethod().getName()
                  + " it is "
                  + returnObject.getClass().getName());
        }
      }
    }

    // If the user name is not set, try and set it after the method call.
    // This covers authentication when the user is only known after the call.

    if (auditInfo.getUserIdentifier() == null) {
      auditInfo.setUserIdentifier(AuthenticationUtil.getFullyAuthenticatedUser());
    }

    return auditMode;
  }
 /**
  * Sets the audit volume model
  *
  * @param volume the audit volume
  */
 public void setAuditVolumeModel(double aVolume) {
   if (auditVolumeModel != null) {
     auditVolumeModel.setAuditVolume(aVolume);
   } else {
     auditVolumeModel = new AuditModel(aVolume);
   }
 }
 /**
  * Sets the audit price model
  *
  * @param price the audit price
  */
 public void setAuditPriceModel(BigDecimal aPrice) {
   if (auditPriceModel != null) {
     auditPriceModel.setAuditPrice(aPrice);
   } else {
     auditPriceModel = new AuditModel(aPrice);
   }
 }
  /*
   * (non-Javadoc)
   *
   * @see org.alfresco.repo.audit.AuditComponent#beforeMethodCallManualAudit(org.aopalliance.intercept.MethodInvocation)
   */
  @SuppressWarnings("unchecked")
  public void beforeMethodCallManualAudit(
      Class clazz, Object target, String methodName, Object... args) {
    Class[] argTypes = new Class[args.length];
    for (int i = 0; i < args.length; i++) {
      argTypes[i] = args[i].getClass();
    }
    Method method;
    try {
      method = clazz.getMethod(methodName, argTypes);
    } catch (SecurityException e1) {
      return;
    } catch (NoSuchMethodException e1) {
      return;
    }
    MethodInvocation methodInvocation =
        new ReflectiveMethodInvocation(null, target, method, args, null, null) {};
    if ((auditFlag.get() == null) || (!auditFlag.get().booleanValue())) {
      if (auditModel instanceof AuditEntry
          && ((AuditEntry) auditModel).getEnabled() == TrueFalseUnset.TRUE) {
        boolean auditInternal =
            (auditModel.getAuditInternalServiceMethods(methodInvocation) == TrueFalseUnset.TRUE);
        try {
          String serviceName = publicServiceIdentifier.getPublicServiceName(methodInvocation);

          if (!auditInternal) {
            auditFlag.set(Boolean.TRUE);
          } else {
            if (logger.isDebugEnabled()) {
              logger.debug(
                  "Auditing internal service use for  - " + serviceName + "." + methodName);
            }
          }

          if (method.isAnnotationPresent(Auditable.class)) {

            if (serviceName != null) {
              if (logger.isDebugEnabled()) {
                logger.debug("Auditing - " + serviceName + "." + methodName);
              }
              try {
                auditImpl(methodInvocation, false);
              } catch (Throwable e) {

              }
            } else {
              if (logger.isDebugEnabled()) {
                logger.debug("UnknownService." + methodName);
              }
              try {
                auditImpl(methodInvocation, false);
              } catch (Throwable e) {

              }
            }

          } else if (method.isAnnotationPresent(NotAuditable.class)) {
            if (logger.isDebugEnabled()) {
              logger.debug("Not Audited. " + serviceName + "." + methodName);
            }
          } else {
            if (logger.isDebugEnabled()) {
              logger.debug("Unannotated service method " + serviceName + "." + methodName);
            }
            if (method.getDeclaringClass().isInterface()
                && method.getDeclaringClass().isAnnotationPresent(PublicService.class)) {
              throw new RuntimeException(
                  "Unannotated service method " + serviceName + "." + methodName);
            }
          }
        } finally {
          if (!auditInternal) {
            auditFlag.set(Boolean.FALSE);
          }
        }
      }
    }
  }
  /**
   * Set auditable information and determine if auditing is required before method invocation. This
   * would normally be based on the method arguments.
   *
   * @param auditMode
   * @param auditInfo
   * @param mi
   * @return - the audit mode.
   */
  private AuditMode beforeInvocation(
      AuditMode auditMode, AuditState auditInfo, MethodInvocation mi) {
    AuditMode effectiveAuditMode = auditModel.beforeExecution(auditMode, mi);

    if (auditMode != AuditMode.NONE) {
      String methodName = mi.getMethod().getName();
      String serviceName = publicServiceIdentifier.getPublicServiceName(mi);
      auditInfo.setAuditApplication(SYSTEM_APPLICATION);
      auditInfo.setAuditConfiguration(auditConfiguration);
      auditInfo.setAuditMethod(methodName);
      auditInfo.setAuditService(serviceName);
      auditInfo.setClientAddress(null);
      auditInfo.setDate(new Date());
      auditInfo.setFail(false);
      auditInfo.setFiltered(false);
      auditInfo.setHostAddress(auditHost);

      auditInfo.setPath(null);

      Auditable auditable = mi.getMethod().getAnnotation(Auditable.class);
      Object key = null;
      switch (auditable.key()) {
        case ARG_0:
          checkArgLength(mi, methodName, serviceName, 0);
          key = mi.getArguments()[0];
          break;
        case ARG_1:
          checkArgLength(mi, methodName, serviceName, 1);
          key = mi.getArguments()[1];
          break;
        case ARG_2:
          checkArgLength(mi, methodName, serviceName, 2);
          key = mi.getArguments()[2];
          break;
        case ARG_3:
          checkArgLength(mi, methodName, serviceName, 3);
          key = mi.getArguments()[3];
          break;
        case ARG_4:
          checkArgLength(mi, methodName, serviceName, 4);
          key = mi.getArguments()[4];
          break;
        case ARG_5:
          checkArgLength(mi, methodName, serviceName, 5);
          key = mi.getArguments()[5];
          break;
        case ARG_6:
          checkArgLength(mi, methodName, serviceName, 6);
          key = mi.getArguments()[6];
          break;
        case ARG_7:
          checkArgLength(mi, methodName, serviceName, 7);
          key = mi.getArguments()[7];
          break;
        case ARG_8:
          checkArgLength(mi, methodName, serviceName, 8);
          key = mi.getArguments()[8];
          break;
        case ARG_9:
          checkArgLength(mi, methodName, serviceName, 9);
          key = mi.getArguments()[9];
          break;
        case NO_KEY:
        default:
          break;
      }
      if (key != null) {
        RecordOptions recordOptions = auditModel.getAuditRecordOptions(mi);
        if (key instanceof NodeRef) {
          auditInfo.setKeyStore(((NodeRef) key).getStoreRef());
          auditInfo.setKeyGUID(((NodeRef) key).getId());
          if (recordOptions != null && recordOptions.getRecordPath() == TrueFalseUnset.TRUE) {
            auditInfo.setPath(getNodePath((NodeRef) key));
          }
        } else if (key instanceof StoreRef) {
          auditInfo.setKeyStore((StoreRef) key);
        } else if (key instanceof ChildAssociationRef) {
          ChildAssociationRef car = (ChildAssociationRef) key;
          auditInfo.setKeyStore(car.getParentRef().getStoreRef());
          auditInfo.setKeyGUID(car.getParentRef().getId());
          if (recordOptions != null && recordOptions.getRecordPath() == TrueFalseUnset.TRUE) {
            auditInfo.setPath(getNodePath(car.getParentRef()));
          }
        } else if (key instanceof SearchParameters) {
          SearchParameters sp = (SearchParameters) key;
          if (sp.getStores().size() > 0) {
            auditInfo.setKeyStore(sp.getStores().get(0));
          }
        } else {
          logger.warn(
              "Key argument is not a node, store or child assoc reference or search parameters on "
                  + serviceName
                  + "."
                  + methodName
                  + " it is "
                  + key.getClass().getName());
        }
      }
      auditInfo.setKeyPropertiesAfter(null);
      auditInfo.setKeyPropertiesBefore(null);
      auditInfo.setMessage(null);
      if (mi.getArguments() != null) {
        Serializable[] serArgs = new Serializable[mi.getArguments().length];
        for (int i = 0; i < mi.getArguments().length; i++) {
          if ((auditable.recordable() == null)
              || (auditable.recordable().length <= i)
              || auditable.recordable()[i]) {
            if (mi.getArguments()[i] == null) {
              serArgs[i] = null;
            } else if (mi.getArguments()[i] instanceof Serializable) {
              serArgs[i] = (Serializable) mi.getArguments()[i];
            } else {
              serArgs[i] = mi.getArguments()[i].toString();
            }
          } else {
            serArgs[i] = "********";
          }
        }
        auditInfo.setMethodArguments(serArgs);
      }
      auditInfo.setReturnObject(null);
      auditInfo.setSessionId(null);
      auditInfo.setThrowable(null);
      auditInfo.setTxId(AlfrescoTransactionSupport.getTransactionId());
      auditInfo.setUserIdentifier(AuthenticationUtil.getFullyAuthenticatedUser());
    }

    return effectiveAuditMode;
  }
  public Object audit(MethodInvocation mi) throws Throwable {
    if ((auditFlag.get() == null) || (!auditFlag.get().booleanValue())) {
      if (auditModel instanceof AuditEntry
          && ((AuditEntry) auditModel).getEnabled() == TrueFalseUnset.TRUE) {
        boolean auditInternal =
            (auditModel.getAuditInternalServiceMethods(mi) == TrueFalseUnset.TRUE);
        try {
          Method method = mi.getMethod();
          String methodName = method.getName();
          String serviceName = publicServiceIdentifier.getPublicServiceName(mi);

          if (!auditInternal) {
            auditFlag.set(Boolean.TRUE);
          } else {
            if (logger.isDebugEnabled()) {
              logger.debug(
                  "Auditing internal service use for  - " + serviceName + "." + methodName);
            }
          }

          if (method.isAnnotationPresent(Auditable.class)) {

            if (serviceName != null) {
              if (logger.isDebugEnabled()) {
                logger.debug("Auditing - " + serviceName + "." + methodName);
              }
              return auditImpl(mi, true);
            } else {
              if (logger.isDebugEnabled()) {
                logger.debug("UnknownService." + methodName);
              }
              return auditImpl(mi, true);
            }

          } else if (method.isAnnotationPresent(NotAuditable.class)) {
            if (logger.isDebugEnabled()) {
              logger.debug("Not Audited. " + serviceName + "." + methodName);
            }
            return mi.proceed();
          } else {
            if (logger.isDebugEnabled()) {
              logger.debug("Unannotated service method " + serviceName + "." + methodName);
            }
            if (method.getDeclaringClass().isInterface()
                && method.getDeclaringClass().isAnnotationPresent(PublicService.class)) {
              throw new RuntimeException(
                  "Unannotated service method " + serviceName + "." + methodName);
            } else {
              return mi.proceed();
            }
          }
        } finally {
          if (!auditInternal) {
            auditFlag.set(Boolean.FALSE);
          }
        }
      } else {
        return mi.proceed();
      }
    } else {
      return mi.proceed();
    }
  }