Saturday, 19 February 2011

Grails Tip: Accessing a Service from a Plain Old Groovy Object

Here's an example of how to access a Grails Service from a POGO:

package com.questern.aoms.pogo

import com.questern.aoms.MaterialDetail
import org.codehaus.groovy.grails.commons.ApplicationHolder as AH

class MaterialRow {
    Long id
    Integer layerNo
    String type
    String colour
    Double thickness
    String units

    def ctx = AH.application.mainContext
    def refCodeService = ctx.refCodeService

    public MaterialRow(){}

    public MaterialRow(MaterialDetail detail){
        this.id = detail.id
        this.layerNo = detail.layerNo
        this.type = detail.type
        this.colour = detail.colour
        this.thickness = detail.thickness

        def refCodeInstance = refCodeService.get("Material", this.type)
        def form = refCodeInstance?.meaning
        if(form == "Paper"){
            this.units = "gr"
        } else {
            this.units = "mu"
        }
    }
}

Sunday, 14 November 2010

Grails Tip: save() fail - the silent killer!

The conventions in Grails are usually very sensible and obvious, but the lack of notification on failure to save() a domain object is counter intuitive.

The simple solution is to enable the fail on error in the Config.groovy:

grails.gorm.failOnError=true

You can apply the setting on a case by case basis as follows:

quote.save(failOnError:true)

See docs for more details

There are historical reasons why the default is set to allow silent failure of save() and there is a discussion on the newsgroup to change the default behaviour to raise an exception on failure.

Thursday, 14 October 2010

STS Grails Tip - Formatting error in GSP

In a GSP the following causes the Springsource Tool Suite GSP Editor to incorrectly display an error:
<td class="prop">
  <g:textField name="dimensions[${i}].value" 
  value="${fieldValue(bean: q, field: 'value')}" />
</td> 
This is due to the construct [${i}], to resolve the problem wrap the i variable in braces [${(i)}]

<td class="prop">
  <g:textField name="dimensions[${(i)}].value" 
  value="${fieldValue(bean: q, field: 'value')}" />
</td> 
The error then disapears.

Friday, 24 September 2010

Grails Tip: Sorting rows in table when the underlying data structure is a Set (unsorted)

I was having trouble with the display of a list of items in a table.  Each time I refreshed the page the order was different.  This is because the items are coming from a Set, which is unsorted.  I had to add a sort closure to the g:each as illustrated below:
<g:each in="${ quoteInstance?.quoteItems.sort{a,b-> a.id.compareTo(b.id)} }" status="i" var="q">
<tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
<td><span class="buttons"><q:button controller="quote" action="selectQuoteItem" class="save" params="['id': quoteInstance?.id, 'quoteItemId':q.id]" value="${message(code: 'default.button.save.label', default: 'Select Quote Item')}" /></span>
<td>${fieldValue(bean: q, field: 'quantity')}</td>
<td>${fieldValue(bean: q, field: 'unitOfSale')}</td>
<td>${fieldValue(bean: q, field: 'unitPrice')}</td>
<td>${fieldValue(bean: q, field: 'materialGuidePrice')}</td>
<td>
<div class="buttons">
<q:button controller="quoteItem" action="edit" class="edit" params="['quoteId': quoteInstance?.id, 'id':q.id]" value="${message(code: 'default.button.edit.label', default: 'Edit')}" />
<q:button controller="quoteItem" action="delete" class="delete" params="['quoteId': quoteInstance?.id, 'id':q.id]" value="${message(code: 'default.button.delete.label', default: 'Delete')}" />
</div>
</td>
</tr>
</g:each>


Sunday, 30 May 2010

Cloud Hopping

Like this rock crevice that illuminates this cave at the "Murder Hole" near Melmore, Co. Donegal, windows of opportunity come in many shapes and sizes.
Currently there are many opportunities in the abundance of Cloud computing options.
The hard part is taking such fantastic resources and harnessing these to your particular needs. The Cloud provides many options for fledgling projects and businesses to quickly get up and running, but what if your business is not necessarily going to live in the Cloud?

We face one such problem as we develop our Order Management System.  It's an office system for a small company with no particular pretensions to live on-line.  So where's the Cloud angle on this?  For us the immediate need is to get our application in front of our customers as soon as possible so we can start the customer feedback cycle.  However, to go straight to the end system with an on site server to host our application is going to take time and money.

That's where the Cloud provides the window of opportunity, given that our application is built using the mighty Grails framework we can easily deploy our application with Grails on Cloud Foundry.  With a minimum of effort we where up and running with a test system that our users could validate new feature and give valuable feedback.  With short one week sprints and no fuss deployment we can now iterate quickly and keep the customer engaged in the project.

On the practical side of things we have found no need to have a permanent web presence for our test application, we simply deploy a new instance when we need our customer to test, send them the new URL and then stop the instance when they are done.  This keeps the hosting costs to a bare minimum, data is persisted in the Amazon EBS and available to the next deployed instance.

In conclusion, the Cloud is going to influence software development in many ways.  Whether you are the next big internet start up, or merely cloud hopping your way to delivering small office systems the opportunity to utilize the Cloud is an opportunity not to be missed.

Monday, 24 May 2010

Grails on Cloud Foundry

Some brief notes on Getting Started with Grails and Cloud Foundry.  I found the Cloud Foundry getting started page to be excellent, but there are a few details beyond the getting started guide that you need to deploy a real application.

Sign up with Cloud Foundry

Sign up with Cloud Foundry - https://www.cloudfoundry.com/cfapp/reg.html?_flowId=register-flow

I found it takes about 48 hours for your sign up to be approved.


follow the instructions on getting started with Cloud Foundry.  Remember to save your RSA Private Key you'll need it for SSH access.

http://www.cloudfoundry.com/getting_started.html

Creating WAR
Before creating the war ensure the DataSource.groovy is set up correctly, to make sure you don't reset the database every time you redeploy  set 

dbCreate = "update"

Now create the war:

grails prod clean
grails war

Deploying WAR
I toyed with the SpringSource Tools Suite, great for Grails development but for Grails deployment to Cloud Foundry it is not quite there yet.  I expect this to improve in the near future.  For now I find it easier to use the Grails Cloud Foundry plugin to upload:


grails cloud-foundry-upload


Then login to the Cloud Foundry web app: https://www.cloudfoundry.com/


on the applications tab select deploy for my application

You need to enter a name or the deployment - aoms

Select the database storage type as EBS New Volume and accept the default volume name, set backup interval appropriately

select Launch button

Subsequently when you redeploy the application you will select either:
- a Snapshot as the storage type and select the appropriate snapshot to restore from (this will result in a new EBS volume being created)
- an Existing Volume as the storage type and select the appropriate volume

You need to manage your EBS volumes and snapshots from the AWS Management Console - https://console.aws.amazon.com/ec2/home

Setting up SSH
For SSH access to my EC2 instance I use putty, the following guide is a great help:

http://docs.amazonwebservices.com/AWSEC2/2007-08-29/GettingStartedGuide/putty.html

You'll need the RSA Private Key you generated when setting up Cloud Foundry



Monday, 7 September 2009

Questern - Search for the optimal solution.

Questern is collection of ideas that lead to projects and possibly one day a business.

Right now we are building a Order Management System, because some one we know needs one!
In tandem we are assembling the processes and infrastructure necessary to enable a small geographically distributed team to collaborate on software projects in an optimal way.

Our vision is to become a software company specializing in delivering optimal solutions to business problems.

This blog is intended to capture our experiences, both business and technical from what we learn along the way.