Loading...

Tuesday, April 28, 2009

Escaping quotes in Groovy strings

Groovy supports strings enclosed in single or double quotes and between slashes. If we use single quotes we don't have to escape double quotes. And if we use double quotes we don't have to escape single quotes. We can use the slashes if we have a string with both double and single quotes and we don't want to escape them.

def singleQuote = 'Single quote string to "demo" double quotes without backslash escape.'
def doubleQuote = "Double quote string let's us use single quote without backslash escape."
def slashy = /Slashy string let's us use single and "double" quotes without backslash escapes./

println singleQuote
println doubleQuote
println slashy

When we run this Groovy script we get the following output:

Single quote string to "demo" double quotes without backslash escape.
Double quote string let's us use single quote without backslash escape.
Slashy string let's us use single and "double" quotes without backslash escapes.

Wednesday, April 22, 2009

Google Analytics API released

Google has released the Google Analytics API in Google Labs. With the API we can access the Google Analytics data from our own programs. This makes the solution described in Handle Google Analytics scheduled e-mail reports with Apache Camel and Groovy and Handle Google Analytics scheduled e-mail reports with Apache James obsolete.

Friday, April 17, 2009

Send mail with Apache Camel from Grails

We have seen how to use a Grails service in a Camel route, but the Apache Camel plugin also allows us to send messages to a Camel route. We can use the sendMessage method in our controllers and services. We define the starting point of the route and a message object and we can send it.

For our example we are going to send an e-mail message from a controller. We are using a fire-and-forget method, so we can immediatelly return to the web page and we don't have to wait until the mail communication is finished. Let's start with a Grails application:

$ grails create-app sendmail
$ cd sendmail
$ grails install-plugin camel

Next we create a controller which will create and send a message to a Camel route:

$ grails create-controller mail

We open the MailController in an editor and add a mail closure. Here we get the values from the request parameters name and email (the web page with a form and two input fields name and email is created next). We invoke the sendMessage method to send a map message to the route starting point seda:mailQueue. The SEDA component from Apache Camel allows asynchronuous communication, so we immediatelly return to our controller after the message is sent. To get more robust asynchronuous communication we could use for example ActiveMQ. Finally we return to the web page with a flash message we can display.

class MailController {
    def mail = {
        if (params.name != null && params.email != null) {
            sendMessage "seda:mailQueue", [name: params.name, email: params.email]
            flash.message = "Check your e-mail for new messages."
        }
    }
}

The controller will look for a file grails-app/views/mail/mail.gsp to display a web page. So let's create it. The page only needs a form with input fields for name and e-mail:

<%@ page contentType="text/html;charset=UTF-8" %>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Mail with Apache Camel and Grails</title>
  </head>
  <body>
    <h1>Mail with Apache Camel</h1>
    <g:if test="${flash.message}">
      <div class="message">${flash.message}</div>
    </g:if>
    <g:form method="POST">
      Name: <g:textField name="name"/><br />
      E-mail: <g:textField name="email"/><br />
      <g:submitButton name="submit" value="Send mail"/>
    </g:form>
</body>
</html>

Okay we have created the controller and web page. Next we create the Camel route:

$ grails create-route mail

The route will listen with the SEDA component for incoming messages. The message contains a map with the name and e-mail values. We use these values to create the content of an e-mail message. The content is HTML so we can show off Groovy's builder support. We also define the subject, to and from headers of the e-mail message. Then we use Camel's mail component to send the e-mail via SMTP.

import org.codehaus.groovy.grails.commons.*

class MailRoute {
    def configure = {
        def config = ConfigurationHolder.config

        from("seda:mailQueue")
        .process {
            def name = it.in.body.name
            def to = it.in.body.email
            def html = new groovy.xml.StreamingMarkupBuilder().bind {
                html {
                    body {
                        p "${name},"
                        p {
                            mkp.yield "Thank you for your interest in "
                            a href:'http://camel.apache.org', "Apache Camel"
                            mkp.yield "."
                        }
                        p {
                            i "P.S. Grails rocks"
                        }
                    }
                }
            }
            it.out.setBody html.toString()
            it.out.setHeader "to", to
            it.out.setHeader "from", "h.kleinikkink@gmail.com"
            it.out.setHeader "subject", "Mail sent from Apache Camel"
        }
        .to("smtps://smtp.gmail.com?username=${config.smtps.user}&password=${config.smtps.password}&contentType=text/html")
    }
}

The Camel mail component has a dependeny on the JavaMail API libraries. We must download the libraries and add them to our lib directory. Or we can install the Grails mail plugin, which contains the JavaMail API libraries already. This way the libraries are automatically added to our application. (grails install-plugin mail)

And we are done. We can run our application and start sending e-mails:

$ grails run-app

Notice how the web page returns immediatelly after we submit the form, because of the asynchronuous SEDA component.

Tuesday, April 14, 2009

Go full screen with NetBeans

When we want to get the most of our big, high resolution screens in Windows we can maximize the NetBeans window. But this will still leave the title bar on the screen, so to really use all of the screen we can run NetBeans in full screen mode. We go to View | Full Screen (or use Alt+Shift+ENTER in Windows) and NetBeans goes full screen. The title bar is now gone. And if we go to Window | Maximize Window (or use Shift+ESC in Windows) we can maximize the editor window to get a big editing space:

Monday, April 13, 2009

Unit testing constraints in domain object in Grails

We can unit test constraints in domain objects with the mockForConstraintsTests(domainClass) method. This will add a validate() method to our domain class. Normally the validate() is dynamically added to our domain class when we run our Grails application. But with the mockForConstraintsTests(domainClass) method we can use it without running a complete Grails application.

Suppose we have the following domain class with a lot of constraints defined for the different properties:

package com.mrhaki.grails.unittest

class User {

    static constraints = {
        name       blank: false, maxSize: 40, notEqual: 'testEquals'
        nickName   blank: false, unique: true, minSize: 4, maxSize: 20,
                   validator: {
                       if (it == 'groovy') {
                           ['invalid.groovyness']
                       }
                   }
        avatar     nullable: true, validator: {val, obj ->
                       if (val != null) {
                           val != obj.name
                       }
                   }
        creditCard nullable: true, creditCard: true
        email      nullable: true, email: true, matches: /.*\.nl$/
        type       nullable: false, inList: ['Admin', 'User']
        points     nullable: true, max: 1000, min: 100
        age        nullable: true, range: 12..120
        blogURL    nullable: true, url: true
        extra      nullable: true, size: 4..25
    }

    String name
    String nickName
    String avatar
    String creditCard
    String email
    String type
    Integer points
    Integer age
    String blogURL
    String extra
}

To unit test the constraints we can simply write a unit test class which extends from GrailsUnitTestCase. Then we must invoke mockForConstraintsTests(User) so the validate() method is added to our user class. Next we can set values for the properties and test if the validation succeeds or fails. We run the tests with the following grails command:

grails test-app -unit

Here is the code for the unit test class:

package com.mrhaki.grails.unittest

import grails.test.*

class UserTests extends GrailsUnitTestCase {

    def user

    protected void setUp() {
        super.setUp()
        // Make sure we can invoke validate() on our User domain object.
        mockForConstraintsTests(User)
        // Set up default user, so we can easily test single properties.
        user = new User(name: 'test', nickName: 'tester', type: 'User')
    }

    /**
     * class User{
     *     ...
     *     nickName unique: true
     *     ...
     * }
     */
    void testUnique() {
        // Test user to test uniqueness of nickName property.
        def test = new User(name: 'tester', nickName: 'tester', type: 'User')
        mockForConstraintsTests(User, [test])

        assertFalse user.validate()
        assertEquals 'Nickname is not unique.', 'unique', user.errors['nickName']

        user = new User(name: 'test', nickName: 'otherTester', type: 'User')
        assertTrue user.validate()
    }

    /**
     * class User {
     *     ...
     *     name notEqual: 'testEquals'
     *     ...
     * }
     */
    void testNotEqual() {
        user.name = 'testEquals'
        assertFalse user.validate()
        assertEquals 'Name is equal to testEquals.', 'notEqual', user.errors['name']

        user.name = 'test'
        assertTrue user.validate()
    }

    /**
     * class User {
     *     ...
     *     name blank: false
     *     nickName blank: false
     *     ...
     * }
     */
    void testBlank() {
        user = new User(name: '', nickName: '', type: 'Admin')
        assertFalse user.validate()
        assertEquals 'Name is blank.', 'blank', user.errors['name']
        assertEquals 'NickName is blank.', 'blank', user.errors['nickName']

        user = new User(name: 'test', nickName: 'tester', type: 'User')
        assertTrue user.validate()
    }

    /**
     * class User {
     *     ...
     *     avatar nullable: true
     *     creditCard nullable: true
     *     email nullable: true
     *     type nullable: false
     *     points nullable: true
     *     age nullable: true
     *     blogURL nullable: true
     *     extra nullable: true
     *     ...
     * }
     */
    void testNullable() {
        user = new User()
        assertFalse user.validate()
        assertEquals 'Name is null.', 'nullable', user.errors['name']
        assertEquals 'NickName is null', 'nullable', user.errors['nickName']
        assertNull user.errors['avatar']
        assertNull user.errors['creditcard']
        assertNull user.errors['email']
        assertEquals 'Type is null.', 'nullable', user.errors['type']
        assertNull user.errors['points']
        assertNull user.errors['age']
        assertNull user.errors['blogURL']
        assertNull user.errors['extra']
    }

    /**
     * class User {
     *     ...
     *     nickName minSize: 4
     *     ...
     * }
     */
    void testMinSize() {
        user = new User(name: 'test', nickName: 'tst', type: 'User')
        assertFalse user.validate();
        assertEquals 'NickName is not minSize 4.', 'minSize', user.errors['nickName']

        user.nickName = 'tester'
        assertTrue user.validate()
    }

    /**
     * class User {
     *     ...
     *     name maxSize: 40
     *     nickName maxSize: 20
     *     ...
     * }
     */
    void testMaxSize() {
        user.name = 'This name is just way longer than the maxSize argument defines.'
        user.nickName = 'The nickName is just too long, people will not remember this.'
        assertFalse user.validate()
        assertEquals 'Name is too long.', 'maxSize', user.errors['name']
        assertEquals 'NickName is too long.', 'maxSize', user.errors['nickName']

        user.name = 'Hubert Klein Ikkink'
        user.nickName = 'mrhaki'
        assertTrue user.validate()
    }

    /**
     * class User {
     *     ...
     *     email email: true
     *     ...
     * }
     */
    void testEmail() {
        user.email = 'test'
        assertFalse user.validate()
        assertEquals 'Not a valid email.', 'email', user.errors['email']

        user.email = 'valid@country.nl'
        assertTrue user.validate()
    }

    /**
     * class User {
     *     ...
     *     email matches: /.*\.nl$/
     *     ...
     * }
     */
    void testMatches() {
        user.email = 'test@country.com'
        assertFalse user.validate()
        assertEquals "Doesn't end with .nl.", 'matches', user.errors['email']

        user.email = 'test@country.nl'
        assertTrue user.validate()
    }

    /**
     * class User {
     *     ...
     *     creditCard creditCard: true
     *     ...
     * }
     */
    void testCreditCard() {
        user.creditCard = '1234512'
        assertFalse user.validate()
        assertEquals 'Not a valid creditcard#.', 'creditCard', user.errors['creditCard']
        
        user.creditCard = '4417123456789113'
        assertTrue user.validate()
    }

    /**
     * class User {
     *     ...
     *     type inList: ['Admin', 'User']
     *     ...
     * }
     */
    void testInList() {
        user.type = 'NotValid'
        assertFalse user.validate()
        assertEquals 'NotValid not in list for type.', 'inList', user.errors['type']

        user.type = 'user'
        assertFalse user.validate()
        assertEquals 'inType validator is case sensitive.', 'inList', user.errors['type']

        user.type = 'User'
        assertTrue user.validate()
    }

    /**
     * class User {
     *     ...
     *     points max: 1000
     *     ...
     * }
     */
    void testMax() {
        user.points = 20000
        assertFalse user.validate()
        assertEquals '20000 is above max for points.', 'max', user.errors['points']

        user.points = 900
        assertTrue user.validate()
    }

    /**
     * class User {
     *     ...
     *     points min: 100
     *     ...
     * }
     */
    void testMin() {
        user.points = 10
        assertFalse user.validate()
        assertEquals '10 is below min for points.', 'min', user.errors['points']

        user.points = 210
        assertTrue user.validate()
    }

    /**
     * class User {
     *     ...
     *     extra size: 4..25
     *     ...
     * }
     */
    void testSize() {
        user.extra = 'ab'
        assertFalse user.validate()
        assertEquals "'ab' size is below 4 for extra.", 'size', user.errors['extra']

        user.extra = 'This text is too long to be of the correct size.'
        assertFalse user.validate()
        assertEquals 'Text is longer than 25 for extra.', 'size', user.errors['extra']

        user.extra = 'This is the right length.'
        assertTrue user.validate()
    }

    /**
     * class User {
     *     ...
     *     age range: 12..120
     *     ...
     * }
     */
    void testRange() {
        user.age = 0
        assertFalse user.validate()
        assertEquals '0 is below range for age.', 'range', user.errors['age']

        user.age = 200
        assertFalse user.validate()
        assertEquals '200 is above range for age.', 'range', user.errors['age']

        user.age = 40
        assertTrue user.validate()
    }

    /**
     * class User {
     *     ...
     *     blogURL url: true
     *     ...
     * }
     */
    void testURL() {
        user.blogURL = 'invalid-url'
        assertFalse user.validate()
        assertEquals "'invalid-url' is not valid.", 'url', user.errors['blogURL']

        user.blogURL = 'http://www.mrhaki.com'
        assertTrue user.validate()
    }

    /**
     * class User {
     *     ...
     *     nickName validator: {
     *                 if (it == 'groovy') {
     *                     ['invalid.groovyness']
     *                 }
     *              }
     *     avatar validator: {val, obj ->
     *                 if (val != null) {
     *                     val != obj.name
     *                 }
     *            }
     *     ...
     * }
     */
    void testCustomValidator() {
        user.avatar = 'test'
        assertFalse user.validate()
        assertEquals "'test' is the same as name.", 'validator', user.errors['avatar']

        user.avatar = 'avatar-test'
        assertTrue user.validate()

        // Test custom error key.
        user.nickName = 'groovy'
        assertFalse user.validate()
        assertEquals "'groovy' not allowed as nickName.", 'invalid.groovyness', user.errors['nickName']

        user.nickName = 'tester'
        assertTrue user.validate()
    }
}

Thursday, April 9, 2009

Simple Logging Facade for Java (SLF4J) has nice template-like methods

The Simple Logging Facade for Java (SLF4J) library makes logging in Java code easy. We can use the facade and at deployment time decide to log using Log4j, java.util.logging or another framework. The library has a very nice feature called parameterized logging. Using parameterized logging we can increase logging performance for disabled logging statements.

This is best explained with an example:

String entry = "sample string";
if (logger.isDebugEnabled()) {
    logger.debug("We need to add logger.isDebugEnabled(), otherwise our logged " 
    + entry + " is contructed "
    + "by concatenating the String, even if debug logging is disabled.");
}

logger.debug("By using parameterized logging we can print entry:{} but we don't have the overhead of String concatenation if debug logging is disabled.", entry);

Wednesday, April 8, 2009

Groovy even makes database access easy

Sigh. Why is everything so easy in Groovy? I had a small request from a client to change a lot of database records. Now, I am no SQL guy, but I know Java and Groovy. So I wrote a little script to access the database and change the value of some records:

import groovy.sql.Sql

// Just copy mysql-connector.jar in $GROOVY_HOME/lib and we
// use the MySql driver.
def sql = Sql.newInstance("jdbc:mysql://localhost/db", "user",
                          "password", "com.mysql.jdbc.Driver")

// Make sure we can update the records.
sql.resultSetConcurrency = java.sql.ResultSet.CONCUR_UPDATABLE

sql.eachRow("select * from articles where description like '%IN STOCK%'") {
    println "Change record with id ${it.id}"
    it.description = it.description.substring(0, it.description.indexOf('IN STOCK'))
}

println "Done."

Find Grails files and types in NetBeans

We can search quickly for Groovy and resource files in our Grails application in NetBeans. We go to Navigate | Go to Type... or use the (Windows) shortcut key Ctrl+O. NetBeans opens a dialog in which we type the name of the Groovy type we are looking for. For example we can look for the file Config.groovy by typing the letters conf. We then select the found file and click on the OK button to open the file in NetBeans:

To search for other files in our Grails application we must go to Navigate | Go to File... or use the (Windows) shortcut key Alt+Shift+O. In this dialog window we can type part of the name of the file we are looking for. For example we can type in to search for the index.gsp file:

Monday, April 6, 2009

Poll for files and use a Grails service with Apache Camel

We have seen how easy it is to add Apache Camel with the Grails plugin to our Grails application. In this post we see how we can invoke a Grails service from a Camel route. We want to poll for new XML files placed in a directory and pass each file to a Grails service. In the Grails service we parse the XML and update our database with domain classes, because we have full access to all Grails artifacts.

The XML in the files is like this:

<?xml version="1.0" ?>
<AnalyticsReport>
    <Report name="Dashboard">
        <Title id="Title">
            <Detail></Detail>
            <Name>Dashboard</Name>
            <ProfileName>www.website.com</ProfileName>
        </Title>
        <Graph id="Graph">
            <XAxisTitle>Day</XAxisTitle>
            <Serie>
                <Label>Visits</Label>
                <Id>primary</Id>
                <ValueCategory>visits</ValueCategory>
                <Point>
                    <Value>20</Value>
                    <Label>Wednesday, March 4, 2009</Label>
                </Point>
                <Point>
                    <Value>22</Value>
                    <Label>Thursday, March 5, 2009</Label>
                </Point>
                <Point>
                    <Value>22</Value>
                    <Label>Friday, March 6, 2009</Label>
                </Point>
                <Point>
                    <Value>11</Value>
                    <Label>Saturday, March 7, 2009</Label>
                </Point>
                <Point>
                    <Value>42</Value>
                    <Label>Sunday, March 8, 2009</Label>
                </Point>
                <Point>
                    <Value>24</Value>
                    <Label>Monday, March 9, 2009</Label>
                </Point>
                <Point>
                    <Value>35</Value>
                    <Label>Tuesday, March 10, 2009</Label>
                </Point>
            </Serie>
        </Graph>
    </Report>
</AnalyticsReport>

Yes, it is part of the Google Analytics XML report. We are going to poll a directory to see if there are new files. If new files are placed in the directory we read the XML files from the directory and pass the file to the Grails service HandleReportService with the following Camel route:

import org.codehaus.groovy.grails.commons.*

class HandleReportRoute {
    def configure = {
        def config = ConfigurationHolder.config

        from("file://${config.camel.route.save.dir}")
        .to("bean:handleReportService?methodName=save")
    }
}

Notice at line 7 how we can use a Grails service in our route. We define the name of the service and the method name. Suppose for our example we use the domain classes WebsiteProfile and Visit which look like this:

class WebsiteProfile {
    static hasMany = [visits:Visit]
    String name
}
class Visit {
    static belongsTo = [profile:WebsiteProfile]
    Long numberOfVisits
    Date date
}

The Grails service has one argument which is the file object from our Camel route. We use the XmlSlurper to parse the XML from the file. We use data from the XML to create our domain objects and save them:

import java.text.SimpleDateFormat

class HandleReportService {

    boolean transactional = true

    def save(file) {
        // Default parser to read date formats from Google Analytics XML.
        def dateParser = new SimpleDateFormat("EEEE, MMMM ddd, yyyy", Locale.US)

        // Read the XML file.
        def report = new XmlSlurper().parse(file)

        final String name = report.Report.Title[0].ProfileName.text()

        // See if we already have a profile in the database.
        def profile = WebsiteProfile.findByName(name)
        if (!profile) {
            // No profile yet, so we create one here.
            profile = new WebsiteProfile(name: name)
            profile.save()
        }

        report.Report.Graph[0].Serie[0].Point.each {
            final Date date = dateParser.parse(it.Label.text())
            // See if we already saved the # of visits for the date and profile, 
            // if so we don't need to add another.
            if (!Visit.findByDateAndProfile(date, profile)) {
                final Integer counter = new Integer(it.Value.text())
                profile.addToVisits(new Visit(numberOfVisits: counter, date: date))
            }
        }
        profile.save()
    }
}

Sunday, April 5, 2009

Use Apache Camel plugin in Grails

We've learned how to use Apache Camel from Groovy code. In this post we learn how to use Apache Camel in a Grails application.

To include Apache Camel in a Grails application is so easy, thanks to the plugin system of Grails. We can install Camel with the Camel plugin. This plugin will add the Camel classes to our application, the possbility to send and route messages directly from services and controllers and a new Grails artifact: routes. We are going to install the plugin and create a new route which will poll a Gmail account and save the attachment to a specified directory.

$ grails install-plugin camel
$ grails create-route GetMail

In the directory grails-app/routes we have a new file GetMailRoute.groovy. The great thing is we can use closures for the filter, when and process methods from the Java DSL. The following code fragment shows how we can poll for e-mails and save the attachment to a directory. We use values from the Grails configuration in our code for mail username and password and the directory we want the files to be saved.:

import org.codehaus.groovy.grails.commons.*

class GetMailRoute {
    
    def configure = {
        def config = ConfigurationHolder.config

        from("imaps://imap.gmail.com?username=" + config.camel.route.gmail.username
            + "&password=" + config.camel.route.gmail.password
            + "&folderName=GoogleAnalytics"
            + "&consumer.delay=" + config.camel.route.gmail.pollInterval)
        .filter { 
            it.in.headers.subject.contains('Analytics')
        }
        .process{ exchange ->
            exchange.in.attachments.each { attachment ->
                def datahandler = attachment.value
                def xml = exchange.context.typeConverter.convertTo(String.class, datahandler.inputStream)
                def file = new File(config.camel.route.save.dir, datahandler.name) << xml
                log.info "Saved " + file.name
            }
        }
    }
}

That's it. We now have created our own route and when we start the application the route is executed. The only thing we need to do is to include the JavaMail libraries, because they are used by the Camel mail component. Therefore we copy activation.jar and mail.jar to the lib of the Grails application.

Friday, April 3, 2009

See which processes are running in NetBeans

Sometimes NetBeans starts up processes in the background. For example to scan all projects for tasks or downloading indexes for a Maven repository. At the right side of the status bar we can see a progress bar when this happens:

We can click on the progress bar to see which processes are running. Another way is to select Windows | Processes from the menubar. NetBeans shows a stack of all processes that are running:

Install Grails plugins in NetBeans

Update for NetBeans 6.7.1

The great thing about Grails is that we can extend Grails easily with plugins. Plugins extend Grails with new functionality in a Grails way. To install a plugin for our Grails application is NetBeans is easy.

In NetBeans we right-click on the application in the Project Navigator:

We select the option Plugins from the pop-up menu and NetBeans opens a dialog window where we can see which plugins are already installed for our application and a tab page New plugin. When we click on the New Plugin tab we get a list of available plugins. We can select the plugin we want (for example Searchable) and click on the Install button:

The plugin is now downloaded and installed in our appliation:

When we return to the Installed tab we see our newly installed plugin:

Thursday, April 2, 2009

Change character encoding scheme for Maven resource and compile plugin in NetBeans

In a previous post we have learned how to change the source version for the Maven compiler plugin. But we can also change the character encoding scheme from the same Project Properties dialog window. The Encoding select box let's us change the encoding for the Maven project.

NetBeans add an encoding element to the compiler plugin definition and adds a configuration for the resource plugin in the pom.xml.

<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.0.2</version>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-resources-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

Wednesday, April 1, 2009

Handle Google Analytics scheduled e-mail reports with Apache Camel and Groovy

Yes, the title of this post is almost similar to my previous post Handle Google Analytics scheduled e-mail reports with Apache James. So we are going to do the same thing but this time we use Apache Camel instead of Apache James. Apache James is really a server-side solution and probably most people cannot install Apache James just like that. With Apache Camel we can have a solution without the need to install anything else.

This time we are going to send the scheduled Google Analytics report to our Google mail account instead of a James account. Read the previous post to see how we can schedule e-mail with report attachments. In Google we create a new filter which will assign the label GoogleAnalytics to the received e-mails. We are going to poll for mail messages with label GoogleAnalytics and look if the subject starts with the text Analytics. A similar proces is already described in another post. We extract the attachment from the e-mail and save it to a directory.

The following code shows how we poll messages with label GoogleAnalytics in Google mail every hour. We then check the subject of the message to see if it starts with Analytics. If so we process the message with the ExtractAttachment class. The message will contain an attachment with an XML file. So we get the contents of the attachment and save it to a file on disk.

#!/usr/bin/env groovy

import org.apache.camel.Exchange
import org.apache.camel.Processor
import org.apache.camel.impl.DefaultCamelContext
import org.apache.camel.language.groovy.GroovyRouteBuilder

@Grab(group='org.apache.camel', module='camel-groovy', version='1.6.0')
@Grab(group='org.apache.camel', module='camel-mail', version='1.6.0')
@Grab(group='org.apache.camel', module='camel-core', version='1.6.0')
class AnalyticsRoute extends GroovyRouteBuilder {
    void configure(){
        from("imaps://imap.gmail.com?username=username@gmail.com" 
                                 + "&password=secret"
                                 + "&folderName=GoogleAnalytics"
                                 + "&consumer.delay=" + 1000 * 60 * 60)
            .filter { it.in.headers.subject.startsWith('Analytics') }
            .process(new ExtractAttachment())            
    }
}

class ExtractAttachment implements Processor {
    void process(Exchange exchange) throws Exception {   
        def attachments = exchange.in.attachments
        attachments.each { attachment ->
            def datahandler = attachment.value
            def xml = exchange.context.typeConverter.convertTo(String.class, datahandler.inputStream)
            new File('/home/analytics/xml', datahandler.name) << xml
        }
    }
}

def camelCtx = new DefaultCamelContext()
camelCtx.addRoutes(new AnalyticsRoute());
camelCtx.start();

Poll for e-mail with Groovy and Apache Camel

Just recently I read this interesting article and it triggered me to read more about Apache Camel. Apache Camel is a framework for integration patterns with a lot of useful components. The syntax is straighforward and the Java DSL is easy to use.

The following example shows how we can poll our Google mail inbox every 10 minutes and log the message if the subject contains Groovy:

#!/usr/bin/env groovy

import org.apache.camel.impl.DefaultCamelContext
import org.apache.camel.language.groovy.GroovyRouteBuilder

@Grab(group='org.apache.camel', module='camel-groovy', version='1.6.0')
@Grab(group='org.apache.camel', module='camel-mail', version='1.6.0')
@Grab(group='org.apache.camel', module='camel-core', version='1.6.0')
class GroovyMailRoute extends GroovyRouteBuilder {
    protected void configure(){
        from("imaps://imap.gmail.com?username=username@gmail.com"
                                 + "&password=secret"
                                 + "&deleteProcessedMessages=false"
                                 + "&processOnlyUnseenMessages=true"
                                 + "&consumer.delay=600000")
            .filter { it.in.headers.subject.contains('Groovy') }
            .to("log:groovymail?showAll=true&multiline=true")
    }
}

def camelCtx = new DefaultCamelContext()
camelCtx.addRoutes(new GroovyMailRoute());
camelCtx.start();

Change source version for Maven compiler plugin in NetBeans

The Maven compiler plugin allows us to change the source version of the Java files for compilation. If we want to use all the latest support, like assertions, we must set the version to at least 1.4. If we want to use annotations we must set the value to at least 1.5.

In NetBeans we can change this in the Project Properties window. We right-click on our Maven project and select Project Properties. In the Sources tab we can change the Source/Binary Format to the version we want.

NetBeans add the compiler plugin to the pom.xml with the selected version:

<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.0.2</version>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
            </configuration>
        </plugin>
    </plugins>
</build>