Monday, 11 February 2008

My first Grails plugin

The grails plugin architecture it's fantastic, I've spent one afternoon doing a static content plugin, yeah there is a oficial static plugin, but I use jetty for development and production, and the static content it's uploaded by the users.
With Jetty servlet to server static content is enought for me, and with some configuration parameters, if required can be disabled.

Another advantage is that this way you can protect your static content with the Acegi plugin.

The first step it's create plugin:
grails create-plugin jettystatic
The project looks like a normal grails project, excepts that you have a plugin descriptor file.
In the JettystaticGrailsPlugin.groovy I've updated the web.xml generated:

def doWithWebDescriptor = { webXml ->
log.info "Jetty Static Initializing servlet"
def dir = application.config?.jettystatic.dir
if(!dir){
dir = './static'
}

if(application.config?.jettystatic.ignore){
log.info "Jetty Static: No jetty static servlet inicialized"
return
}

log.info "Jetty Static dir '${dir}' and mapping '${mapping}'"
def mapping = '/resources/*'
def servlets = webXml.'servlet'

servlets[servlets.size()-1] + {
'servlet' {
log.info 'Jetty Static generating <servlet> for static content'

'servlet-name'("jettystatic")
'servlet-class'("org.mortbay.jetty.servlet.DefaultServlet")

'init-param' {
'param-name'("resourceBase")
'param-value'(dir)
}

'init-param' {
'param-name'("dirAllowed")
'param-value'("false")
}

'init-param' {
'param-name'("gzip")
'param-value'("true")
}

'load-on-startup'("1")
}
}

def mappings = webXml.'servlet-mapping'
mappings[mappings.size()-1] + {
'servlet-mapping' {
'servlet-name'("jettystatic")
'url-pattern'(mapping)
}
}
}
The other thing I need, is a taglib to make links to static content, and I'd like that the tag transform from absolute path of static content to a relative web path, this make easy upload content, and server the content uploaded.

def resource = {attrs ->
def url = grailsApplication.config?.jettystatic.absolute.url
def dir = grailsApplication.config?.jettystatic.basepath
def file = attrs.file
def baseUrl = ""

if(dir){
if(!dir.endsWith('/')){
dir = dir + '/'
}
file = file.replaceFirst(dir,"")
}
if(url){
baseUrl = url
}else{
baseUrl = g.createLinkTo(dir:'resources')
}

def env = GrailsUtil.environment
if(env && env == "development"){
baseUrl = g.createLinkTo(dir:'resources')
}


if(!baseUrl.endsWith('/')){
baseUrl = baseUrl + '/'
}
out<< "${baseUrl}${file}"
}
At this point the only thing I have to do is package my plugin (grails package-plugin) to use in any project.

I can't imagine doing something like this in java and spend this time.

Wednesday, 30 January 2008

Grails: Tag for Prototype observe

Continuing with Grails taglib, now I'm going to do a taglib to easy capture and group javascript events. I'll use prototype element observe method. Here the code:


def observe = {attrs ->
if(!attrs.noScript){
out << '<script type="text/javascript">'
}
if(attrs.element && attrs.element instanceof String){
printObserve("\$('${attrs.element}')", attrs.event, attrs.function, out)
}
if(attrs.element && attrs.element instanceof List){
attrs.element.each{it -> printObserve("\$('${it}')", attrs.event, attrs.function, out)}
}
if(attrs.classes && attrs.classes instanceof String){
printObserveClass(attrs.classes, attrs.event, attrs.function, out)
}
if(attrs.classes && attrs.classes instanceof List){
attrs.classes.each{ it -> printObserveClass(it, attrs.event, attrs.function, out)}
}
if(!attrs.noScript){
out << '</script>'
}
}

def printObserveClass(className, event, function, out){
out << "var classes = \$\$('.' + '${className}');"
out << "for(i = 0; i < classes.length; i++) {"
printObserve("classes[i]", event, function, out)
out << "}"
}

def printObserve(element, event, function, out){
if(event && event instanceof String){
out << "${element}.observe('${event}', ${function});"
}
if(event && event instanceof List){
attrs.event.each{ it -> out << "${element}.observe('${it}', ${function});"}
}
}




Now, some examples.

Simple use:

<g:javascript>
function testing(event){event.stop();alert('hello');}
</g:javascript>

<a id="idTest" href="http://grails.org">Grails Rulez</a>

<g:observe element="idTest" event="click" function="testing"/>


With a list of elements:

<g:observe element="${['id1','id2','id3']}" event="click" function="testing"/>


With a list of events:

<g:observe element="${['id1','id2','id3']}" event="${['click','load']}" function="testing"/>


With a list of classes:

<g:observe element="${['id1','id2']}" classes="${['class1','class2']}" event="change" function="testing"/>

Sunday, 27 January 2008

Grails: Easy tags (remoteDiv)

TagLibs in Grails are extremely easy, you have some tags for Ajax like remoteField, remoteFuntion, remoteLink. But this time I need to get div asynchronous when page loads, this is very useful for example to show the users connected.

There isn't remoteDiv tag in Grails but in five minutes I've got my tag:


def remoteDiv = { attrs,body ->
def complete = ""
if(attrs.onComplete){
complete = ",onComplete: ${attrs.onComplete}"
}

out << """
<script type="text/javascript">
new Ajax.Updater(
{ success: '${attrs.id}' },
'${attrs.url}',
{
method: 'get',
evalScripts: true
${complete}
});
</script>
"""
}


An example of use:

<div id="testAjax"></div>
<g:remoteDiv
id="testAjax"
url="${createLink(action: 'show', id:'1')}"
onComplete="new Effect.Highlight('testAjax')"
/>


I've use prototype AjaxUpdater to do asynchronous request, it's not library agnostic like others remote tags in Grails but it's simple :D

Saturday, 19 January 2008

Grails, be agile my friend

This month I've been testing Grails, (it was in my Todo list some time ago).
First I've read some about Groovy, and it's really easy the syntax and I like it.

Then, I've read about Grails architecture and the User Guide.

Impressions.


My impresion it's Grails is not much diferent than Appfuse, step by step:
  • GORM and Domain Model, is based in JPA and Hibernate. (domain centric approach explained by icoloma)
  • Controllers are based in Spring MVC.
  • IoC with Spring (of course).
  • Layouts based in Sitemesh.
  • Also you have Web Flow with Spring Web Flow.
  • Both are a simple WAR file.
This similars are very good for me, because I'm an old user of Appfuse and maybe can adapt Appfuse applications to Grails, I and can achive more agility.

Enterprise Ready?

Graeme Rocher gave a kick ass to someone that say no :D. I think it's ready, you have to take care about your code like in any other language.

The only thing I miss, is better support for Groovy and GSP in Eclipse (autocompletion, refactor) and manage the dependencies.

update: Guillaume Laforge thoughts about Enterprise Ready

Sunday, 2 December 2007

Notification area with Scriptaculous

This time I need a notification area in webapp, the idea is a div that appears and disappears.

In Scriptaculous it's easy extend and combine effects, and the first I do is extend an Effect to do the behavior that I'm looking for.

Effect.Notify = function(element) {
element = $(element);
return new Effect.Appear(element,
{ afterFinishInternal: function(effect) {
new Effect.Fade(effect.element,{ delay: 1.6 });
}});
}


The only thing you have to do is create a "div" with style "display: none" and invoke the Effect like this:


new Effect.Notify('mydiv');


Simple and powerful.

Monday, 12 November 2007

AjaxForm class for prototype

Some weeks ago an old mate asked to me the best way to send a form in ajax style and put the result in "div". I think the best way is using prototype javascript framework.
For one project I did a AjaxForm class, it based in an Ajax example of Spring Web Flow.

Here the class:

var AjaxForm = Class.create();
AjaxForm.prototype = {
initialize: function(formElementId) {
this.formElementId = formElementId;
Event.observe(formElementId, 'submit', this.handleSubmitEvent.bindAsEventListener(this), false);
},

handleSubmitEvent: function(event){
var formElement = $(this.formElementId);
if (formElement.tagName.toLowerCase() != 'form') {
throw 'Element ' + formElement + ' is not a FORM element!';
}
var method = formElement.method;
if (method == null) {
method = 'get';
}
var url = formElement.action;
if (url == null) {
throw 'No action defined on ' + formElement;
}
try {
Event.stop(event);
showLoadInfo(formElement);
var params = Form.serialize(formElement, true);

var myRequest = new Ajax.Updater(
{ success: formElement.parentNode },
url,
{
method: method,
parameters: params,
evalScripts: true,
onFailure: errFunc
});
} finally {
return false;
}
}
};


To use this class is very simple, you have to wrapper the form with a div, and create a new AjaxForm, like this example:

<div id="wrapperForm">
<form id="myAjaxForm" action="/dosomething">
...
...
</form>
</div>

<script type="text/javascript">
// <![CDATA[
new AjaxForm('myAjaxForm');
// ]]>
</script>


The result of the post is put in div "wrapperForm". It's fantastic because doesn't break the MVC, remember disable decorators or tiles in the result page, because the result is in the div, not in the page.

I have to update the syntax of AjaxForm class to prototype 1.6, but for example is good enought.

Saturday, 10 November 2007

Compass or Hibernate Search

Compass and Hibernate Search are two frameworks to provide full text search engine to your apps.
Which one to choose? This is a large discussion between Emmanuel Bernard (Hibernate) and Shay Banon (Compass), my conclusion is that both are really good.
Yeah, both are really good but I have to choose one, and I choose Hibernate Search, here my reasons.
  • I use Hibernate API with JPA annotations and similar API seems more natural, to learn and understand.
  • Minimal configuration. I only have to put two properties in the config.
  • All of my searchable data are in database.
  • I think the Hibernate Search annotations fits better with JPA annotations.
  • And the last, Hibernate Search is in maven repository (Compass no).
If I used Ibatis or JDBC directly, I'd choose Compass.
Maybe, if I had many searchable data, that aren't in database I'd choose Compass too.

Monday, 1 October 2007

Saving the last time login with Acegi Security

This time, I'm going to explain how to save the last login time of user with Acegi Security for Spring.
It's really easy, due to Acegi publishes an autentication event in the Spring ApplicationContext (documentation about publish/suscribe events).

I have to create a simple class that implements ApplicationListener.

public class LastLoginListener implements ApplicationListener {

private UserManager userManager;

// getter and setter ...

public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof AbstractAuthenticationEvent) {

if (event instanceof AbstractAuthenticationFailureEvent) {
// log or similar
}

if ( event instanceof AuthenticationSuccessEvent ){
AuthenticationSuccessEvent authenticationSuccessEvent = ( AuthenticationSuccessEvent ) event;
String username = authenticationSuccessEvent.getAuthentication().getName();
User user = userManager.getUserByUsername(username);
user.setLastLogin(new Date());
userManager.saveUser(user);
}

}
}

}


In the method "onApplicationEvent" I listen the event AbstractAuthenticationEvent, that Acegi publishes.
Next, I update the last login time, with the userManager.

The last step is setup my LastLoginListener in security.xml with the other Acegi beans.

<bean id="lastLoginListener" class="net.dahernan.common.security.LastLoginListener">
<property name="userManager" ref="userManager"/>
</bean>

Sunday, 16 September 2007

Tip: Put result in session in Spring Web Flow

So, another tip with Spring Web Flow. Sometimes it's necessary put a result of bean-action in scope session, but in SWF 1.X doesn't have this feature, but you can make a simple action to do the work.

First, the flow definition:

<action-state id="saveProject">
<bean-action bean="projectManager" method="save">
<method-arguments>
<argument expression="flowScope.project" />
</method-arguments>
<method-result name="project" scope="request"/>
</bean-action>
<transition on="success" to="putInSession" />
</action-state>

<action-state id="putInSession">
<action bean="putInSessionAction">
<attribute name="sessionKey" value="project" />
</action>
<transition on="success" to="finish"/>
</action-state>


I call a bean-action "saveProject" and I put the result in request with key "project". Next, I execute the action "putInSession" and I set the attribute "sessionKey" with the value of the key "project", this mean thay the object to save in session is in the request with this key.

With this convention, here the Action implementation:

public class PutInSessionAction implements Action{

public Event execute(RequestContext context) throws Exception {

String key = (String) context.getAttributes().get("sessionKey");
Object value = context.getRequestScope().get(key);
context.getExternalContext().getSessionMap().put(key, value);

return new Event(this, "success");
}

}


This simple Action gets the object from the request and puts in session.

Sunday, 2 September 2007

Tip: Output a success message in a subflow in Spring Web Flow

In Ajax applications is common output a success or error message (like Google Mail interface). With Spring Web Flow I can define subflows to do commons things and reuse parts of the application but if I want to output a success message, the natural way it's to define a view state.

This tip shows other way to output a message.

I have a subflow to add a new company.

<start-state idref="enterCompanyData"/>

<view-state id="enterCompanyData" view="people/ajax/company_add">
<render-actions>
<action bean="formAction" method="setupForm" />
</render-actions>
<transition on="submit" to="saveCompany">
<action bean="formAction" method="bindAndValidate" />
</transition>
</view-state>

<action-state id="saveCompany">
<bean-action bean="companyManager" method="save">
<method-arguments>
<argument expression="flowScope.company" />
</method-arguments>
</bean-action>
<transition on="success" to="finish">
<set attribute="message" value="'company.addCompany.success'" />
</transition>
</action-state>

<end-state id="finish">
<output-mapper>
<mapping source="requestScope.message" target="message" />
</output-mapper>
</end-state>


When I save a company in the action state "saveCompany", I set an atttibute named "message" with a value of String 'company.addCompany.success' (with a single quotes, otherwise the expression language thinks that is a Java Bean), this value is a key for i18n.

In the end state "finish", I have to map the attribute message to the output.

Next, in the root flow, I have to capture the message and put in the flash scope.

<subflow-state id="companyAdd" flow="company-add-flow"> 
<attribute-mapper>
<output-mapper>
<mapping source="message" target="flashScope.message"/>
</output-mapper>
</attribute-mapper>
<transition on="finish" to="companyList" />
</subflow-state>


Putting the message in the flash scope, allow to view the message until next event.

And the last step is show the message in JSP, you have to include this code, in all view states.

<c:if test="${not empty message}">
<fmt:message key="${message}"/>
</c:if>