We recently received a new defect report claiming that some of our data was not being distributed correctly through JMS. Actually some of the data was not being distributed at all! That's the first time we have heard that complaint - hey, JMS is guaranteed delivery, right? Well not so fast...
Apparently we had a 'slow leak' in our connection pool within JBoss MQ. After a few days of uptime, the server seemed to stop distributing some of our data. The problem helped expose a deficiency in our JMS client code. We had not registered an ExceptionListener with our Connection object and as a result, we were not notified of problems creating a new Connection. I don't know about everyone else but most of the JMS sample client code that I have seen hasn't registered an ExceptionListener so that interface was news to me. Oh well, another learning experience!
So... JMS guaranteed delivery requires some assistance from the client as well, to help handle connection errors.
Tuesday, September 29, 2009
Thursday, September 24, 2009
Using HTTPBuilder to call a RESTful web service
Our team is delivering a new RESTful web service and so I figured that I would scratch my Grails itch and create a small application for testing the new web service. RESTClient looked like it would be a great match and it would be except that I want to display the XML request being passed to the service as well as the XML response returned from the service. Displaying the XML request is not a problem. The problem is that RESTClient automatically parses the response data and returns a GPathResult NodeChild object.
After reviewing the documentation for RESTClient and exchanging some emails with the RESTClient developer, he made the suggestion of using HTTPBuilder instead of RESTClient. The code shown below is the call to HTTPBuilder to call the new service. This topic came up in another posting and you can see an alternative approach here.
Points to notice
After reviewing the documentation for RESTClient and exchanging some emails with the RESTClient developer, he made the suggestion of using HTTPBuilder instead of RESTClient. The code shown below is the call to HTTPBuilder to call the new service. This topic came up in another posting and you can see an alternative approach here.
Points to notice
- The second parameter to HTTPBuilder is setting the default content type to TEXT.
- The request sets the Accept header to 'application/xml'.
- HTTPBuilder.RequestConfigDelegate send method sets the content type to XML
- Success handler gets response from 'reader.text' and then pretty-prints the result back in to a String for easy display.
def txnCreate(TransactionSpec txnSpec, String userid, String pswd) { def conf = Configuration.get(3) if (conf != null) { def ppos = new HTTPBuilder( conf.protocol+"//"+conf.server+":"+conf.port, TEXT ) ppos.headers = [Accept:'application/xml', 'ppos-user':userid, 'ppos-pswd':pswd] try { ppos.request( PUT ) { uri.path = conf.context + conf.url send( XML ) { TransactionSpec (training:txnSpec.training) { delegate.transClassName txnSpec.transClassName delegate.locationNumber txnSpec.locationNumber delegate.currencyCode txnSpec.currencyCode AssociateSpec { delegate.associateNumber txnSpec.associateSpec.associateNumber } delegate.terminalName txnSpec.terminalName LineItemSpecs { for (item in txnSpec.lineItemSpecs) { LineItemSpec { sku(item.sku) quantity(item.quantity) } } } TenderSpecs { for (tender in txnSpec.tenderSpecs) { TenderSpec { tenderCode(tender.tenderCode) cardNumber(tender.cardNumber) expiryDate(tender.expiryDate) track1Data(tender.track1Data) track2Data(tender.track2Data) track3Data(tender.track3Data) preLockNumber(tender.preLockNumber) preLockAmount(tender.preLockAmount) amount(tender.amount) precision(tender.precision) } } } } } // success handler response.success = { resp, reader -> // pretty print format the response def stringWriter = new StringWriter() def node = new XmlParser().parseText(reader.text); new XmlNodePrinter(new PrintWriter(stringWriter)).print(node) return stringWriter.toString() } // failure handler response.failure = { resp -> return 'Response status='+resp.status } } } catch(Exception e) { log.error("Caught exception:", e) return e.toString() } } }
Thursday, September 17, 2009
Blogger Minima template wastes space
I just recently started blogging and so I am trying to figure out what looks good and how to get my blog to look better. I choose the Minima template but noticed that the 'gutters' seemed too wide down the left and right side of the page. Postings with code seemed to caused a lot of the line to wrap and it just didn't look very good. After seeing some other blogs that didn't appear to have that problem, I posted comments asking, "How'd you do that?". Someone suggested adjusting the template and so I took his advice. Below is a just a couple minor tweaks I made to the template and the code examples look much better and the gutters are not nearly so wide!
This all coming from a developer who has spent most of his career in the middle-tier and server-side of applications. For those of you very familiar with CSS, you can probably stop reading NOW.
Updating the Minima template to increase the posting area
This all coming from a developer who has spent most of his career in the middle-tier and server-side of applications. For those of you very familiar with CSS, you can probably stop reading NOW.
Updating the Minima template to increase the posting area
- Go to Layout --> Edit HTML page
- Click the 'download template' link to make a backup copy of your template, for safe keeping
- In the editable textarea, make the following changes to the style sheet entries:
- outer-wrapper width change from 660px to 1000px,
- main-wrapper width change from 410px to 700px
- footer width change from 660px to 1000p
- Click the 'preview' button to see the changes
- If you are happy with the new spacings, click the 'save template' button.
Wednesday, September 16, 2009
Example Grails data binding for one-to-many association
Data binding is an integral aspect of all web applications. The responsibility for the data binding generally falls within the scope of the controller. In this following example, I will show all the 'moving parts' that are needed to easily bind a domain object with a one-to-many association within Grails.
I looked around for a simple example of data binding to handle a one-to-many association and never really found a full example so I decided to create an example and share it. The example uses a Person domain object with a one-to-many association of Address objects. All of the data is captured on a single screen. The example uses DHTML or Dom scripting to dynamically create multiple address form fields and submits all the data from one screen.
Domain objects: Person & Address
The Person constructor contains just a first and last name. Notice the Address field implements Serializable and also implements the hashCode() and equals() methods as required for objects that are to be placed in a collection.
Sample screen shot of create person screen
Below is a snapshot of a the create.gsp screen after clicking the 'Add Address' button twice and filling in the data. The 'Add Address' button calls a javascript function (see further below) to create an additional address row in the address table. (I wanted to provide the entire page .gsp source but could not get it formatted correctly - if anyone has suggestions, I would appreciate hearing from you.)
Add Address javascript function
Below is the javascript function called from the 'Add Address' button on the form. The important part here is that use of the hidden field, addrCount, to add an index to the address form field names and ids.
PersonController
When the form is submitted, the save action is called. I have created a helper method, bindPerson(), to handle the data binding. The method iterates 'addrCount' times, creating a new Address object, calling the bindData() method provided by Grails with the params starting with the value 'addresses[i]'. Lastly, the address is added to the collection and the Person object is returned.
The controller code below works party because my constructor for the Person object initializes the addresses field to an empty list. Other options might be to create a list in the controller and then set the addresses field to that list, or keep the initialized list and call personInstance.addToAddresses(addr).
Here you see the results on the show.gsp screen.
Wrap up:
Note: Please see an improved solution in Part 2
I hope this helps and as always, constructive criticism is appreciated! Due to the large number of requests, I have created a site over at Groovy sites and you should be able to download from here. Download site is https://sites.google.com/site/mikesgroovystuff/
I looked around for a simple example of data binding to handle a one-to-many association and never really found a full example so I decided to create an example and share it. The example uses a Person domain object with a one-to-many association of Address objects. All of the data is captured on a single screen. The example uses DHTML or Dom scripting to dynamically create multiple address form fields and submits all the data from one screen.
Domain objects: Person & Address
The Person constructor contains just a first and last name. Notice the Address field implements Serializable and also implements the hashCode() and equals() methods as required for objects that are to be placed in a collection.
class Person { static hasMany = [addresses:Address] static constraints = { } Person() { addresses = [] } String firstName String lastName List<Address> addresses String toString() { firstName + " " + lastName + " Addresses: "+addresses } } class Address implements Serializable { static constraints = { } String street String city String zip String toString() { street + "\n" + city + ", " + zip } int hashCode() { street?.hashCode() + city?.hashCode() + zip?.hashCode() } boolean equals(o) { if (this.is(o)) return true if (!(o instanceof Address)) return false return street?.equals(o.street) && (city?.equals(o.city)) && (zip?.equals(o.zip)) } }
Sample screen shot of create person screen
Below is a snapshot of a the create.gsp screen after clicking the 'Add Address' button twice and filling in the data. The 'Add Address' button calls a javascript function (see further below) to create an additional address row in the address table. (I wanted to provide the entire page .gsp source but could not get it formatted correctly - if anyone has suggestions, I would appreciate hearing from you.)
Add Address javascript function
Below is the javascript function called from the 'Add Address' button on the form. The important part here is that use of the hidden field, addrCount, to add an index to the address form field names and ids.
function addAddr(tblId) { var tblBody = document.getElementById(tblId).tBodies[0]; var newNode = tblBody.rows[0].cloneNode(true); var count = parseInt(document.getElementById("addrCount").value); count++; document.getElementById("addrCount").value = count; var cells = newNode.cells; for (var i=0; iif (cells[i].firstElementChild.id.indexOf("street") != -1) { cells[i].firstElementChild.id = "addresses["+(count-1)+"].street"; cells[i].firstElementChild.name = "addresses["+(count-1)+"].street"; } else if (cells[i].firstElementChild.id.indexOf("city") != -1) { cells[i].firstElementChild.id = "addresses["+(count-1)+"].city"; cells[i].firstElementChild.name = "addresses["+(count-1)+"].city"; } else if (cells[i].firstElementChild.id.indexOf("zip") != -1) { cells[i].firstElementChild.id = "addresses["+(count-1)+"].zip"; cells[i].firstElementChild.name = "addresses["+(count-1)+"].zip"; } } tblBody.appendChild(newNode); }
Here is the initial statement for the hidden addrCount index field.
<g:hiddenField name="addrCount" value="1" />
PersonController
When the form is submitted, the save action is called. I have created a helper method, bindPerson(), to handle the data binding. The method iterates 'addrCount' times, creating a new Address object, calling the bindData() method provided by Grails with the params starting with the value 'addresses[i]'. Lastly, the address is added to the collection and the Person object is returned.
The controller code below works party because my constructor for the Person object initializes the addresses field to an empty list. Other options might be to create a list in the controller and then set the addresses field to that list, or keep the initialized list and call personInstance.addToAddresses(addr).
class PersonController def save = { def personInstance = bindPerson(params) if(!personInstance.hasErrors() && personInstance.save()) { flash.message = "Person ${personInstance.id} created" redirect(action:show,id:personInstance.id) } else { render(view:'create',model:[personInstance:personInstance]) } } def Person bindPerson(params) { def personInstance = new Person() def count = params.addrCount.toInteger() for (int i=0; i<count; i++) { def addr = new Address() bindData(addr, params["addresses["+i+"]"]) personInstance.addresses[i] = addr } personInstance.properties = params return personInstance }
Results
Here you see the results on the show.gsp screen.
Wrap up:
- First you need to setup your domain objects, including implementing Serialization, hashCode() and equals(), where required.
- Form fields need to be name using index, like addresses[0].city or addresses[3].zip
- Finally, the controller needs to bind the association data using the indexed fields.
Note: Please see an improved solution in Part 2
I hope this helps and as always, constructive criticism is appreciated! Due to the large number of requests, I have created a site over at Groovy sites and you should be able to download from here. Download site is https://sites.google.com/site/mikesgroovystuff/
Subscribe to:
Posts (Atom)