Showing posts with label grails. Show all posts
Showing posts with label grails. Show all posts

Saturday, March 11, 2017

Auditing data with the Acegi plugin and Grails upgrade pain

Auditing data with the Acegi plugin and Grails upgrade pain


Im in the middle of trying to upgrade our app (again). Were running on Grails 1.1 now and Im attempting to get us to 1.1.1 and from there to 1.2-M1. As Marc Palmer points out the more people using it the more likely it is that 1.2 final will be rock solid.

The problem thats biting us right now is GRAILS-4453 (or, more accurately, HHH-2763). Were using Grails Hibernate events support to track the user that created and last updated assets in our system. This isnt just us being anal, the site editors frequently search the data using those criteria so its an essential feature.

In Grails 1.1 this is simplicity itself. The following code goes in the domain class and thats all there is to it:

 User createdBy
User updatedBy

def authenticateService

def beforeInsert = {
createdBy = authenticateService.userDomain()
}

def beforeUpdate = {
updatedBy = authenticateService.userDomain()
}

Yes, it is quite exciting that youre able to inject a service into a domain class instance. GORM only maps explicitly typed properties to the database so anything declared using def is effectively transient.

Unfortunately Grails 1.1.1 includes a newer version of Hibernate that introduces a particularly horrible problem. When saving any update to our domain object now were faced with the error: collection [User.authorities] was not processed by flush(). The problem appears to be that the User instance attached to createdBy cannot be flushed when the beforeUpdate closure executes because it has a lazy-loaded collection of authorities. Even declaring the authorities collection as lazy: false doesnt help as the relationship is a bi-directional many-to-many - each Authority also has a collection of all the Users who have been granted that role. Given that for the purposes of displaying data to the audience of our site this audit data doesnt matter a damn I really dont want to be eager fetching it. Also, given the nature of the User-Authority relationship, casual eager fetching could result in rather a lot of data being loaded in to memory (the User, his roles, all the other users with that role, all their roles...)

Our options seem to be:

  1. Explicitly eager fetch the User data in places where the owning object will get updated. Since the domain class in question is the root of a heirarchy of 13 sub-classes (things this project has taught me #63: never do this) and varieties get updated by a service or two, at least one controller and one Quartz and several hundred Selenium test fixtures, its going to be a massive PITA and just as bad to remove if/when HHH-2763 ever gets fixed.
  2. Break referential integrity and store username or id rather than an actual domain object relationship. This feels horribly wrong and is likely to cause problems down the line.
  3. Store the created/updated information as a domain object of its own. This would make the query to find data by who created or updated it more complex (although not impossibly so) and might actually be prone to the same original bug

I dont know if anyone might have come across this problem and has some kind of workaround (preferably one that isnt an evil hack). Id really appreciate any pointers.

Update: This is fixed in Grails 1.2-M2


Available link for download

Read more »

Thursday, February 16, 2017

Auto generate Spock specs for Grails artifacts

Auto generate Spock specs for Grails artifacts


When creating artifacts such as domain classes, controllers and tag libs Grails generates a JUnit test case. If, like me, youre digging writing specifications with Spock youd probably rather have Grails generate one of those. The last thing I want is to manually transform every generated test case into a specification for every artifact I create.

Its very simple to create a CreateUnitSpec or CreateIntegrationSpec script with a template specification. Hooking in to the other types of artifact creation turned out to be fiddlier. Each create-* command calls a Closure called createUnitTest. Reassigning that Closure should be the solution. The trick is in figuring out where that can be done.

Any time one of its Gant targets is invoked the Grails build system fires an event. You can respond to those events by declaring a closure called event<target name>Start in scripts/_Events.groovy. The only Gant target directly invoked when an artifact is created is called default. It is possible to intercept that although that means the event handler will be invoked any time any Gant target called default runs. For this purpose thats no problem since were just overriding a closure in the build binding.

The other factor is that the superclass for the unit test is specified by the individual create-* scripts (or defaulted to GrailsUnitTestCase). Rather than having to override those scripts as well, Ive just mapped the non-standard unit test superclasses to the Spock equivalents.

Heres the code for your _Events.groovy script:
The template specification should be placed in src/templates/artifacts/Spec.groovy and is simply:
It goes without saying that this is a slightly hairy and it would be great if Grails provided a proper hook for overriding the test generation. I can live with some fun-size evil in _Events.groovy for the sake of the convenience of getting template specs for all my artifacts, though.

Available link for download

Read more »

Sunday, February 12, 2017

Avoiding accidental i18n in Grails

Avoiding accidental i18n in Grails


We’re developing an app that’s exclusively for a UK audience so i18n really isn’t an issue for us. However recently we got bitten by some i18n creeping in where we didn’t want it. Specifically, when using Grails’ g:dateFormat tag the default behaviour is to format the date according to the Locale specified in the user’s Accept-Language header. Even though we are explicitly specifying a format pattern for the date Java is aware of localized day names for some languages so the output can vary. The result is that on a page full of English text there suddenly appears a Spanish or Swedish day name. What makes things worse is that as we use server-side content caching and a CDN if a user with a non-English Accept-Language header is the first to see a particular page or bit of dynamically retrieved content then the cache is primed and until it expires everyone will see the non-English day name text.
The solution in a Grails app is as simple as replacing Spring’s standard localeResolver bean with an instance of FixedLocaleResolver. Just add the following to grails-app/conf/spring/resources.groovy:
localResolver(org.springframework.web.servlet.i18n.FixedLocaleResolver, Locale.UK)
This changes the way Spring works out the request locale and any locale-aware tags should just fall into place.

Available link for download

Read more »

Asynchronous application events in Grails

Asynchronous application events in Grails


On the project for my current client weve been using JMS in a rather naïve way for some time now. Weve also experienced a certain amount of pain getting JMS and ActiveMQ configured correctly. However, all were really using JMS for is asynchronous event broadcasting. Essentially we have a handful actions such as flushing hardware caches and notifying external systems that take place when a document changes. We dont want these things blocking the request thread when users save data.

After wrestling with JMS one too many times we decided to take a look at Springs event framework instead. It turns out its extremely easy to use for these kinds of asynchronous notifications in a Grails application.

Essentially any artefact can publish an event to the Spring application context. A simple publishing service can be implemented like this:
import org.springframework.context.*

class EventService implements ApplicationContextAware {

boolean transactional = false

ApplicationContext applicationContext

void publish(ApplicationEvent event) {
println "Raising event $event in thread ${Thread.currentThread().id}"
applicationContext.publishEvent(event)
}
}
So a Grails domain class can then do something like this:
def eventService

void afterInsert() {
eventService.publish(new DocumentEvent(this, "created"))
}

void afterUpdate() {
eventService.publish(new DocumentEvent(this, "updated"))
}

void afterDelete() {
eventService.publish(new DocumentEvent(this, "deleted"))
}
Grails services make ideal ApplicationListener implementations. As services are singleton Spring beans they are automatically discovered by Springs event system without any configuration required. For example:
import org.springframework.context.*

class EventLoggingService implements ApplicationListener<DocumentEvent> {

boolean transactional = false

void onApplicationEvent(DocumentEvent event) {
println "Recieved event $event in thread ${Thread.currentThread().id}"
}
}
Of course, multiple listeners can respond to the same events.

If you run the code you will notice that by default Springs event system processes events synchronously. The EventService and ApplicationListener will print out the same Thread id. This is not ideal if any of the listener implementations might take any time. Luckily its easy to override the ApplicationEventMulticaster bean in resources.groovy so that it uses a thread pool:
import java.util.concurrent.*
import org.springframework.context.event.*

beans = {
applicationEventMulticaster(SimpleApplicationEventMulticaster) {
taskExecutor = Executors.newCachedThreadPool()
}
}
Running the code again will show the event being published in one thread and consumed in another. If you have multiple listeners each one will be executed in its own thread.

Oddly, I would have thought it was possible to override the taskExecutor property of the default ApplicationEventMulticaster in Config.groovy using Grails property override configuration, but I found the following didnt work:
beans {
applicationEventMulticaster {
taskExecutor = Executors.newCachedThreadPool()
}
}

Available link for download

Read more »