Grails validation dependent on related domains - validation

I have several domain classes that are related and I am trying to figure out how to implement a constraint that depends on multiple domains. The jist of the problem is:
Asset has many Capacity pool objects
Asset has many Resource objects
When I create/edit a resource, need to check that total resources for an Asset doesn't exceed Capacity.
I created a service method that accomplishes this, but shouldn't this be done via a validator in the Resource domain? My service class as listed below:
def checkCapacityAllocation(Asset asset, VirtualResource newItem) {
// Get total Resources allocated from "asset"
def allAllocated = Resource.createCriteria().list() {
like("asset", asset)
}
def allocArray = allAllocated.toArray()
def allocTotal=0.0
for (def i=0; i<allocArray.length; i++) {
allocTotal = allocTotal.plus(allocArray[i].resourceAllocated)
}
// Get total capacities for "asset"
def allCapacities = AssetCapacity.createCriteria().list() {
like("asset", asset)
}
def capacityArray = allCapacities.toArray()
def capacityTotal = 0.0
for (def i=0; i<capacityArray.length; i++) {
capacityTotal += capacityArray[i].actualAvailableCapacity
}
if (allocTotal > capacityTotal) {
return false
}
}
return true
}
The problem I am having is using this method for validation. I am using the JqGrid plugin (with inline editing) and error reporting is problematic. If I could do this type of validation in the domain it would make things a lot easier. Any suggestions?
Thanks so much!

To use the service method as a validator, you'll need to inject the service into your domain, then add a custom validator that calls it. I think it'll look something like this:
class Asset {
def assetService
static hasMany = [resources: Resource]
static constraints = {
resources(validator: { val, obj ->
obj.assetService.checkCapacityAllocation(obj, val)
})
}
}

How about:
def resourceCount = Resource.countByAsset(assetId)
def assetCapacityCount = AssetCapacity.countByAsset(assetId)
if(resourceCount < assetCapacityCount) return true
return false
HTH

Related

Performance issue with geb lookup on module object attributes vs. using selectors

Problem Description
I am writing a geb/spock spec which fetches test data from DB2 into a map (the map variable is called "preFilledFields" - see the "MySpec" class further down).
This map is then being iterated over, and for each iteration I check too see if the value matches one in a row on the page.
When I perform the assertion above accessing the module object attributes, then the average execution time per assertion is approx. 5-6 seconds. If I perform the assertion using selectors directly, then the average execution time per assertion is approx. 70-80 ms. See the "MyPage" class for more details regarding the assertions.
Does anyone know what could be the cause of this? Is the bad performance a result of my code, or is there a general problem with regards to performance when using modules in geb?
Appreciate any help and input I can get.
Code:
My "RowModule" class looks like this:
class RowModule extends Module {
static final PREDEFINED_ATTR = "data-predefined-amount"
static content = {
cell { $("td", it) }
description { cell(0).text() }
rubrikNum { cell(1).text().toInteger() }
preDefinedAmount { cell(0).parent("tr").$("td[$PREDEFINED_ATTR]").attr("$PREDEFINED_ATTR") }
inputField { cell(0).parent("tr").$("td input") ?: false }
dataType{ cell(0).parent("tr").attr("data-type") }
}
}
My Page class looks like this:
class MyPage extends Page {
static url = "<some_url>"
static at = { $("h1").text() == "<some_text>" }
static content = {
submitButton { $("input", name:"<some_name>") }
myPageItems {
$("table tr").collect { it.module(RowModule) }
}
}
void verifyPrePopulatedFields(name, amount) {
long now = System.currentTimeMillis();
assert amount == selvangivelseItems.find { it.dataType== name}.preDefinedAmount.toInteger()
//assert amount == $("tr[data-type='" + name+ "']").$(".skts-tooltip-holder").text().toInteger()
println "Execution time" + (System.currentTimeMillis() - now) + " ms"
}
void submit() { submitTaxReturnButton.click() }
}
My Spec file looks like this:
class MySpec extends GebReportingSpec {
#Unroll
def "field #name is pre-populated with amount #amount from the database"() {
expect:
page(MyPage) verifyPrePopulatedFields(name, amount)
where:
name << preFilledFields.keySet()
amount << preFilledFields.values()
}
}
There are no general performance problems with using modules in Geb, at least none that I know of. Your selectors on the other hand are definitely suboptimal.
Firstly by doing myPageItems.find { it.dataType == name } you are iterating over all rows in your table and executing 3 WebDriver commands (that is http request between your test and the browser that is being driven) for each of them. You could improve the selector for dataType to dataType { attr("data-type") } (not 100% sure here because I don't see your DOM structure but this is what logic would suggest) but it would still mean potentially making a lot of requests. You should instead add a site content definition like this:
myItem { dataType ->
$("table tr[data-type='$dataType']").module(RowModule)
}
And then use it like:
assert amount == myPageItem(name).preDefinedAmount.toInteger()
Secondly you can simplify and improve performance of your selectors in the module (if my assumptions about your DOM are correct):
static content = {
cell { $("td", it) }
description { cell(0).text() }
rubrikNum { cell(1).text().toInteger() }
preDefinedAmount { $("td[$PREDEFINED_ATTR]").attr("$PREDEFINED_ATTR") }
inputField { $("td input") ?: false }
dataType{ attr("data-type") }
}
You should avoid using multiple selectors for things that can be found using a single selector or using unnecessary selectors because they will always carry a performance penalty.

Grails validate fields with default values

We have a class like this in a Grails 2.4.3 application (migrated from 2.3.8):
#Validateable
class Foo {
Integer noDefault;
Integer withDefault = 1;
static constraints = {
noDefault(nullable:false)
withDefault(nullable:false)
}
}
This class is being instantiated in a complex configuration mechanism using a Map like this:
[
noDefault: 0,
withDefault: 2
]
(In fact the Map is part of a huge one, but the class constructor sees this small one.) Formerly the class worked if we omitted the withDefault entry from the config map, using the default value which is not null. In Grails 2.4.3, however, it tells me that this field cannot be null. I can fix it by letting it be null in the constraint, but it lets setting the explicite value null (and overwrite the default value), which causes problem during operation.
Do you know some workaround, which preserves the semantics and correct operation?
Thanx in advance, best regards: Balázs
What you are describing is not consistent with what I would expect and not consistent with the behavior I am seeing. The project at https://github.com/jeffbrown/validatedefaults contains the following code.
At https://github.com/jeffbrown/validatedefaults/blob/master/src/groovy/demo/Foo.groovy
// src/groovy/demo/Foo.groovy
package demo
import grails.validation.Validateable
#Validateable
class Foo {
Integer noDefault;
Integer withDefault = 1;
static constraints = {
noDefault(nullable:false)
withDefault(nullable:false)
}
}
The test at https://github.com/jeffbrown/validatedefaults/blob/master/test/unit/demo/FooSpec.groovy passes:
// test/unit/demo/FooSpec.groovy
package demo
import spock.lang.Specification
import grails.test.mixin.TestMixin
import grails.test.mixin.support.GrailsUnitTestMixin
#TestMixin(GrailsUnitTestMixin)
class FooSpec extends Specification {
void 'test validating default values'() {
given:
def map = [noDefault: 0]
def foo = new Foo(map)
expect:
foo.validate()
}
}
When I run the app I get the same behavior.
// grails-app/conf/BootStrap.groovy
import demo.Foo
class BootStrap {
def init = { servletContext ->
def map = [noDefault: 0]
def foo = new Foo(map)
// this prints true...
println "Foo is valid? : ${foo.validate()}"
}
def destroy = {
}
}
I hope that helps.

Grails Spring Security verify access for multiple url

I would like to verify if the user has access to more than one url, in a view, like this:
<sec:access url="/user,/client">
Just like the sec:ifAnyGranted tag for roles:
<sec:ifAnyGranted roles="ROLE_ADMIN,ROLE_SUPERVISOR">
In my verifications, the sec:access url just works with one url.
Is there any way or alternative to this?
I'm using the spring-security-core:2.0-RC2 plugin for grails.
I don't thing multiple URLs is supported. You can create your own tag to do this like
class CustomTagLib {
static namespace = "myTag"
def ifAnyGranted = { attrs, body ->
List<String> urls = attrs.remove('urls').split(',')
Boolean hasAccess = Boolean.FALSE
for (int i = 0; i < urls.size(); i++) {
hasAccess = sec.access(url: urls.get(i).trim()) { Boolean.TRUE }
if (hasAccess) {
out << body()
break
}
}
}
}
and use it in the view like:
<myTag:ifAnyGranted urls="/domain/index,/domain/show">
Something to display if has access to anyone of the URL
</myTag:ifAnyGranted>

Grails - Field error disappears from parent class

I have the following problem:
I have a domain class called customer, with a field discount embedded.
class Customer {
...
String username
Discount discount
static constraints = { ... }
}
class Discount {
Integer item1
Integer item2
static constraints = { item1 min:1, max:100, nullable:true }
}
I have a controller, where a customer's data can be modified. The code goes something like this:
def edit() {
Customer c = Customer.findByUsername(params.userName)
if(request.method != 'GET'){
bindData(c, params)
if(c.validate()) {
//save the result
}
}
println c.dump()//1
model:[customer:c]
}
Then in the edit.gsp I put the following code:
${customer.dump()}//2
${customer.discount.dump()}
Now my problem is, if I have a validation error, for example the user enters 123 for item1, I get the appropriate errors object which says that Customer bean has 1 field error on field discount.item1 when I call println c.dump()//1
In the edit.gsp on the other hand, the customer bean doesn't have any field errors but customer.discount has the mentioned error. This is a big inconvenience, because I want to render errors next to the fields like so:
<g:renderErrors bean="${customer}" field="discount.item1"/>
But the customer bean doesn't have any errors, just the discount bean (therefore I don't get any errors rendered).
Has this problem occured to any of you ?
It seems that #Validatable classes use functionality of spring framework's AbstractBindingResult, which doesn't support this usage (as far as I can tell).
However I was able to create a workaround, which could be used as a taglib to achieve the same effect:
Given two validateable classes
#Validateable
class TestA {
TestB b
static constraints = {
b validator: {
it.validate()
}
}
}
#Validateable
class TestB {
int c
static constraints = {
c min: 100
}
}
One can simply resolve the bean and the attribute and delegate the rendering to the existing taglib.
import test.*
import org.codehaus.groovy.grails.plugins.web.taglib.*
ValidationTagLib validationTagLib = ctx.getBean(ValidationTagLib)
renderErrorsWithNestedFields = { attrs, body ->
def modifiedAttrs = attrs
String[] path = attrs?.field?.split('\\.')
if(path?.size() > 1) {
Object resolvedBean
resolvedBean = attrs.bean
path[0..-2].each {
//Some error handling would not hurt, but this is just a proof of concept
resolvedBean = resolvedBean[it]
}
modifiedAttrs = new HashMap(attrs)
modifiedAttrs.bean = resolvedBean
modifiedAttrs.field = path.last()
}
validationTagLib.renderErrors (modifiedAttrs, null)
}
TestA a = new TestA(b:new TestB(c:3))
a.validate()
renderErrorsWithNestedFields([bean:a, field:'b.c'], null)
And this should render an error for violating the min constraint on c.

Grails domain class validator, property must be greater than another property

I have the following domain class in my grails project:
class Vacation {
Date start
Date end
User vacationer
static constraints = {
start(validator: {return (it >= new Date()-1)})
}
}
Is it possible to add a validator that requires end to be equal or greater than start?
Cheers
Use
start(validator: {
val, obj ->
val < obj.properties['end']
})
You can directly access property "end", since obj is the object of the class Vacation only, where it is defined.
Use:
start(validator: {
val, obj ->
val < obj.end
})

Resources