Showing posts with label Grails. Show all posts
Showing posts with label Grails. Show all posts

Monday, August 18, 2008

Grails Crowd has launched

After working on this project on and off for around 9 months (funny coincidence with pregnancy time frame :-) [life took precedence], I was finally able to finish and launch Grails Crowd - "the friendly online community (or directory) for Grails developers Worldwide".

I will most likely open source the code and let the community drive the innovation and the future direction of the site. I have pretty much decided that the home of the code will be GitHub :-)

Later...

Friday, July 18, 2008

Getting closer

As I'm getting closer to finishing up the essential code for GrailsCrowd, I noticed that I'm doing on the fly refactorings more seamlessly than I was able to do when I first started hacking with Groovy/Grails. And Groovy Closures are my friends these days :-)

Here's a small example from the GrailsCrowd code base - 2 simple controller actions to query for Grails projects by tags, only with the difference that the first action gets all the projects within a system for a specified tag (globally) and the other one gets projects for a tag for a specific member. Both actions operate on the Tag instance, so I refactored the common functionality of querying for Tags into a method which takes a closure:


class GrailsProjectController {

...
private def withTag(callable) {
if (!params.selectedTag) {
redirect(uri: '/notAllowed')
}
def tag = Tag.findByName(params.selectedTag)
callable(tag)
}
...
}


And then the above mentioned actions became:


class GrailsProjectController {

...
def findByTagGlobally = {
def total = 0
def projects = []
withTag {tag ->
if (tag) {
total = Tagging.countByTag(tag)
//Using CrieteriaBuilder here, so we could query by 'taggings' association
projects = GrailsProject.createCriteria().list(params) {
taggings {
eq('tag', tag)
}
} //Criteria builder
//Sort by name since GrailsProject implements Comparable and the name property is its natural order
projects.sort()

} //if
} //Closure
render(view: 'list', model: [projects: projects, navMenu: 'discoverNavigationByTag',
paginatingController: controllerName, paginatingAction: actionName, total: total,
menuContext: [tag: params.selectedTag]])
}

def findByTagForMember = {
def total = 0
def projects = []
def member = Member.findByName(params._name)
withTag {tag ->
if (tag) {
if (!member) {
redirect(uri: '/notAllowed')
}
total = Tagging.countByTagAndMember(tag, member)
//Using CrieteriaBuilder here, so we could query by 'taggings' association
projects = GrailsProject.createCriteria().list(params) {
taggings {
eq('tag', tag)
eq('member', member)
}
} //Criteria builder
//Sort by name since GrailsProject implements Comparable and the name property is its natural order
projects.sort()
} //if
} //Closure
render(view: 'list', model: [projects: projects, navMenu: 'memberProjectsNavigationByTag',
paginatingController: controllerName, paginatingAction: actionName, total: total,
menuContext: [tag: params.selectedTag, member: member]])
}
...
}


Also notice the use of GORM CriteriaBuilder which allowed to nicely query m:n 'Tagging' association class!

Keep Groovying.

Later...

Saturday, June 7, 2008

Programming with closures

Recently I caught myself thinking that my programming habits are changing while programming in Groovy. In particular, I started using closures more and more to clean up my code, make it more DRYer, e.g. by not just merely using existing closures provided by libraries such as GDK, GORM, etc., but by creating my own closures.

Here's a small example from GrailsCrowd. The idea here is to either 'accept project participation invitation' or 'reject project participation invitation'. So, in the Controller, I factored out the common code of retrieving the Member, Project, redirecting to the appropriate action afterwards, etc. to a private method which takes a closure, and calling that closure for the actual action of 'acceptance' or 'rejection':


private def withProject(callable) {
def invitee = freshCurrentlyLoggedInMember()
def creator = Member.findByName(params.creator)
def project = GrailsProject.get(params.projectId)
//Call the closure
callable([project:project,creator:creator,invitee:invitee])
redirect(controller: 'mailbox')
}

def acceptParticipationInvitation = {
withProject {projectMap ->
projectMap.project.acknowlegeParticipationAcceptance(projectMap.creator,
projectMap.invitee, params.messageId.toLong())
}
}

def rejectParticipationInvitation = {
withProject {projectMap ->
projectMap.project.rejectParticipationInvitation(projectMap.creator,
projectMap.invitee, params.messageId.toLong())
}
}


IMO, this makes code cleaner, reusable, and more maintainable. Also, this style of programming with closures kind of replaces good old Template Method design pattern.

Keep on Groovying, folks!

Later...

Thursday, April 10, 2008

Grails in a 'Cloud'

These days, the new generation of computing, so called 'cloud computing', where the infrastructure of the entire data centers is outsourced, abstracted, and hosted somewhere in the 'cloud' (on the Internet), is getting hugely popular. In a nutshell, it provides a so called 'low barrier to entry' for smaller internet companies to make their presence on the Internet market place without spending a fortune and ridiculous amount of time and energy buying their own hardware and maintaining their own data centers.

Amazon EC2 service hugely popularized this type of computing and early this week, Google jumped on the bandwagon with their App Engine exposing the power of their computing infrastructure, as well as the entire web development stack (Python-based - what else did you expect from Google) :-) to the army of ordinary, but creative software development minds.

After the announcement, Google has received feedback from developers requesting support for different programming languages/frameworks, and among Perl and Ruby, the requests for Java/Groovy/Grails are overwhelming.

Now that we have a rock-solid RAD web framework for Java (Grails that is), we are just missing the last piece of the puzzle: a rock-solid and affordable Grails hosting in a 'cloud'. The demand seems to be there. Hint, hint for ambitious start up companies :-)

Later...

Friday, April 4, 2008

So enjoyable

While hacking GrailsCrowd today, I caught myself thinking that programming in Groovy is such an enjoyable experience (for me). Take this method for example:


// Social feature: gets a list of 'colleagues' working on the same projects as *this* member
def getProjectColleagues() {
getActiveProjects().collect
{it.participants}.flatten().findAll
{it.participant.id != this.id}.collect {it.participant}
}
Is it possible to navigate "deep" object graph and express the same intent with the similar compactness in 'raw' Java code? I think not :-)

Later...

Sunday, March 16, 2008

Simple "Feedback" service

At our organization, I keep observing a recurring struggle to gather requirements and design public facing products. I mean, for example, when development teams are tasked to design systems that are targeted for students, all the requirements come from deans (supposedly 'product managers') without any kind of usability study and feedback from real users e.g. students. Also, the growing amount of 'phantom use cases' is being pushed into public facing products by our internal IT management without any real analysis of what the actual users would want and how they would actually use the system in question (or so it seems to me).

I was just discussing with my colleagues the fact that it would really be beneficial to gather feedback about systems from our student users, analyze it and then derive use cases from it for future product developments. IMO, that would really be more useful than simply coming up with those 'phantom requirements' ourselves.

To realize that, I'm thinking of creating a simple generic "Feedback" web application/service that would contain a 'rating', 'feedback/suggestions/comments' that users can submit. This should be a generic service that could gather feedback/reviews/ratings from students and/or internal corporate users for any systems, etc. (think Amazon reviews). And once we have all the data, we would be able to do all kinds of "collective intelligence' (data mining) analysis with it which would hopefully help us improve our products and make our product development more 'user-centric' instead of 'corporate-centric'.

I'm planning using Grails for the first prototype.

Later...

Tuesday, February 12, 2008

Hidden gem: grails.war.resources

In the process of packaging up the Grails application as a WAR in preparation for deployment to Tomcat, I needed to figure out a way to exclude the Oracle JDBC drver from WEB-INF/lib (we use 'shared' Oracle driver for our web apps which gets loaded by the Catalina's common ClassLoader). So I was thinking of a way to provide an "event hook" script, and while reading Grails' War.groovy I found a "hidden gem". That is a closure which is defined in the application's Config.groovy. So when this closure is defined, the War.groovy calls it with "staging directory" as a parameter and sets Ant as its 'delegate' right before zipping it up as a war.

So I was able to do the following (... from Config.groovy):


//Closure to customize the packaging of a war. In particular it excludes the Oracle JDBC driver
//from the war as it is loaded by the Catalina common ClassLoader when deployed to Tomcat
grails.war.resources = {stagingDir ->
delete(file: "$stagingDir/WEB-INF/lib/ojdbc14-10.2.jar")
}

This is real nice, but I don't think this feature is documented anywhere.

Later...

Monday, February 11, 2008

Script event hooks are cool

Grails has had the so called 'event hooks' for Gant scripts since 0.5. It basically is a way to tap into the Grails Gant scripts execution flow to customize build process, etc. It is elegantly implemented (as everything else in Grails) as a collection of closures in the Events.groovy script. The 'event closures' get called by Grails when the corresponding 'events' get generated in the Gant script e.g. a method 'event' is called with the event name as a parameter. So for example, event("StatusUpdate", [ "Status update event is called"]) would result in eventStatusUpdate { msg -> } closure defined in Events.groovy being called.

So, at work, for the typical Spring web applications we use Ant-based "common build" system originally created by the Spring guys. The common build uses ivy for the dependency resolution, so we have a custom ivyconf.xml which contains definitions for our local dependency repository, etc.

Grails has an ivy plugin, but when installing it for each web app, it puts the default ivyconf.xml into the root of the web app. So, I needed a way to 'tap' into the _Install.groovy script of the plugin to copy our local invyconf.xml. Sure enough the script 'statusUpdate' hook did the trick.

Here is the Events.groovy:


static final ESS_IVYCONF_FILE_LOCATION = "$userHome/.common-build/ntg/common-build"

eventStatusUpdate = { msg ->
if(msg ==~ /.*ivyconf.xml.*/) {
println "Copying ESS ivyconf.xml from common-build global directory ..."
Ant.copy(todir: "${basedir}", overwrite: true) {
fileset(dir: "$ESS_IVYCONF_FILE_LOCATION") {
include(name: "ivyconf.xml")
}
}
}
}


Later...

Plugins for local needs

The Grails plugin system is great not only for creating all kinds of useful functionality available publicly, but also is a perfect framework to extract bits and pieces of reusable logic suitable only for internal corporate projects.

At our organization we started finally using Grails for internal projects. The first small web application was done in a matter of a few days. But then when it was time to package it up as a 'war', we had a little dilemma and that's where Grails plugin system came to the rescue.

In a nutshell, we use Spring Security (formerly known as ACEGI) together with JA-SIG Central Authentication Service, for all our auth/authz needs. For Grails applications, I did not choose Grails Acegi plugin as it does not seem to provide CAS authentication support (yet?). So we reverted back to good 'ol Spring resources.xml and dropped all the verbose Acegi bean definitions there (hopefully Spring Security 2 should reduce the 'configuration chaos' dramatically). Works just fine. But we have 3 "String" bean definitions there pertaining to CAS properties, such as 'casServiceUrlPrefix', 'casLoginUrl', and 'casValidateUrl'. So, for the typical Spring web app., we define those as JNDI-bound resources, like so:


<bean id="casServiceUrlPrefix" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName"><value>java:comp/env/casServiceUrlPrefix</value></property>
</bean>

<bean id="casLoginUrl" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName"><value>java:comp/env/casLoginUrl</value></property>
</bean>

<bean id="casValidateUrl" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName"><value>java:comp/env/casValidateUrl</value></property>
</bean>
So, when packaging application as a 'war' and deploying it to Tomcat, this is fine, but in the 'development' mode, in embedded Jetty, I would have liked to put this config somewhere else. Like conf/Config.groovy for example. That's where Grails plugin system came in, and with its wonderful SpringBeanBuilder I was able easily dynamically create those 3 bean definitions during assembly phase of the ApplicationContext, depending on the environment the application was running in.

Here's the plugin:


import grails.util.GrailsUtil as GU
import org.springframework.jndi.JndiObjectFactoryBean

class CasPropertiesResolverGrailsPlugin {
def version = 0.1
def author = "Dmitriy Kopylenko"
def title = "This plugin is used to provide cas related properties to the Spring beans used for Spring Security config"
def description = ''' The plugin participates in the creation phase of the Spring application context
which is used to configure Spring Security related beans and dynamically provides
'configuration beans' namely 'casServiceUrlPrefix', 'casLoginUrl', and 'casValidateUrl'
depending on the environment in which Grails application is preparing to run.

More specifically, if the environment is 'development' then the value is sourced from
Grails Config instance. On the other hand, if the environment is 'production', the value
is sourced from standard ess JNDI namespace.
'''

def dependsOn = [:]

def doWithSpring = {
switch (GU.environment) {
case 'development':
casServiceUrlPrefix(java.lang.String, application.config.casServiceUrlPrefix)
casLoginUrl(java.lang.String, application.config.casLoginUrl)
casValidateUrl(java.lang.String, application.config.casValidateUrl)
break
case 'production':
casServiceUrlPrefix(JndiObjectFactoryBean) {
jndiName = 'java:comp/env/casServiceUrlPrefix'
}
casLoginUrl(JndiObjectFactoryBean) {
jndiName = 'java:comp/env/casLoginUrl'
}
casValidateUrl(JndiObjectFactoryBean) {
jndiName = 'java:comp/env/casValidateUrl'
}
break
}
}
...

I'm sure there are other ways to do this, but that was fun nevertheless :-)

Later...

Tuesday, February 5, 2008

Grails 1.0 is golden!

Yes, after more than 2 years in the making, with the development team hard at work, the Grails 1.0 final has been officially released. IMO, this event is historical and a great milestone for "lightweight" web development on the JVM platform.

Happy Grails hacking!

Later...

Saturday, December 15, 2007

Fetch random GORM model

Despite busy schedule at work and a year old daughter at home, who now requires constant attention, I was able to get some time to work on the Grails community site (Grails Crowd).

As a part of it, I wanted to have a feature to display a 'random' user (a 'member') In fact, keep displaying a random user as long as 'Discover users' link is being clicked. You know, kind of like Flickr's "Explore" feature. So with a help of standard JDK library features i.e. 'java.utils.Collections.shuffle()' and Groovy closures, here's what I've come up with:

MemberController's action:


...

def findRandom = {
def member = null

withMemberIds { memberIds ->
//Pick the last one
member = Member.get(memberIds[-1])
//Then remove it from the list
memberIds.pop()
}

if(member) {
render(view: 'discover', model: [member: member])
}
else {
//No one is registered yet - just 'go home'
redirect(uri:'/')
}
}

private def withMemberIds(closure) {
def memberIds = session.memberIds
if (!memberIds) {
memberIds = Member.withCriteria {
projections {
property('id')
}
}
if (!memberIds.isEmpty()) {
//Some members are in the database:
//Shuffle 'em up
Collections.shuffle(memberIds)
session.memberIds = memberIds
}
else {
//No members are in the database
return
}
}
closure(memberIds)
if (memberIds.isEmpty()) {
session.memberIds == null
}
}

...



It works like a charm.

Later...

Friday, December 7, 2007

Why Grails is so 'close to home'

Here's another [big] reason why Grails is not a "foreign" technology for Java developers. I know, it's been said before, but this is a real world example of a Java person coming to Grails and experiencing this familiar state of things: 1) Create war; 2) Drop into any of the available Java Servlet container/app server 3) Sit back and relax (in the ideal world) :-)

I'm not sure if the same is true for JRuby (On Rails), so I'm not going to speculate here ;-)

Later...

Sunday, May 20, 2007

Could it be any easier?

Well here I am again, on the second week of development of my Grails based 'addictive time waster' web2.0 site (I'm not rushing and spend may be an hour a day on it). As I described in the previous post, I was having a blast with Grails custom codecs feature which enables adding various 'encoding/transformation' features to any arbitrary Java types with ease! Well, I'm continuing "abusing" custom codecs with a great level of success and most importantly with a lot of fun.

As I noticed on almost all of those user generated content web2.0 style sites, there are some kind of a 'Submitted by: user234 x days ago type of a piece of info. So, I've decided to add 'time ago' type of a stat to my web app. I'll continue to show the 'Submission' class for the examples, representing user's submission of any kind. So in order to track when Submissions are created, I've added a 'createdOn' property:


class Submission {

...
Date createdOn = new Date()
...
}


That will take care of recording the date of submission. Now, when retrieving and showing the the submissions, there would need to be some kind of a calculation to show the 'x minutes/hours/days/weeks/months/years ago' info. So, I've decided to "abuse" the codecs feature and "attach" the "encoding" of the date type into the 'time ago' string to the java.util.Date type. Thanks to the "richness" of the Joda time library, I was able to do that easily and put the code into the custom codec:


import org.joda.time.*

class TimeAgoStringCodec {

static encode = { date ->
def start = new DateTime(date)
def end = new DateTime(new Date())
def ago = Minutes.minutesBetween(start, end).getMinutes()
if(ago == 0) {
return 'less then 1 minute ago'
}
else if(ago < 60) {
return "$ago minute" + (ago > 1 ? "s ago" : " ago")
}

ago = Hours.hoursBetween(start, end).getHours()
if(ago < 24) {
return "$ago hour" + (ago > 1 ? "s ago" : " ago")
}
ago = Days.daysBetween(start, end).getDays()
if(ago < 7) {
return "$ago day" + (ago > 1 ? "s ago" : " ago")
}
ago = Weeks.weeksBetween(start, end).getWeeks()
if(ago < 4) {
return "$ago week" + (ago > 1 ? "s ago" : " ago")
}
ago = Months.monthsBetween(start, end).getMonths()
if(ago < 12) {
return "$ago month" + (ago > 1 ? "s ago" : " ago")
}
ago = Years.yearsBetween(start, end).getYears()
return "$ago year" + (ago > 1 ? "s ago" : " ago")
}
}


And equipped with this codec, I am then able to call: submission.createdOn.encodeAsTimeAgoString() and viola, I have the proper 'time ago' for any Date type application-wide!

Here I could conclude that adding 'codecs' to any arbitrary Java type application-wide is piece of cake in Grails, and also here is a great example of the advantage of Groovy's seamless integration with "raw Java" where I was able to make use of an existing Java library (Joda time) with zero integration overhead.

Later...

Sunday, May 13, 2007

Permalink codec

So, for about a week I've been working on my fun little "social" Grails web application and I've been having a lot of fun.

Yesterday, while jyting I've been taking a note of its URL structure. Let's say you have a claim, and then in order to see it, the URL to it is not something like http://jyte.com/claim/show/12345 , but rather more readable, like http://jyte.com/cl/dima767.myopenid.com-is-the-only-grails-hacker-on-jyte

That's called "permalink" (for permanent link) and is done by converting the text of the claim (or any user submition for that matter) into permalink string (removing all the special characters e.g. \W, and replacing them with '-'). Then permalink essentially becomes a searchable attribute of the submission, so instead of doing something like Claim.get(1234) you do Claim.findByPermalink(params.permalink). It's just a way of creating "user friendlier" interfaces.

Thanks to Grails and its nice custom URL mapping, and custom codecs facility, I was able to implement "permalink" functionality very easily!

Lets' say I have a domain class "Submission":


class Submission {
String title

//permalink property here is for nicer URLs
String permalink

}


So then I simply create "PermalinkCodec" utility class and place it in grails-app/utils so the Grails "ExpandoMetaClass" machinery could "weave" this functionality into all Strings!


class PermalinkCodec {

static encode = { str ->
str.toLowerCase().replaceAll(/\W/,'-')
}
}


Then in my "SubmissionController's" "save" action I do something like this:


...
def save = {
def s = new Submission()
s.properties = params
s.permalink = params.title.encodeAsPermalink()
s.save()
...
}


And finally, i define the custom mapping:


class MyAppUrlMappings {
static mappings = {
...
"/s/$permalink" {
controller = 'submission'
action = 'show'
}
...
}
}


So this will give users nice URLs like http://myapp/s/my-shiny-and-the-best-in-the-world-submission instead of http://myapp/submission/show/1234

I think it's a little thing, but nice, nevertheless.

Later...

Thursday, February 22, 2007

Grails will survive

Some people have an opinion that Grails will fail. I have an opposite opinion that Grails will "survive".

Later...

Wednesday, January 24, 2007

Philadelphia SPUG

Yesterday I went to the Philadelphia's Spring user group meeting with two of my colleagues, where Thomas Risberg presented "using Groovy with Spring" (using Spring 2 dynamic language support) and Jason Rudolph of Grails fame presented "An introduction to Grails"

Thomas showed the arbitrary Spring web app with Controller implemented in Groovy and seamlessly integrated with the rest of the app e.g. dependency injected, etc. This is really cool integration and I'm definitely going to explore it by slowly introducing some Groovy bits and pieces into our existing Spring apps by perhaps implementing some Services in Groovy (where it makes sense of course) to do things much more expressively and naturally :-) One such example would be the XML parsing (agrrrrr) with Groovy's excellent XML support i.e. XmlSlurper, GPath, etc.

Then Jason did an excellent job of introducing Grails to the audience. I felt that the presentation was very fresh, dynamic and not boring. Jason used a "live coding" demo, where he coded from scratch the basic "Racetrack" application (from his "Getting started with Grails book") before our eyes. Nice job Jason! I might even steal his presentation to do it at our internal "Design and Development" meeting to introduce it to our development crowd.

And also I've won a copy of an excellent and much anticipated "Groovy in Action" book! The only caveat is that I've ordered that book from Amazon a couple of weeks ago and it actually arrived last night :-( So this one will go to our "Development library" at work to educate other developers about this excellent language.

I am very excited about Groovy and Grails development and the growing momentum it has. And I sure hope to see Grails applications being developed and deployed at our enterprise some time in 2007!

Later...