After migration to new PROD server start getting error from some inactivity period:

2012-04-11 14:27:29,415 [TP-Processor3] ERROR (org.hibernate.util.JDBCExceptionReporter) - Communications link failure due to underlying exception: 

** BEGIN NESTED EXCEPTION ** 

java.io.EOFException
MESSAGE: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.

STACKTRACE:

java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
	at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:1997)
	at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2411)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2916)
	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1631)
	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1723)
	at com.mysql.jdbc.Connection.execSQL(Connection.java:3256)
	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1313)
	at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1448)
	at org.apache.commons.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:96)
	at org.apache.commons.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:96)
	at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
	at org.hibernate.loader.Loader.getResultSet(Loader.java:1808)
	at org.hibernate.loader.Loader.doQuery(Loader.java:697)

On previous server I’ve already had Broken Pipe error with MySQL and successfully solved it with http://sacharya.com/grails-dbcp-stale-connections/
But on new server (Red Hat Enterprise Linux) it failed.

After digging a lot I found http://stackoverflow.com/questions/2983248/com-mysql-jdbc-exceptions-jdbc4-communicationsexception-communications-link-fai and some other topics which helped.

Resulted config which fix problem is following:

  • On server in /etc/hosts.allow added ‘mysqld : ALL : ACCEPT’
  • On server in /etc/my.cf added ‘port=3306′
  • In DataSource.groovy added properties
  • In DataSource.groovy changed datadase URL to have IP (127.0.0.1) instead of localhost: ‘jdbc:mysql://127.0.0.1:3306/db_name’

That’s all!

 

Problem

Ofter we need to create RESTful API to READ data for existed domain objects with easy manipulation of fields in it. For example, we do not need to see in API result fields like ‘id’, ‘lastUpdated’, ‘createdBy’, collections, references and any other fields. Also we want to have easy way to change field name. For example, instead of ‘image’ you want ‘imageUrl’ because we need to put URL link there. And of course, we want to make different manipulations with fields, like put full URL or calculate whether shop is working now or anything else.

Solution

Of course, we can do it by simple code like

But when you have more then 20 fields in object and need to send complex structures, like send ‘address’ and ‘contact’ references but do not send ‘currentLocation’ and you have more then 10 of such objects – It became a nightmare! Support is even worst!

So, to solve this problem we create rather simple (at least when looking now on it) solution.
First define in UrlMapping something like:

So all READ API calls will be
‘/appName/api/users’ or ‘/appName/api/venues?format=json&max=10&offset=10′
In ‘ApiJsonRestController’ we need to get from domainInPlural real domain class name (through a simple mapping or complicated rule – up to you) and just send it to response:

In the result you will get list of domain instances with all fields – very Ugly.

Extend DomainClassMarshaller

Now is the most interesting part.
We need to override default Grails DomainClassMarshaller, so that during object rendering ours was used instead

It is a copy of DomainClassMarshaller with several modifications:

  • We control whether to define id for object by protected needToDefineId()
  • We control object id itself by protected getObjectIdentifier()
  • processAdditionalFields() allow to put any fields you want which are not in domain
  • We control fields to skip and alternative field name via protected methods getSkippedFields() and getAlternativeName(String originalName)
  • We controll how to display references to other domains and collections via processSpecificFields()

So for each object where we have specific fields to skip and alternative name or some rules to display fields we need to create an extended class:

You can try to play with it, but once it is done you have no any problem with support. New fields added automatically, if you change field name it will be changed everywhere: in places where domain object rendered itself and in embedded object.

And do not forget to register your Marshallers!!! We do it in BootStrap.groovy:

© 2012 REID Consulting Suffusion theme by Sayontan Sinha