Friday 23 May 2008

Debugging with Internet Explorer

Debugging with IE isn't something that you can really do without installing some sort of 3rd-party software.

To debug JavaScript, I've always used Visual Interdev, and for CSS, the IE Developer Toolbar. The problem with Visual Interdev is that its cost puts people off.

There are some good free tools available, however. I haven't used these before, but after re-installing windows, I thought I'd give them a go:

DebugBar is a plugin for IE that gives you a DOM inspector, an HTTP inspector, a JavaScript inspector and console, validation tools, and a whole load more. It's pretty much a "Firebug for IE" (although sadly, without a JavaScript debugger) :

http://www.debugbar.com/

Web Development Helper is a plugin for IE that gives you some useful tools (DOM inspector, logging HTTP requests, script error call stacks) :

http://projects.nikhilk.net/WebDevHelper/Default.aspx

Visual Web Developer 2008 is an application that lets you design and build web pages. It also comes with a JavaScript debugger :

http://www.microsoft.com/express/vwd/

There's a good article here about how to debug JavaScript using it :

http://www.berniecode.com/blog/2007/03/08/how-to-debug-javascript-with-visual-web-developer-express/


I'll update this post after I've used them for a while, although my first impressions are that DebugBar is probably the way to go.

Wednesday 21 May 2008

Fun with Hibernate's flush mode

An "interesting" problem we ran into recently was that even though we discarded changes to a domain object (when it failed validation) some of those changes were actually getting written to the database.

Consider this example:
class Lolcat {

String name
int number
boolean isGood

static constraints = {
number(nullable: true)
}
}

and let's re-create the problem:
    // save an instance
def kitteh = new Lolcat(name: 'ceiling cat', isGood: true)
assert kitteh.save(flush: true)
sessionFactory.currentSession.clear()
kitteh.refresh()

// check hibernate session contains our object and is not dirty
assert sessionFactory.currentSession.contains(kitteh)
assert !sessionFactory.currentSession.isDirty()

// update a simple property
kitteh.name = 'basement cat'

// session is now dirty as kitteh has pending writes
assert sessionFactory.currentSession.isDirty()

// assign another property based on a count query
kitteh.number = Lolcat.countByName(kitteh.name) + 1

// as we'd expect session is still dirty
assert sessionFactory.currentSession.isDirty()

// update another simple property
kitteh.isGood = false

// change our mind and discard changes (as real code would if validation failed)
kitteh.discard()

// session is no longer dirty
assert !sessionFactory.currentSession.isDirty()

// re-fetch our instance from the database and check it wasn't updated
sessionFactory.currentSession.clear()
kitteh.refresh()
assert kitteh.isGood
assert kitteh.name == 'ceiling cat' // FAILS - value is 'basement cat' WTF?!

What the devil is going on there? One of the property values we thought we'd discarded has been written to the database after all. We've been checking the dirty state of the Hibernate session as we go and it didn't look like it was flushed anywhere along the way.

We can shed some light on the problem by splitting up the assignment of the 'number' property like this:
    def newNumber = Lolcat.countByName(kitteh.name) + 1
assert sessionFactory.currentSession.isDirty() // FAILS (and a lightbulb goes on)
kitteh.number = newNumber
assert sessionFactory.currentSession.isDirty()

Now we can see that what's happening is the count query we execute is actually causing the Hibernate session to get flushed, hence the 'name' property value we assigned before the query gets prematurely written to the database while the 'isGood' property we assigned after the query gets discarded properly.

The culprit here is the Hibernate flush mode. By default it's set to AUTO. The Hibernate javadocs (for those of you too lazy to look it up) tell us: "The Session is sometimes flushed before query execution in order to ensure that queries never return stale state."

There are two ways to solve this then. One solution is to set the flush mode to MANUAL or COMMIT (the latter would be more appropriate in a transactional context such as a service method or withTransaction block), wrapping the code that modifies the domain object instance in something like this:
    try {
sessionFactory.currentSession.flushMode = org.hibernate.FlushMode.MANUAL
// modify and save our object
} finally {
sessionFactory.currentSession.flushMode = org.hibernate.FlushMode.AUTO
}

Which will certainly make the example above work. However, a better option in my opinion may be to do any pre-processing queries before starting to assign new values to the object. That way the session won't get flushed prematurely and we'd retain the benefits of FlushMode.AUTO.

Monday 19 May 2008

Dont trip on webtests due to this

A small gotcha when using Webtests which has caught a couple of pairs out is when your webtest is failing, citing a 404 as the cause whilst when you view the target URL using a browser it renders fine.

To flush this out, we enabled the following in our webtest (see storeResponseCode)

void webtest(String name, Closure yield) {
ant.testSpec(name: name) {
config(configMap) {
option(name: "ThrowExceptionOnFailingStatusCode", value: false)
}
steps {
yield.delegate = ant
yield()
}
}

}


then added

webtest("MyTest: some test"){
invoke(url:'/urlThatWorks')
storeResponseCode(property:"status")
verifyProperty(name:"status", text:"200")
.... [rest of test]
}


Our test passed with 200 status code, thus revealing the clue... our advert IFRAME within the page was 404'ing and the actual cause of our webtest failure.

Dynamic layouts in sitemesh

If you need to add sections into your sitemesh template you can use the <content/> tag.
For example, in main.gsp you might have something like this:

<body>
<div class="nav">
<span class="menuButton"><a href="http://www.blogger.com/" class="home">Home</a></span>
<g:pageproperty name="page.extraNav"/>
</div>
<g:layoutbody/>
</body>

Then you can add extra buttons to the nav bar in your pages by adding:

<content tag="extraNav">
<span class="menuButton"><a href="page/create" class="create">New Page</a></span>
</content>

Thursday 15 May 2008

Be unique ... and enforce constraints

Some of our unique constraints for domain objects are a bit loose at the moment. Where we have unique constraints based on multiple properties they are only enforced by the database when the hibernate session is flushed. However, it is possible to get grails to enforce multi property constraints so that a call to validate() will fail, rather than letting it fall through and cause a data access/jdbc exception.

For example, today we added a unique constraint on to Asset, where the originalAssetId had to be unique per Site.

To do this we added the constraint:

static constraints = {
.......
.......
originalAssetId(unique:'site')
.......
.......
}
The 'unique' property can also accept a list of properties. The following snippet would make originalAssetId unique by site and state.

static constraints = {
.......
.......
originalAssetId(unique:['site','state'])
.......
.......
}
Check out the grails docs for a full description.

Fear & Loathing in the MetaClassRegistry

On your testing travels you may, on occasion, mock methods out on certain classes using the old metaClass trick:
MyLovelyClass.metaClass.'static'.myLovelyMethod = { //crazy stuff here }

Now the fun with this approach is that when/how/where/how long/huh? feeling you get when you realize that other tests in the the suite start failing - dreaded test bleed (insert dramatic soundclip here).

Thanks to the Groovy method reference operation (&) and the MetaClassRegistry all can be made well, without having to resort to sticking all the initial method references in a map (or similar) and trying to stuff it all back on the original class in your tearDown():
void tearDown() {
def remove = GroovySystem.metaClassRegistry.&removeMetaClass
remove MyLovelyClass
}

Hmmm. I feel a bit lightheaded. Maybe you should drive.

Saturday 10 May 2008

Debugging client-side issues without access to source

If you're trying to debug a client-side issue without having access to modify the source code, it can be very tricky to try things out - especially in IE without handy tools such as Firebug. This is where Proxomitron comes in handy.

It's a handy proxy that lets you hot-replace code before it's delivered to the browser, based upon rules that can be customised quite heavily (including using regexps).

Get it here: http://www.proxomitron.info/

There are also many preset filters that can be edited or copied to make things easier.

Friday 9 May 2008

Use JSON for fixture output

When setting up automated web tests sometimes you need to parse generated data (ids, dates etc). An easy solution that works both from java and javascript and is therefore compatible with Selenium, Canoo and HttpUnit is to output the fixtures as JSON.


class FixtureController {

def index = {
Class clazz = grailsApplication.getClassForName(params.id)
List domainObjects = clazz.list(sort:'id', order:'asc')
Map model = getJsonModel(domainObjects)
render(view:'index', model: model)
}

private Map getJsonModel(List items) {
Map model = new HashMap()
items.each { item ->
JodaFriendlyJSON converter = new JodaFriendlyJSON(target: item);
converter.setRenderDomainClassRelations(true)
model.get('json', []).add(converter)
}
return model
}
}

// Only necessary if you use Joda rather than java.util.Date
// otherwise just use grails.converters.deep.JSON
class JodaFriendlyJSON extends grails.converters.deep.JSON {
protected void bean(Object o) {
if (o.class.isAssignableFrom(DateTime.class)) {
value(o.toString("dd/MM/yyyy HH:mm:ss"))
} else {
super.bean(o);
}
}
}


Now you can get whatever attribute you like from any of your domain objects just by navigating to /fixture/index/DomainObjectClass.

Java example:

protected String getConversationIdFromFixturePage(WebResponse resp, Integer index) {
JSONArray jsonArray = new JSONArray(resp.getElementWithID('json').getText())
return jsonArray.getJSONObject(index).getJSONObject('id')
}


Selenium Example:

// Add this to a custom extension

function parseJson(json) {
var x; eval('x = ' + json); return x;
}

Selenium.prototype.getJson = function(locator) {
return parseJson(this.getText(locator));
}

// Then do something like this in your selenium test
<tr>
<td>storeJson</td>
<td>//div[@id='json']</td>
<td>conversations</td>
</tr>
<tr>
<td>storeEval</td>
<td>{storedVars.conversations[0].id}</td>
<td>conversationId</td>
</tr>


Not groovy / grails related, but useful none the less

Moving files without losing Subversion history

You may have noticed that IntelliJ doesn't seem to like moving classes that are in the default package to another source directory (e.g. from test/integration to test/unit). Sure, you can simply move the file, then add to subversion and commit, but you lose the subversion history. A better workaround is:
    svn move [from] [to]
which retains subversion history of the file.

Thursday 8 May 2008

Confused with Groovy Regex?

Ever wonder what the heck is going on with groovy regex? Well recently I was confused with the following syntax matcher[0][1] when I was doing some regex work. What the heck does it mean and where does it come from?

Let's start from the top and work our way down. (Note: When trying to figure out regex while doing grails work I normally pop open the "grails console" and test everything in there)

assert "\\S" == /\S/ These are both the same thing. Note the benefit of the /.../ is that you do not have to escape so many characters.
def matcher = 'a b c' =~ /\S/ Match any character that is not whitespace

matcher is now a java.util.regex.Matcher and now can be used to return each match.
assert matcher[0] == 'a'
assert matcher[1] == 'b'
assert matcher[2] == 'c'


Ok that makes sense the matcher has found 3 matches to the regex that was defined.

So what happens when you add grouping?
matcher = 'a:1 b:2 c:3' =~ /(\S+):(\S+)/

Now matcher is again an instance of java.util.regex.Matcher except now it returns a two dimensional array. The first dimension is the number of times the regex has matched the string and the second is the grouping. Confused? Well let me show you an example that should explain everything.

matcher = 'a:1 b:2 c:3' =~ /(\S+):(\S+)/
assert matcher[0][0] == 'a:1' The full string that was matched.
assert matcher[0][1] == 'a' The first group.
assert matcher[0][2] == '1' The second group.

assert matcher[1][0] == 'b:2'
assert matcher[1][1] == 'b'
assert matcher[1][2] == '2'

assert matcher[2][0] == 'c:3'
assert matcher[2][1] == 'c'
assert matcher[2][2] == '3'

Hopefully this answered some questions. I have included some links to some useful groovy regex links:
http://groovy.codehaus.org/Regular+Expressions
http://docs.codehaus.org/display/GROOVY/Tutorial+5+-+Capturing+regex+groups
http://www.regular-expressions.info/reference.html

Wednesday 7 May 2008

Quick and easy way to find all methods on your groovy class

Here is a link that gives you the skills to get at all the methods and properties of your groovy class.

finding groovy methods

Linux Kickstart Boot Options

The RedHat/Centos Installation CD includes a basic bootloader. This is used to load the Anaconda Application which is responsible for performing the Operating System installation.

The boot loader allows you to pass different parameters into the Anaconda Application during boot time. These parameters may be predefined variables that influence the behaviour of the booting system, or they may be user defined variables that you can manually use in custom pre/post install scripts.

Predefined variables
Below are a list of some of the common predefined
  • ip - ip address of the booting system
  • netmask - netmask of the booting system
  • gateway - gateway of the booting system
  • dns - IP of nameserver
  • ks - location of kickstart file (either http, ftp or nfs location)
  • ksdevice - networking interface used to connect to ks file
  • text
example:
ip=1.2.3.4 netmask=255.255.255.0 gateway=1.2.3.254 dns=1.1.1.1 ksdevice=eth1 ks=http://kickstartserver/config/ks.cfg

User defined variables
All parameters passed to in the boot loader get written to the /proc/cmdline file. Post installation scripts can be written to source this file (. /proc/cmdline), and use the defined variables.

example:
a variable of "hostname=server.company.com" could be passed to the boot loader. A post installation script could be written to source this value and then write the contents to the /etc/sysconfig/network file on the installed system. The newly installed system now has a suitable hostname assigned to it.

Friday 2 May 2008

Debugging Grails

Here are some of the tools that you can use to help debug problems that you are having with grails:

  • grails-debug: Instead of running just grails run-app you can use grails-debug run-app which will allow you to hook up your ide to grails and insert break points.
  • grails -Dgrails.full.stacktrace=true run-app: This should give you the full stack trace. It isn't always useful but when you have nothing to go on it is a place to start.
  • ?showSource = If you are in development mode and you have a gsp error you can use this command to figure out what the problem actually is.