From 7b268f8924410dce32c24ede5ede6ef4f475f9c0 Mon Sep 17 00:00:00 2001 From: Felix Scheinost Date: Wed, 18 Sep 2019 16:11:22 +0200 Subject: [PATCH 1/4] Use correct (old) plugin syntax in build.gradle --- plugin/build.gradle | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugin/build.gradle b/plugin/build.gradle index 63b32d0c..8bc068f1 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -11,13 +11,10 @@ buildscript { classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.3' classpath 'org.asciidoctor:asciidoctorj-epub3:1.5.0-alpha.6' classpath 'org.asciidoctor:asciidoctorj-pdf:1.5.0-alpha.11' + classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.4' } } -plugins { - id "com.jfrog.bintray" version "1.4" -} - version file("$rootDir/version.txt").text.trim() group "org.grails.plugins" @@ -27,6 +24,7 @@ apply plugin: "org.grails.grails-plugin" apply plugin: "org.grails.grails-plugin-publish" apply plugin: "org.grails.grails-gsp" apply plugin: "org.asciidoctor.convert" +apply plugin: 'com.jfrog.bintray' // Used for publishing to central repository, remove if not needed // apply from: 'https://raw.githubusercontent.com/grails/grails-profile-repository/master/profiles/plugin/templates/grailsCentralPublishing.gradle' From 4c6507d2eeee6b4e7c0b28defe46dc56baec6124 Mon Sep 17 00:00:00 2001 From: Felix Scheinost Date: Wed, 18 Sep 2019 16:16:22 +0200 Subject: [PATCH 2/4] Use project.file instead of $rootDir in build.gradle When including this project in another project as inline plugin $rootDir is the directory of the project that this plugin is included in. Using project.file we always get the correct path --- plugin/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/build.gradle b/plugin/build.gradle index 8bc068f1..36315677 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -15,7 +15,7 @@ buildscript { } } -version file("$rootDir/version.txt").text.trim() +version project.file("../version.txt").text.trim() group "org.grails.plugins" apply plugin: "eclipse" From d7e410a701d9b5ce3c29d5be42a1280d36bf5824 Mon Sep 17 00:00:00 2001 From: Felix Scheinost Date: Thu, 19 Sep 2019 14:43:16 +0200 Subject: [PATCH 3/4] Handle composite ID values (closes #194) GormEntity#ident has a similar if with these two branches: - PersistentEntity#identity is not null => Return value of this PersistentProperty - otherwise use PersistentEntity#compositeIdentity which is a list of properties that make up the composite key The default format of the string returned by getLogEntityId() is supposed to look like a map of the properties that make up the composite ID. For GormEntity only the ident is logged. --- .../grails-app/domain/test/CompositeId.groovy | 19 +++++++++ .../test/NonAuditableCompositeId.groovy | 19 +++++++++ .../grails-app/domain/test/TestEntity.groovy | 20 +++++++++ .../groovy/test/AuditableSpec.groovy | 28 ++++++------- .../plugins/orm/auditable/Auditable.groovy | 41 +++++++++++++++++-- 5 files changed, 107 insertions(+), 20 deletions(-) create mode 100644 examples/audit-test/grails-app/domain/test/CompositeId.groovy create mode 100644 examples/audit-test/grails-app/domain/test/NonAuditableCompositeId.groovy create mode 100644 examples/audit-test/grails-app/domain/test/TestEntity.groovy diff --git a/examples/audit-test/grails-app/domain/test/CompositeId.groovy b/examples/audit-test/grails-app/domain/test/CompositeId.groovy new file mode 100644 index 00000000..a067c614 --- /dev/null +++ b/examples/audit-test/grails-app/domain/test/CompositeId.groovy @@ -0,0 +1,19 @@ +package test + +import grails.plugins.orm.auditable.Auditable + +class CompositeId implements Auditable, Serializable { + + Author author + String string + NonAuditableCompositeId nonAuditableCompositeId + + String notIdString + + static constraints = { + } + + static mapping = { + id composite:['author', 'string', 'nonAuditableCompositeId'] + } +} diff --git a/examples/audit-test/grails-app/domain/test/NonAuditableCompositeId.groovy b/examples/audit-test/grails-app/domain/test/NonAuditableCompositeId.groovy new file mode 100644 index 00000000..6390e1cd --- /dev/null +++ b/examples/audit-test/grails-app/domain/test/NonAuditableCompositeId.groovy @@ -0,0 +1,19 @@ +package test + +class NonAuditableCompositeId implements Serializable { + + String foo + String bar + + @Override + String toString() { + "toString_for_non_auditable_${foo}_${bar}" + } + + static constraints = { + } + + static mapping = { + id composite: ['foo', 'bar'] + } +} diff --git a/examples/audit-test/grails-app/domain/test/TestEntity.groovy b/examples/audit-test/grails-app/domain/test/TestEntity.groovy new file mode 100644 index 00000000..9967cca0 --- /dev/null +++ b/examples/audit-test/grails-app/domain/test/TestEntity.groovy @@ -0,0 +1,20 @@ +package test + +import grails.plugins.orm.auditable.Auditable + +@SuppressWarnings("GroovyUnusedDeclaration") +class TestEntity implements Auditable { + String property + String otherProperty + String anotherProperty + + // Just for testing + Serializable ident() { + "id" + } + + @Override + String toString() { + property + } +} diff --git a/examples/audit-test/src/integration-test/groovy/test/AuditableSpec.groovy b/examples/audit-test/src/integration-test/groovy/test/AuditableSpec.groovy index 156b8c49..ff7dcaa1 100644 --- a/examples/audit-test/src/integration-test/groovy/test/AuditableSpec.groovy +++ b/examples/audit-test/src/integration-test/groovy/test/AuditableSpec.groovy @@ -4,11 +4,9 @@ import grails.core.GrailsApplication import grails.gorm.transactions.Rollback import grails.plugins.orm.auditable.AuditEventType import grails.plugins.orm.auditable.AuditLogContext -import grails.plugins.orm.auditable.Auditable import grails.plugins.orm.auditable.resolvers.AuditRequestResolver import grails.spring.BeanBuilder import grails.testing.mixin.integration.Integration -import org.grails.datastore.gorm.GormEntity import org.springframework.test.annotation.DirtiesContext import spock.lang.Shared import spock.lang.Specification @@ -190,25 +188,23 @@ class AuditableSpec extends Specification { uri == "http://foo.com" actor == "Aaron" } -} - -@SuppressWarnings("GroovyUnusedDeclaration") -class TestEntity implements Auditable, GormEntity { - String property - String otherProperty - String anotherProperty - // Just for testing - Serializable ident() { - "id" - } + void "composite ids are handled correctly"() { + when: + Author author = new Author(name: "Aaron", age: 37, famous: true).save(flush:true) + CompositeId compositeId = new CompositeId( + author: author, + string: "string", + nonAuditableCompositeId: new NonAuditableCompositeId(foo:"foo", bar:"bar") + ) - @Override - String toString() { - property + then: + compositeId.logEntityId == "[author:$author.id, string:string, nonAuditableCompositeId:toString_for_non_auditable_foo_bar]" } } + + class TestAuditRequestResolver implements AuditRequestResolver { @Override String getCurrentActor() { diff --git a/plugin/src/main/groovy/grails/plugins/orm/auditable/Auditable.groovy b/plugin/src/main/groovy/grails/plugins/orm/auditable/Auditable.groovy index 4c2c7d5e..bdeaa62d 100644 --- a/plugin/src/main/groovy/grails/plugins/orm/auditable/Auditable.groovy +++ b/plugin/src/main/groovy/grails/plugins/orm/auditable/Auditable.groovy @@ -4,15 +4,16 @@ import grails.plugins.orm.auditable.resolvers.AuditRequestResolver import grails.util.GrailsNameUtils import grails.util.Holders import groovy.transform.CompileStatic -import groovy.util.logging.Slf4j -import org.slf4j.Logger -import org.slf4j.LoggerFactory import org.grails.datastore.gorm.GormEntity import org.grails.datastore.mapping.dirty.checking.DirtyCheckable import org.grails.datastore.mapping.model.PersistentEntity +import org.grails.datastore.mapping.model.PersistentProperty +import org.slf4j.Logger +import org.slf4j.LoggerFactory import javax.persistence.Transient +import static grails.plugins.orm.auditable.AuditLogListenerUtil.makeMap /** * Domain classes should implement this trait to provide auditing support */ @@ -152,8 +153,40 @@ trait Auditable { String getLogEntityId() { log.debug("getLogEntityId()") if (this instanceof GormEntity) { + PersistentEntity persistentEntity = (PersistentEntity) getClass().invokeMethod("getGormPersistentEntity", null) log.debug(" this instanceof GormEntity") - return convertLoggedPropertyToString("id", ((GormEntity)this).ident()) + if (persistentEntity.identity != null) { + return convertLoggedPropertyToString("id", ((GormEntity)this).ident()) + } + else { + // Fetch composite ID values + PersistentProperty[] idProperties = persistentEntity.compositeIdentity + Map map = makeMap(idProperties*.name, this) + + // Build a string representation of this class that looks like: [:] + StringBuilder stringBuilder = new StringBuilder() + stringBuilder.append("[") + map.eachWithIndex { Map.Entry entry, int i -> + stringBuilder.append(entry.key) + stringBuilder.append(":") + switch (entry.value) { + case Auditable: + stringBuilder.append(((Auditable) entry.value).logEntityId) + break + case GormEntity: + stringBuilder.append(((GormEntity) entry.value).ident().toString()) + break + default: + stringBuilder.append(convertLoggedPropertyToString(entry.key, entry.value)) + break + } + if (i != (map.size() - 1)) { + stringBuilder.append(", ") + } + } + stringBuilder.append("]") + return stringBuilder.toString() + } } if (this.respondsTo("getId")) { log.debug(" this respondsTo getId") From 52484ca84c57b80f0772eaddbdafda4f3847d85e Mon Sep 17 00:00:00 2001 From: Felix Scheinost Date: Thu, 19 Sep 2019 15:03:40 +0200 Subject: [PATCH 4/4] Specify travis distro explicitly for JDK 8 https://travis-ci.community/t/error-installing-oraclejdk8-expected-feature-release-number-in-range-of-9-to-14-but-got-8 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b017442d..cf56a2dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: groovy +dist: trusty sudo: false cache: directories: