Java programmer since 1996. J2SE, J2EE Expert, Technical Leader, Team Manager. Rich experience in infrastructure and architecture of distributed applications Pavel has posted 6 posts at DZone. You can read more from them at their website. View Full User Profile

Web Applications Development with Gaelyk

12.10.2012
| 4324 views |
  • submit to reddit

For a long time I wondered this: what is the best framework for small, experimental web applications?

I've been a Java programmer since 1996, and I can create a servlet or jsp with simple HTML, but I see a number of things as issues.

First of all - user management. Login / registration form, email etc   - I prefer to  spend as little time as possible on all those issues.

Second - hosting - Java hosting is expensive.

And finally I found a solution - it is Gaelyk: a Groovy framework for Google App Engine.

There are a number of ways to create simple Gaelyk project - you can download template project  and you can create a project using maven archetype, but both are using the standard groovy compiler (and not the eclipse groovy compiler).  Also, neither contain examples of object persistence.

So, I created my own maven archetype for Gaelyk. Let's use it to create a simple Gaelyk project:

mvn archetype:generate -DarchetypeGroupId=org.bernshtam -DarchetypeArtifactId=gaelyk-archetype -DarchetypeRepository=http://bernshtam.name/maven2 -DgroupId=myexample -DartifactId=test1 -DarchetypeVersion=1.0

Now you can import this project to Intellij IDEA.

After importing, do not forget to add App Engine facet to the project.  Now you can add a run configuration.

Pay attention, the Google App Engine development kit should be already installed and set in IDEA.

maven will bring the rest of the dependencies :) 

Let's run maven's "install" and ...

Now - launch! 

Yes! It is working! This is a simple application for the creation of notes with priority.

Let's look at the source code.

web.xml setup a servlet and filter for groovlets and templates (gtpl files)

<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
    <listener>
        <listener-class>groovyx.gaelyk.GaelykServletContextListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>GroovletServlet</servlet-name>
        <servlet-class>groovyx.gaelyk.GaelykServlet</servlet-class>
        <init-param>
            <param-name>verbose</param-name>
            <!-- Set it to true for more details -->
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet>
        <servlet-name>TemplateServlet</servlet-name>
        <servlet-class>groovyx.gaelyk.GaelykTemplateServlet</servlet-class>
        <init-param>
            <!-- Remove the default "generated by" messages from the templates -->
            <param-name>generated.by</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>verbose</param-name>
            <!-- Output generation time in the HTML, see source page -->
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <filter>
        <filter-name>RoutesFilter</filter-name>
        <filter-class>groovyx.gaelyk.routes.RoutesFilter</filter-class>
    </filter>

    <servlet-mapping>
        <servlet-name>GroovletServlet</servlet-name>
        <url-pattern>*.groovy</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>TemplateServlet</servlet-name>
        <url-pattern>*.gtpl</url-pattern>
    </servlet-mapping>

    <filter-mapping>
        <filter-name>RoutesFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <welcome-file-list>
        <welcome-file>index.gtpl</welcome-file>
    </welcome-file-list>
</web-app>

appengine-web.xml is a Google App Engine descriptor. You need to replace test1-archetype with the name of your app engine application (if you want to deploy it) and create this application in the App Engine console before you deploy.

 

<appengine-web-app xmlns="http://appengine.google.com/ns/1.0-SNAPSHOT">
    <application>test1-archetype</application>
    
    <version>1</version>

    <!-- Enable concurrent requests by default to serve requests in parallel -->
    <threadsafe>true</threadsafe>

    <!-- If all your templates and groovlets are encoding in UTF-8 -->
    <!-- Please specify the settings below, otherwise weird characters may appear in your templates -->
    <system-properties>
        <property name="file.encoding" value="UTF-8"/>
        <property name="groovy.source.encoding" value="UTF-8"/>
        <property name="java.util.logging.config.file" value="WEB-INF/logging.properties" />
    </system-properties>

    <!-- Uncomment this section if you want your application to be able to receive XMPP messages -->
    <!-- And create a file named jabber.groovy in /WEB-INF/groovy -->
    <!-- Similarily, if you want to receive incoming emails -->
    <!-- And create a file named email.groovy in /WEB-INF/groovy -->
    <!--
    <inbound-services>
        <service>xmpp_message</service>
        <service>mail</service>
    </inbound-services>
    -->

    <!-- It it advised to keep this parameter to true -->
    <!-- as per the release of SDK 1.2.8, -->
    <!-- this should speed up cold startups of applications by 10% -->
    <precompilation-enabled>true</precompilation-enabled>
    
    <static-files>
        <exclude path="/WEB-INF/**.groovy" />
        <exclude path="**.gtpl" />
    </static-files>
</appengine-web-app>

Now Gaelyk specific stuff. routes.groovy contains instructions on how to redirect HTTP requests.

get "/", redirect: "listnotes.groovy"
get "/favicon.ico", redirect: "/images/favicon.png"

Gaelyk is an MVC framework, so most requests will be forwarded to controllers, whose role in Gaelyk plays groovlets. You can see a full description of routes.groovy DSL here .

Let's look now to the class Note:

package myexample

import groovyx.gaelyk.datastore.Entity
import groovyx.gaelyk.datastore.Key
import groovyx.gaelyk.datastore.Unindexed

@Entity(unindexed=false)
class Note {
    @Key long id
    String login
    @Unindexed int priority
    String text
}

By default, Gaelyk offers you very simple integration with Google App Engine Datastore. It is not real ORM, not JPA, but you can use it for simple applications.

Let's see examples from this application controller:

Note  note = new Note(priority:priority, text: text, login: email)
note.save()
...

def  note = Note.get(id)
note.delete()
..
def notes = Note.findAll { login == email }


Nice :) Isn't it?

Now let's look to variables user, request and log.

def email = user.email
...
log.fine("$notes ${notes.size()}")
...
String text = request.getParameter("text")

Those variables are not defined there. They are injected. user will contain null if a user is not logged in and will contain user details otherwise. log contains a logger and request contains HttpRequest object.

You will be excited by how many variables are automatically injected  into Gaelyk controllers, templates (and, if you wish, any other classes)

The model is passed from a controller to a view by request object properties:

request['notes'] = notes
forward "index.gtpl"

Templates are the last thing to see. They looks like jsp, contains % include % directives and code snippets.

<% include '/WEB-INF/includes/header.gtpl' %>

<h1>My notes</h1>

<% if (user) { %>
    <p>



            <table width="50%" border="1">
                <tr><th width="30%">Note</th><th>Priority</th><th></th></tr>
                    <% request.notes.each { note -> %>
                        <tr><td>${note.text}</td><td align="left"> ${note.priority}</td><td><A href="deletenote.groovy?id=${note.id}">X</A> </td></tr>
                    <% } %>
            </table>


    </p>
    <div class="add">
    <h2>Add a new note</h2>
    <p>
    <form name="addnote" action="addnote.groovy" method="post">

    Priority: <input name="priority" id="priority" type="number" value="1" min="1" max="10"/><br/> <br/>
    Text: <input name="text" id="text" type="text"/>
    <input type="submit" value=" Add Note "/></form>
    </p>
    </div>
    <% } else { %>
    <p><A href="${users.createLoginURL("/")}">Login</A> </p> to access your notes
<% } %>


<% include '/WEB-INF/includes/footer.gtpl' %>

 

Take a look how we check that a user logged in ( if (user) ...), how we retrive the mode ( request.notes.each ...), groovy style  of embedding variables ( ${note.priority} ), creation of login link ( ${users.createLoginURL("/")} - users is one more injected variable.

If you like Gaelyk - start by reading this tutorial!

Published at DZone with permission of its author, Pavel Bernshtam.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Vasia Pupkin replied on Tue, 2012/12/11 - 5:05am

Nice article, but I cannot see any advantages of this framework over Grails, Play Framework or Spring MVC. The only one advantage I found till now is <i>native</i> integration with Google App Engine - which from my point of view is clear disadvantage. 

фтопку 

Pavel Bernshtam replied on Tue, 2012/12/11 - 5:32am in response to: Vasia Pupkin

If you want free hosting for your java web app - you need use google app engine, I do not know other options.

Vasia Pupkin replied on Tue, 2012/12/11 - 7:21am in response to: Pavel Bernshtam

Play Framework comes with built-in support of Heroku. The demo application that comes with tutorial, actually creates the same "Notes" application and deploys it through git on Heroku. The main differences between Play and this one - a) support in Java language, b) popularity and exciting community of the Play Framework. 

Amazon EC2 micro edition could be evaluated during one year - you can install there whatever you wish.


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.