Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Basic auditing and java driver update

  • Loading branch information...
commit 917c39b361a2b8a90113f93d846b2d8a170945aa 1 parent f7d3dff
Juri Kuehn authored
4 CHANGES.textile
View
@@ -2,6 +2,10 @@ h2. Change Log
Also see the "release notes of underlying morphia library":http://code.google.com/p/morphia/wiki/ReleaseNotes and the GORM-MongoDB "User Guide":http://jkuehn.github.com/gorm-mongodb/
+h3. v0.8.1 - 2012-11-19
+* Added a basic auditing feature. Mongo-Domain classes having the @grails.plugins.mongodb.audit.Audited@ annotation will have a copy of every saved instance persited to a @collectionName@ + "History" collection.
+* Updated MongoDB Java driver to *2.9.3*
+
h3. v0.8.0 - 2012-09-12
* Updated MongoDB Java driver to *2.9.1*
* Added the ability to configure MongoOptions in DataSource.groovy - see quickstart in user guide (thanks to Thomas)
10 MongodbMorphiaGrailsPlugin.groovy
View
@@ -9,6 +9,8 @@ import grails.plugins.mongodb.MongoDomainClassArtefactHandler
import com.google.code.morphia.Morphia
import com.google.code.morphia.Datastore
import com.google.code.morphia.mapping.MappedClass
+import grails.plugins.mongodb.audit.MorphiaAuditEntityInterceptor
+import com.google.code.morphia.AbstractEntityInterceptor
class MongodbMorphiaGrailsPlugin {
@@ -20,7 +22,7 @@ class MongodbMorphiaGrailsPlugin {
def scm = [ url: "https://github.com/jkuehn/gorm-mongodb" ]
// the plugin version
- def version = "0.8.0"
+ def version = "0.8.1"
// the version or versions of Grails the plugin is designed for
def grailsVersion = "1.3.4 > *"
// the other plugins this plugin depends on
@@ -82,6 +84,8 @@ class MongodbMorphiaGrailsPlugin {
grailsApplication = ref("grailsApplication", true)
}
}
+
+ morphiaAuditEntityInterceptor(MorphiaAuditEntityInterceptor)
}
def doWithDynamicMethods = { ApplicationContext ctx ->
@@ -120,6 +124,10 @@ class MongodbMorphiaGrailsPlugin {
}
MongoPluginSupport.enhanceMorphiaQueryClass()
+
+ // add auditing feature
+ def morphiaAuditInterceptor = ctx.getBean('morphiaAuditEntityInterceptor')
+ if (morphiaAuditInterceptor instanceof AbstractEntityInterceptor) morphia.getMapper().addInterceptor(morphiaAuditInterceptor)
}
/**
11 application.properties
View
@@ -1,9 +1,8 @@
#Grails Metadata file
-#Wed Sep 12 21:57:41 CEST 2012
-app.grails.version=2.1.0
+#Thu Sep 13 11:20:14 CEST 2012
+app.grails.version=2.1.1
app.name=mongodb-morphia
app.version=0.8.0
-plugins.hibernate=2.1.0
-plugins.release=1.0.1
-plugins.svn=1.0.2
-plugins.tomcat=2.1.0
+plugins.hibernate=2.1.1
+plugins.release=2.0.4
+plugins.tomcat=2.1.1
BIN  lib/mongo-2.9.1.jar → lib/mongo-2.9.3.jar
View
Binary file not shown
2  plugin.xml
View
@@ -1,4 +1,4 @@
-<plugin name='mongodb-morphia' version='0.8.0' grailsVersion='1.3.4 &gt; *'>
+<plugin name='mongodb-morphia' version='0.8.1' grailsVersion='1.3.4 &gt; *'>
<author>Juri Kuehn</author>
<authorEmail>juri.kuehn at gmail.com</authorEmail>
<title>Alternative MongoDB GORM based on the Morphia library</title>
15 src/groovy/grails/plugins/mongodb/audit/Audited.java
View
@@ -0,0 +1,15 @@
+package grails.plugins.mongodb.audit;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Put this above domain classes that should be audited after save
+ * Copies of every saved state go to collectionName + "History"
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface Audited {
+}
22 src/groovy/grails/plugins/mongodb/audit/MongodbAuditProcessor.java
View
@@ -0,0 +1,22 @@
+package grails.plugins.mongodb.audit;
+
+import com.google.code.morphia.mapping.Mapper;
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBObject;
+
+/**
+ * Processor for history entries from auditing.
+ */
+public interface MongodbAuditProcessor {
+
+ /**
+ * Manipulate the historyEntry (like adding add editing user information) before it gets saved to the history collection
+ * @param historyEntry
+ * @param entity
+ * @param serializedEntity
+ * @param mapper
+ * @return false if this entry should not be saved to history collection
+ */
+ public boolean processHistoryEntry(BasicDBObject historyEntry, Object entity, DBObject serializedEntity, Mapper mapper);
+
+}
73 src/groovy/grails/plugins/mongodb/audit/MorphiaAuditEntityInterceptor.java
View
@@ -0,0 +1,73 @@
+package grails.plugins.mongodb.audit;
+
+import com.google.code.morphia.AbstractEntityInterceptor;
+import com.google.code.morphia.mapping.MappedClass;
+import com.google.code.morphia.mapping.Mapper;
+import com.mongodb.BasicDBObject;
+import com.mongodb.DB;
+import com.mongodb.DBObject;
+import grails.plugins.mongodb.MongoDomainClassArtefactHandler;
+import grails.plugins.mongodb.MongoHolderBean;
+import org.codehaus.groovy.grails.commons.GrailsApplication;
+import org.codehaus.groovy.grails.commons.GrailsClass;
+import org.codehaus.groovy.grails.commons.GrailsDomainClass;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * After each save, also save the entry to a history collection
+ */
+public class MorphiaAuditEntityInterceptor extends AbstractEntityInterceptor implements InitializingBean {
+
+ @Autowired private MongoHolderBean mongo;
+ @Autowired private GrailsApplication grailsApplication;
+
+ private DB db;
+ private MongodbAuditProcessor auditProcessor = null;
+ private Map<Class, String> watchedClasses = new HashMap<Class, String>();
+
+ @Override
+ public void postPersist(Object ent, DBObject dbObj, Mapper mapr) {
+ if (ent == null || dbObj == null) return; // nothing to do for incomplete requests
+ String historyCollectionName = watchedClasses.get(ent.getClass());
+ if (historyCollectionName != null) {
+ // persist this entity to the history collection
+ db.getCollection(ent.getClass().getSimpleName() + "History").save(new BasicDBObject("date", new Date()).append("entity", dbObj));
+ }
+ }
+
+ /**
+ * Add class to watched classes for auditing
+ * Not thread safe. Call this method once during app initialization
+ * @param auditClass
+ */
+ public void auditClass(Class auditClass) {
+ MappedClass mappedClass = mongo.getMorphia().getMapper().getMappedClass(auditClass);
+ if (mappedClass != null) {
+ watchedClasses.put(auditClass, mappedClass.getCollectionName() + "History");
+ }
+ }
+
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ db = mongo.getDb();
+
+ /**
+ * add auditing features to given entities. after save of given entities, put the entity into according history collection too
+ *
+ * entities that should have history entires should be annotated with {@link Audited}
+ */
+ for (GrailsClass domainClass : grailsApplication.getArtefacts(MongoDomainClassArtefactHandler.TYPE)) {
+ if (domainClass instanceof GrailsDomainClass && domainClass.getClazz().getAnnotation(Audited.class) != null) auditClass(domainClass.getClazz());
+ }
+
+ // init audit processor
+ Object mongodbAuditProcessor = grailsApplication.getMainContext().getBean("mongodbAuditProcessor");
+ if (mongodbAuditProcessor instanceof MongodbAuditProcessor) this.auditProcessor = (MongodbAuditProcessor)mongodbAuditProcessor;
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.