Friday, October 11, 2013

I cannot audit with TomEE, so what should I do?

Basic CRUD operations audit, even being an old problem of many apps, is still unresolved by most java frameworks (just as reloadable config files), which gives me the sensation that we, programmers, are sometimes running in circles.

So I've filled a bug for TomEE (probably related to eclipse and OSGI?) because openJPA @Auditable seems not to work on any tomee distribution I can test (1.5.2, 1.5.3, 1.6.0). The sample code you can get at the bug report.

What is the workaround?

Interceptors to the rescue.

First, add this to your src/META-INF/beans.xml

<beans>
  <interceptors>
    <class>AuditInterceptor</class>
  </interceptors>
</beans>


To implement the interceptor, you need an annotation and the interceptor itself

@InterceptorBinding
@Target({TYPE, METHOD})
@Retention(RUNTIME)
public @interface Audit {
}


and


@Interceptor
@Audit
public class AuditInterceptor implements Serializable{

    private static final long serialVersionUID = 6988858067583207506L;
   
    @EJB
    private LogManagerEJB logManagerEJB;

    private JSONSerializer json = new JSONSerializer();

    @AroundInvoke
    public Object logMethodEntry(InvocationContext ctx) throws Exception {
       
        String action = ctx.getMethod().getDeclaringClass()+"."+ctx.getMethod().getName();
        String subject = json.serialize(ctx.getParameters());
        logManagerEJB.saveTelemetryLogs(action, subject);

        return ctx.proceed();
    }
}


and logManagerEJB looks like

    public void saveTelemetryLogs(String action, String subject) {
        TelemetryLog telemetryLog = new TelemetryLog();
        telemetryLog.setAction(action);
        telemetryLog.setActor(JSFUtil.getAuthenticatedUser().getUsername());
        telemetryLog.setSubject(subject);
        telemetryLog.setTs(new Timestamp(System.currentTimeMillis()));
        this.baseService.getTelemetryLogDAO().add(telemetryLog);
    }


DAO is omitted because it's just entity.persist() on the object.

Then you add the @Audit annotation for all methods you want to audit (usually in your business logic layer)

    @Audit
    public void saveUserGroupAccess(UserGroupAccessPK pk) {
        UserGroupAccess uga = new UserGroupAccess();
        uga.setPk(pk);
        this.baseService.getUserGroupAccessDAO().add(uga );       
    }





No comments:

Post a Comment