openxava / documentation / Access tracking (new in v5.9)

In OpenXava v4.x you can use the old AccessTracking project. Other alternative for auditing is Hibernate Envers.

OpenXava has a mechanism to track any change done by users to the data and also read access. This mechanism is totally configurable and it's disable by default.

Access tracker custom implementation

To track the data access you need an IAccessTrackerProvider (an interface from org.openxava.util). Creating one is easy, just create a class that implement that interface, like the next one:
package org.openxava.util;
 
import java.io.*;
import java.util.*;
 
import org.apache.commons.logging.*;
import org.openxava.application.meta.*;
 
 
public class LogAccessTrackerProvider implements IAccessTrackerProvider {
 
    private static Log log = LogFactory.getLog(LogAccessTrackerProvider.class);
 
    private static String fileName;
 
    public void consulted(String modelName, Map key) {
        log("CONSULTED: user=" + Users.getCurrent() +    ", model=" + modelName + ", key=" + key);
    }
 
 
    public void created(String modelName, Map key) {
           log("CREATED: user=" + Users.getCurrent() +    ", model=" + modelName + ", key=" + key);
    }
 
    public void modified(String modelName, Map key, Map<String, Object> oldChangedValues, Map<String, Object> newChangedValues) {
        StringBuffer changes = new StringBuffer();
        for (String property: oldChangedValues.keySet()) {
            if (changes.length() > 0) changes.append(", ");
            changes.append(Labels.getQualified(property));
            changes.append(": ");
            changes.append(Strings.toString(oldChangedValues.get(property)));
            changes.append(" --> ");
            changes.append(Strings.toString(newChangedValues.get(property)));
        }
        log("MODIFIED: user=" + Users.getCurrent() +    ", model=" + modelName + ", key=" + key + ", changes=" + changes);
    }
 
    public void removed(String modelName, Map key) {
        log("REMOVED: user=" + Users.getCurrent() +    ", model=" + modelName + ", key=" + key);
    }
 
    private static void log(String line) {
        try {
            createFileIfNotExist();
            FileOutputStream f = new FileOutputStream(getFileName(), true);
            PrintStream p = new PrintStream(f);
            p.println(line);
            p.close();
            f.close();
        }
        catch (Exception ex) {
            log.warn(XavaResources.getString("log_tracker_log_failed"), ex);
        }
    }
 
    private static void createFileIfNotExist() throws Exception {
        Files.createFileIfNotExist(getFileName());
    }
 
    private static String getFileName() {
        if (fileName == null) {
            Collection applicationNames = MetaApplications.getApplicationsNames();
            String app = "openxava-app";
            if (!applicationNames.isEmpty()) app = applicationNames.iterator().next().toString().toLowerCase();
            fileName = Files.getOpenXavaBaseDir() + app + "-access.log";
        }
        return fileName;
    }
 
}
This is the simplest possible implementation, just it registers the accesses in a log file. Note that you have to implement four simple methods: consulted(), created(), modified() and removed(). Since v7.2 you have also an executed() method that you can implement optionally, executed() is called each time an action is executed, but excluding CRUD actions and other built-in basic OpenXava actions. You can write your own tracker provider to include more data and to save the accesses in a database table, for example. The above tracker provider, LogTrackerAccessProvider, is included in OpenXava, in the package org.openxava.util, so you can use it "as is" if you don't need more.

Register the tracker provider

In order that your tracker provider works you have to declare it in xava.properties of your project, using the accessTrackerProvidersClasses entry:
accessTrackerProvidersClasses=org.openxava.util.LogAccessTrackerProvider
You can declare several access tracker providers separated by commas.
Now, all changes and read access from the users will add a line in the .openxava/yourapplication-accesss.log file.

Notify your own changes

By default, all the changes done via MapFacade, that includes all creation, consult, modification and deletion (in main entity and collections) from a standard OpenXava module. Moreover, the editors included in OpenXava, such as Discussion, ImagesGallery or Files also notify for changes. However, if you access to data from your own code using JPA or JDBC directly you should notify the access using AccessTracker class from org.openxava.util. For example:
createInvoiceWithJPA(getView().getKeyValues(), getView().getValues()); // Here you saved in your own way
AccessTracking.created("Invoice", getView().getKeyValues()); // YOU HAVE TO ADD THIS LINE