2007-11-30

Groovy Grails GORM and its flaws

NOTE: This problem was fixed in the Grails 1.0 release making GORM the most amazing Object Relational Mapper ever created by mortals.

I am beginning to understand the limitations in Grails better. I would say the "honey moon" phase is drawing to a close now and I can effectively evaluate the tool in light of some of its limitations. One such limitation is GRAILS-1308 which is slated for fix on the Grails 1.1 release... yes the Grails 1.1 release... NOT the up coming Grails 1.0 release. It turns out that this is a significant problem.

The problem in a nutshell is that if you have:

class Company {
Long id
Long version

String name

static hasMany [employees: EmployeeBean]
}

... and that EmployeeBean can be the one from this tutorial or even a straight Groovy domain object... and you try todo this:

def people = EmployeeBean.list()
people.each({ e ->
company.addToEmployees(e)
})
company.save()


The employees will simply not make it into the database... more over GORM won't even bother setting up anything to associate the two classes... ick.

What I end up doing is either:

  • edit EmployeeBean so it "belongsTo" the company

  • create a "bridging" object like "Contract"



I haven't tested going to all JPA classes yet, but I wonder if that wouldn't work.

I had not even noticed that I was working around this problem because I just naturally saw that things weren't working for me the way I wanted to I tried to figure out what the tool could do... and then I'd do that. Ideally you shouldn't have to do that at all. But, this is reality and we have to ship our projects on the platforms in front of us.

Even with its flaws Grails is still much better at many tasks than any other Java related product I have access to. Seeing flaws like this one and the poor support for SOAP clients in Groovy/Grails make me evaluate where I'll use Grails until version 1.1 comes out. The answer for me is Grails will be my front end system and I'll learn how to do Spring-JNDI bridging or Spring-RMI remoting to tie in more mature EJB3 technologies for the complex tasks.

In other words, Grails becomes more View than Controller for me. It becomes a powerful front-controller system for UI and web-applications. That's a good niche to fill... especially if I can learn to tie in a SessionBean from plain old Java land.

Oh yeah, and I'm sorely disappointed in the Searchable plugin too. It simply doesn't work on newer Grails versions. I might use a standalone WAR with very old Grails in it just to get the searchable feature... or I might wait fitfully for that wonderful plugin to deliver on its promises.

EDIT

Looks like the searchable plugin development has stopped dead in its tracks. Oh well. I guess it will be a while.

EDIT 2

I guess we can look forward to this bug being fixed in Grails 1.0! This just shows how amazingly responsive Graeme Rocher and his team are. Think of how many utterly disappointing software releases we've seen in the last few years. The Grails 1.0 release could really count as a breath of fresh air. I know getting this kind of response from a development team surely is for me. It bodes well for the future of Grails.

I can live without a plugin for a while if it means I get a sterling framework for it to plugin to.

2007-11-29

Working Grails and JPA... troubleshooting

I've been working with Grails and the JPA. In eclipse I use the Hibernate3 reverse engineer tool. To make that work I use a hibernate.cfg.xml file that I place in my project's top level folder and a hibernate.reveng.xml file also in the top level folder. I then ask the tool to create EJB3 annotated POJOs and drop them into my grails project.

Previously, I had been deleting the hibernate.cfg.xml and hibernate.reveng.xml files out of the project but yesterday I forgot to do that. What happens if you leave these extra files in your project is that none of the JPA objects get mapped and are therefore invisible to your GORM.

It turns out GORM is reading the top level hibernate.cfg.xml file so why would it see those classes? I never mapped the EJB3 entity beans in the hibernate.cfg.xml I was using for reverse engineer. So, no surprise. There won't be an error either because there were no hibernate errors. The GORM was working perfectly well against the hibernate.cfg.xml in the top level directory.

Now you might wonder why I have two different hibernate.cfg.xml files? Well, the answer is that I need different configurations for the running environment and for the reverse engineer environment. That might be peculiar for me.

Is this a bug? No, not really. It was very hard to diagnose because of the lack of output. Even turning all the logs wide open produced no problems. It wasn't until I went through the project and reverted it to an old version then added one change at a time to it that I noticed the problem was related to the extra hibernate file. At least I know to watch for that now.

2007-11-27

Grails Datasource, legacy database, and you

Any one out there trying to work with Groovy, Grails, and legacy databases?

Well, I am and I thought I'd share with you my final dataSource configuration. I'm using a legacy database that drove an Apache + mod_perl web site that had a MySQL 3.x database. The Groovy/Grails project I'm working on will interact with that data (right now as a read-only service) and here's the final dataSource definition I ended up using for our first beta.


import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration
/**
* This project is driven off of Legacy data.
* Use update to prevent wiping old tables...
* much of the data is accessed using JPA classes generated by
* the Hibernate3 reverse engineer tool.
********************************************************************/
dataSource {
configClass = GrailsAnnotationConfiguration.class
dbCreate = "update"
dialect= org.hibernate.dialect.MySQLMyISAMDialect // or perhaps MySQL5Dialect
pooled = false
}
environments {
development {
dataSource {
driverClassName = "com.mysql.jdbc.Driver"
url = "jdbc:mysql://localhost:3306/legacy?zeroDateTimeBehavior=convertToNull"
username = "legacy"
password = "legacy"
}
}
test {
dataSource {
driverClassName = "com.mysql.jdbc.Driver"
url = "jdbc:mysql://localhost:3306/legacy?zeroDateTimeBehavior=convertToNull"
username = "legacy"
password = "legacy"
}
}
production {
dataSource {
jndiName = "java:/LegacyDS"
}
}
}


The LAMP stack was upgraded to use MySQL 5 recently so we can set up our new projects using the setting dialect= org.hibernate.dialect.MySQLInnoDBDialect which will give us the ability to use actual foreign key relationships. That's a big deal if you are a LAMP developer. I suppose that in short order I will be a Grails, Linux, Apache, MySQL developer... a GLAM developer... ah... no... lets not call it that.

BTW: I deploy to a JBoss Application server in production which manages the DataSources in a legacy-ds.xml file under /usr/local/jboss/server/default/deploy that's why my production dataSource uses the jndi lookup.

2007-11-26

Alpha Geeks: say w00t!

2 Types of programmers
... what many would call "alpha" programmers — the leaders, trailblazers, trendsetters, the kind of folks that places like Google and Fog Creek software are obsessed with hiring. These folks were the first ones to install Linux at home in the 90's; the people who write lisp compilers and learn Haskell on weekends "just for fun"; they actively participate in open source projects; they're always aware of the latest, coolest new trends in programming and tools.


Yet, we work for and produce software for use by casual programmers and non-programmers. And as Sussman's post points out we had best not forget it. That means you. If you are reading my blog chances are an alpha geek (or just horribly lost).

What's the point of all the pretty shiny objects if we can't get people to use the pretty shiny objects?

2007-11-21

Interoperability is the key to success

I just read the We have lost control post by Reg Braithwaite that's been making the rounds of the blog-o-sphere. Basically, modern IT departments compete directly with the internet. We have to. It's the 21st century. That's because...

Our users are being exposed to applications we don’t control. And it messes things up.


It means that our end users have used the internet and if our programs don't measure up they know it. You can't hide it! They know! Braithwaite tells us this lovely story about working on a CRM for his mum:


For example, my Mother uses Skype to talk to her friends. She thinks it’s normal to see all of your voice mail messages in a list on the screen. If I tried to give her a CRM application for managing contacts, the very first question she would ask would be, “Why can’t I listen to all of the voice mails from that contact in the application?”

Do you think she would have patience for my explanation that the company’s phone systems are complex and proprietary and that we can’t install Asterix just for her? She would grab me by the ear and drag me to my desk to get cracking on it!


In other words if you ship a CRM today that can't interoperate with a phone system... or your phone system can't interoperate with a CRM... your in house CRM will not measure up to the internet based competition... Skype.

And is the user wrong to expect a Skype-like experience? Should the IT department tell them to go suck an egg? I don't think that will fly.

Long story short modern IT departments will have to provide in-house mash-ups of services to be able to provide an end user experience that can compete with the wild and wooly internet.

BTW: I now believe that the Grails Searchable Plugin will change my life. Even though I haven't used it yet. Because I can see how full text search wins and how that plugin can single handedly enable search for all my projects. Yes... the computing world is about to change... again. Hold on for the barrel roll.

2007-11-20

helloLDAP.groovy

Here's a short script that I wrote just to test working with an ActiveDirectory server. It's a short hack of a script that you can use to just test settings and the like. Thanks to this script I know I've found the right settings to work with our Microsoft ActiveDirectory server through Java. I could even use this groovy code to set up a Spring Bean service.


#!/usr/bin/env groovy

import java.util.Hashtable
import javax.naming.*
import javax.naming.event.*
import javax.naming.directory.*

def ou = " System and Service Accounts"

// here, we're just reading in some parameters...
def stdin = new BufferedReader(
new InputStreamReader(System.in)
)
print "username: " // your username to access LDAP... not a real user
String username = stdin.readLine()
print "password: " // the password for that account...
String passwd = stdin.readLine()

// next we set up an environment for LDAP
Hashtable env = new Hashtable()
env.put(
Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory"
)
env.put(
Context.SECURITY_AUTHENTICATION,
"EXTERNAL"
)
/* // if only I had SSL working... *sigh* oh well...
env.put(
Context.SECURITY_PROTOCOL,
"ssl"
) //*/

// You'll want to put your server's name or IP here:
env.put(
Context.PROVIDER_URL,
"ldap://activedirectoryhost.mycompany.com:636/"
)

// Here, you'll want to set up your company's parameters for OU and DC...
env.put(
Context.SECURITY_PRINCIPAL,
"CN=" + username + ",OU=" + ou + ",DC=mycompany,DC=com"
) // username
env.put(
Context.SECURITY_CREDENTIALS,
passwd
) // and password

// Now we'll try and connect...
try {
def ctx = new InitialDirContext(env)
def attr = ctx.getAttributes("")
def srchInfo = new SearchControls()
// you'll want to use your own search base
def searchBase= "OU=company,DC=mycompany,DC=com"
// this is the magic search string sauce:
def searchFilter = "(&(objectClass=person))"
// we strong type the next var because it is
// used in a Java API that needs String[]
String[] objAttribs=[
"givenName",
"cn",
"sn",
"mail",
"mailNickname",
"userPrincipalName",
"displayName",
"manager",
"department",
"memberOf"
]
srchInfo.setSearchScope(SearchControls.SUBTREE_SCOPE)
srchInfo.setReturningAttributes(objAttribs)

// Now we get the results and loop through them...
NamingEnumeration dirObjects = ctx.search(searchBase,searchFilter,srchInfo)
def nodirObjects = 0
while (dirObjects != null && dirObjects.hasMoreElements()) {
def dirObject = dirObjects.next()
println("'" + dirObject.getName() + "':")
def attrs = dirObject.getAttributes()
for(name in objAttribs) {
println "\t * " + attrs.get(name)
}
nodirObjects++
}
ctx.close()
println("Number of entries identified: " + nodirObjects)
} catch (Exception e) {
println "Exception: " + e
}

2007-11-17

Grails Searchable Plugin... wow.

Words fail me Searchable plugin for Grails... wow. I'm speechless... I'm... wow. I just don't know what to say... wow.

Is anybody using this yet? I'm going to have to plug this into my very next project... wow.

2007-11-16

Magical MySQL URL parameters Save my Groovy Code

I've been working with legacy databases in MySQL and basically forbidden from using hibernate by a bug I had with all zero dates of the format '0000-00-00' which is perfectly legal in MySQL but completely disallowed in JDBC.
Stack trace for this problem contains:

SQL Exception: Value '0000-00-00' can not be represented as java.sql.Date

The answer? Apparently there is a hidden setting to use...

dataSource {
driverClassName = "com.mysql.jdbc.Driver"
dialect= org.hibernate.dialect.MySQLMyISAMDialect
url = "jdbc:mysql://localhost:3306/legacy?zeroDateTimeBehavior=convertToNull"
username = "legacyUser"
password = "legacyPassword"
}


That little flag on the URL is absolutely magical and now I can map my Grails objects onto a legacy database. Isn't life grand?

Groovy Class tricks

jwagon sent me these mind bending groovy class manipulations in a chat today:

#!/usr/bin/env groovy

class AA {
def msg
AA(something){ msg = something }
}

def c = { a, b ->
def x =a.newInstance(b)
println x.msg
}

c(AA, "foo")


Or how about....

#!/usr/bin/env groovy
def m = java.lang.String
def n = m.newInstance("foo")
println n

2007-11-15

The Fallacies of Distributed Computing

I'm working a SOAP heavy project right now so I thought I'd look up the 8 Fallacies of Distributed Computing. These are 8 assumptions people often make in designing network based systems such as a SOA or ESB that simply aren't true.

The following is NOT true:
1. The network is reliable.
2. Latency is zero.
3. Bandwidth is infinite.
4. The network is secure.
5. Topology doesn't change.
6. There is one administrator.
7. Transport cost is zero.
8. The network is homogeneous.

Designs should allow for the network to drop in and out, run slowly, take a while to move data around, change with out notice, or deal with multiple operating systems, langauges, or data representations. How often to we just think about the 'best case' scenario and fail to build in allowances for problems?

2007-11-14

Groovy Grails and the JPA

If you are using Grails 0.6 or later chances are the tutorials you've found for making EJB3 persistence annotated POJOs work with Grails don't match up exactly. If you're like me, probably need to be made aware of a few differences in configuration. They aren't big... but the little differences could trip you up.

First note my version of myApp/grails-app/conf/DataSource.groovy

import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration
dataSource {
configClass = GrailsAnnotationConfiguration.class
pooled = true
dbCreate = "create-drop"
driverClassName = "com.mysql.jdbc.Driver"
dialect= org.hibernate.dialect.MySQLInnoDBDialect
url = "jdbc:mysql://localhost:3306/grails"
username = "grails"
password = "grails"
}

Is not the same. Just because configClass = GrailsAnnotationConfiguration.class is set and your IDE says the class is found in this context doesn't mean that it's working for you... that import above still has to happen...

Next, I have added a file under "grails-app/conf/hibernate/hibernate.cfg.xml" and this part goes pretty much like the tutorials from last year... you register each class here one at a time. I need to research this one but I think grails mixes in this hibernate.cfg.xml with another one at run time so just stick to registering your classes. I tried to get fancy here and it didn't work out too well. My working hibernate.cfg.xml looks something like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping package="com.mycompany.shared.domain" />
<mapping class="com.mycompany.shared.domain.Subject" />
</session-factory>
</hibernate-configuration>

You'll need your Java files to be in "src/java" and annotated up. I will be trying to make a shared JAR file full of only the shared domain objects for the various projects that need them. I don't know how well this is going to work but my idea is to create one set of JPA annotated EJB3 Entity classes and put them in a JAR and share them between various Spring applications. I don't know if that's a good idea or not...

Finally, you'll need to get the compiled class files for these annotated POJOs into "web-app/WEB-INF/classes" that means you need to do a "grails run-app" or similar first so that the Java files get compiled into classes and dropped into the "web-app/WEB-INF/classes" directory.

Once that is done you can run the "grails generate-all" command on your Java classes.

If you're interested in working through the EJB3 examples I have posted ejb3_grails.zip which uses this tutorial by Jason Rudolph but also uses Grails version 1.0_RC1 and the Groovy Eclipse Plugin.

EDIT: in version 1.0 and higher recent experience shows that if you set the Eclipse Groovy plugin to output to bin and set the build path of the Java compiler to output to project/bin class resolution will work fine for the IDE. When Grails itself goes to run the application or build the WAR file, the right class files will make it into "WEB-INF/classes" since Grails uses a separate class cache anyhow. It seems the reason I advised to output Groovy and Java classes to "web-app/WEB-INF/classes" is no longer true.

2007-11-13

Groovy Grails documentation online...

As the much anticipated 1.0 release of Grails approaches, the first release of the official Grails 1.0_RC1 documentation has been released.

2007-11-11

3D Linux Desktop

I use a 3D Linux desktop to do my work in. I have a dual monitor setup at work and a nice high-resolution single monitor (shown) at home. The 3D desktop doesn't just give my work a nice sheen of eye-candy it also gives me valuable feedback on the health and status of my OS.

For one thing a busy application gets dimmer and gray in my desktop. So if my browser is busy it doesn't just stop responding to my clicks, I'll know its working hard well before that... I'll see it dim and go gray. If something really bad happens it will burst into flames. A moving application wobbles as it refreshes itself making the move feel substantial.

The 3D cube is a more natural way to deal with multiple desktops. I've been using 4 desktops in KDE for about a decade. But, it was easy to get lost on the desktops since they had no real spatial relationship to each other. This same feature has been ported to Windows and OSX so I'm sure many people are now enjoying multiple desktops. As far as I know these are UI changes that appeared on Linux first.

If you haven't seen Beryl yet you should. I think Beryl and Compiz could revitalize Linux on the desktop.

The humor of Engineers

From the wikipedia entry on Portal the video game:
"at the beginning of the Portal development process, we sat down as a group to decide what philosopher or school of philosophy our game would be based on. That was followed by about fifteen minutes of silence and then someone mentioned that a lot of people like cake."

I wish I worked in a team that had conversations like that. Oh... wait... I do.

2007-11-08

Being Presidential

"Nothing in the world can take the place of persistence.
Talent will not; nothing in the world is more common than unsuccessful men with talent.
Genius will not; unrewarded genius is a proverb.
Education will not; the world is full of educated derelicts.
Persistence and determination alone are omnipotent."
-- Calvin Coolidge

2007-11-07

Grails XFire Plugin

Had a little trouble with the XFire Plugin for Grails. I found this thread of posts on
nabble which clears things up. I attached the thread to the appropriate bug. Other than that I noticed that java.util.Date Is turned into a string. To fix this I created DTO (Data Transport Object) with XMLGregorianCalendar instead. This works find for DTO but could cause a minor headache if I have to expose domain classes directly through a SOAP service. Other than that the XFire plugin handles everything I need it to so far.

XFire is apparently on the verge of getting replaced with CXF which is an Apache incubator project. I was able to work through an CXF service myself using the JSR-181 annotations (that's the Java Web Services meta data specification). Configuring CXF inside a Spring container was the usual Spring XML-er-ific mess that you run into when doing Spring work without a tool kit.

Integrating the CXF Spring config with Grails worked up until I hit a class incompatability between Groovy 1.1 and CXF somewhere down in the XML parsers. I caught just enough to see that it was a class version problem around the DATETIME type where Groovy had one version and CXF had another. That was enough for me to decide to stick with the XFire plugin. I don't want to be in the business of building my own versions of anything that I didn't write.

I figure if the XFire plugin is that simple to set up then it will probably be just that simple to "port" my services to CXF later. Grails does a pretty good job of letting you switch between DWR, Prototype, and YUI when you are working in Ajax... so why not have multiple SOAP plugins that swap out just as easily?