Search

Dark theme | Light theme
Showing posts with label Groovy:Grassroots. Show all posts
Showing posts with label Groovy:Grassroots. Show all posts

October 11, 2012

Grassroots Groovy: Parse XML with XmlSlurper from Java

We can introduce Groovy into our Java projects at grassroots level. Even if we aren't allowed to run the Groovy compiler we can use other ways to run Groovy code. As long as we can include the Groovy libraries as a compile dependency than we can already use Groovy from Java. In this post we see how we can use the power of XmlSlurper to parse XML from our Java code.

To execute a Groovy script from we can use a GroovyShell object and invoke the evaluate() method. The evaluate() method can parse a Groovy script as File or Reader object. We can also use a String value to be evaluated. The last statement of the script that is evaluated can be assigned to a Java variable. To pass variables to the script we use the Binding object. This is a map of variables and their values. We assign values to the variables in the Java code and in the Groovy script we can use the variable values.

In the example we need to be able to parse a XML document with the following structure and find users with a given age:

<?xml version="1.0"?>
<users>
    <user age="39">mrhaki</user>
    <user age="39">hubert</user>
    <user age="23">chris</user>
</users>

We first define a simple Java interface with a method getUsersWithAge(int):

package com.mrhaki.groovy.grassroots.xml;

import com.mrhaki.groovy.grassroots.model.User;

import java.util.List;

public interface DataExtractor {
    /**
     * Get list of User object parsed from
     * an input source like XML.
     *
     * @param age Age of users to look for.
     * @return List of found users.
     */
    List<User> getUsersWithAge(final int age);
}

We have the following User class:

package com.mrhaki.groovy.grassroots.model;

public class User {

    private final String username;
    private final int age;

    public User(final String username, final int age) {
        this.username = username;
        this.age = age;
    }

    public String getUsername() {
        return username;
    }

    public int getAge() {
        return age;
    }
}

The following class is an implementation of the DataExtractor interface and uses Groovy code to find all users from an XML source with a given age:

package com.mrhaki.groovy.grassroots.xml;

import com.mrhaki.groovy.grassroots.model.User;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;

import java.util.List;

/**
 * Use XML input source to extract data from.
 */
public class XMLDataExtractor implements DataExtractor {
    /**
     * XML input source String.
     */
    private final String xml;

    public XMLDataExtractor(final String xml) {
        this.xml = xml;
    }

    @Override
    public List<User> getUsersWithAge(final int age) {
        // First we create the binding with variables
        // to be used in the Groovy script.
        final Binding binding = new Binding();
        binding.setVariable("xml", xml);
        binding.setVariable("age", age);

        // Create Groovy shell to run script and
        // set binding with variables for the script.
        final GroovyShell shell = new GroovyShell(getClass().getClassLoader(), binding);

        // Create Groovy script as String.
        // We use the XmlSlurper to parse the XML String and
        // return a list of found objects.
        final ScriptBuilder parseScript = new ScriptBuilder();
        parseScript.addLine("import com.mrhaki.groovy.grassroots.model.User");
        parseScript.addLine("def slurper = new XmlSlurper().parseText(xml)");
        parseScript.addLine("slurper.user.findAll { it.@age == age }.collect { new User(it.text(), it.@age.toInteger()) } ");

        // Evaluate script. The last line of the script is
        // automatically the return statement, so the value
        // is assigned to result.
        // We could also assign it to a variable in the script and
        // use binding.getVariable() to get the value.
        final Object result = shell.evaluate(parseScript.build());

        return (List<User>) result;
    }

    /**
     * Utility builder class to create a Groovy script
     * as String with the correct line endings.
     */
    private final class ScriptBuilder {
        private StringBuilder script = new StringBuilder();

        public ScriptBuilder addLine(final String scriptLine) {
            script.append(scriptLine);
            script.append(newLine());
            return this;
        }

        private String newLine() {
            return System.getProperty("line.separator");
        }

        public String build() {
            return script.toString();
        }
    }

}

Ronan gave some good comments based on this version of the XMLDataExtractor class. We can reduce the Groovy code to be executed to a single line. We can add the import for the User with an ImportCustomizer. And in the binding we can immediately bind the result of the new XmlParser().parseText(xml) method to the slurper variable. Here is another version of the XMLDataExtractor class:

package com.mrhaki.groovy.grassroots.xml;

import com.mrhaki.groovy.grassroots.model.User;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.util.XmlSlurper;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.customizers.ImportCustomizer;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.List;

/**
 * Use XML input source to extract data from.
 */
public class XMLDataExtractor implements DataExtractor {
    /**
     * XML input source String.
     */
    private final String xml;

    public XMLDataExtractor(final String xml) {
        this.xml = xml;
    }

    @Override
    public List<User> getUsersWithAge(final int age) {
        // First we create the binding with variables
        // to be used in the Groovy script.
        final Binding binding = createBinding(age);

        // Create Groovy shell to run script and
        // set binding with variables for the script.
        final GroovyShell shell = createGroovyShell(binding);

        // Evaluate script. The line of the script is
        // automatically the return statement, so the value
        // is assigned to result.
        final Object result = shell.evaluate("slurper.user.findAll { it.@age == age }.collect { new User(it.text(), it.@age.toInteger()) } ");

        return (List<User>) result;
    }

    private GroovyShell createGroovyShell(final Binding binding) {
        // Add import for User class to script compiler configuration.
        final ImportCustomizer imports = new ImportCustomizer();
        imports.addImports("com.mrhaki.groovy.grassroots.model.User");
        final CompilerConfiguration config = new CompilerConfiguration();
        config.addCompilationCustomizers(imports);

        return new GroovyShell(getClass().getClassLoader(), binding, config);
    }

    private Binding createBinding(final int age) {
        final Binding binding = new Binding();
        try {
            binding.setVariable("slurper", new XmlSlurper().parseText(xml));
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (SAXException e) {
            throw new RuntimeException(e);
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        }
        binding.setVariable("age", age);
        return binding;
    }

}

To finish it up we can here see some simple tests to check the results of our XMLDataExtractor object:

package com.mrhaki.groovy.grassroots.xml;

import static org.junit.Assert.assertEquals;

import com.mrhaki.groovy.grassroots.model.User;
import org.junit.Test;

import java.util.List;

public class XMLDataExtractorTest {

    @Test
    public void numberOfUsersWithGivenAgeMustReflectNumbeOfUsersInXML() {
        final String sample = createSampleXml();
        final DataExtractor extractor = getExtractor(sample);

        final List<User> users = extractor.getUsersWithAge(39);

        assertEquals(2, users.size());
    }

    @Test
    public void foundUserMustHaveCorrectPropertyValues() {
        final String sample = createSampleXml();
        final DataExtractor extractor = getExtractor(sample);

        final List<User> users = extractor.getUsersWithAge(23);

        final User user = users.get(0);
        assertEquals("chris", user.getUsername());
        assertEquals(23, user.getAge());
    }

    private String createSampleXml() {
        final StringBuilder xml = new StringBuilder("<?xml version=\"1.0\"?>");
        xml.append("<users>");
        xml.append(createUserSampleXml("mrhaki", 39));
        xml.append(createUserSampleXml("hubert", 39));
        xml.append(createUserSampleXml("chris", 23));
        xml.append("</users>");
        return xml.toString();
    }

    private String createUserSampleXml(final String username, final int age) {
        return String.format("<user age=\"%2$s\">%1$s</user>", username, age);
    }

    protected DataExtractor getExtractor(final String sample) {
        return new XMLDataExtractor(sample);
    }

}

We have to add Groovy as a compile dependency to a Java project. The following build script defines a dependency on the Groovy XML module. Since Groovy 2 we don't have to include all of Groovy, but we can pick the modules we need and add them to our project:

// File: build.gradle
apply {
    plugin 'java'
    plugin 'idea'
}

version = 1.0

repositories {
    mavenLocal()
    mavenCentral()
}

ext {
    groovyVersion = '2.0.+'
    junitVersion = '4.+'
}

dependencies {
    compile "org.codehaus.groovy:groovy-xml:$groovyVersion"
    testCompile "junit:junit:$junitVersion"
}

November 1, 2011

Grassroots Groovy: Reading JSON with JsonSlurper

We can introduce Groovy into our Java projects at grassroots level. In this post we see how we can use the JsonSlurper class in our Java code to read JSON data. Once we have included the Groovy libraries in our project, for example by adding a dependency in a Maven POM file, we can use Groovy classes in our Java applications. And once we have Groovy in our project we might extend the use of Groovy further...

The JsonSlurper class has a parseText() and parse() method to read in JSON data. We get back a Map with values from the JSON structure. Let's see how we can use it in a simple Java application:

package com.mrhaki.sample;

import groovy.json.JsonSlurper;

import java.util.List;
import java.util.Map;

public class JsonParser {

    public static void main(String[] args) {
        String jsonText = "{\"user\":{\"name\":\"mrhaki\",\"age\":38,\"interests\":[\"Groovy\",\"Grails\"]}}";
        JsonSlurper jsonSlurper = new JsonSlurper();
        Object result = jsonSlurper.parseText(jsonText);

        Map jsonResult = (Map) result;
        Map user = (Map) jsonResult.get("user");
        String name = (String) user.get("name");
        Integer age = (Integer) user.get("age");
        List interests = (List) user.get("interests");

        assert name.equals("mrhaki");
        assert age == 38;
        assert interests.size() == 2;
        assert interests.get(0).equals("Groovy");
        assert interests.get(1).equals("Grails");
    }

}

Or use a URL with JSON content:

package com.mrhaki.sample;

import groovy.json.JsonSlurper;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Map;

public class JsonUrlParser {

    private static final String JSON_URL = "http://www.mrhaki.com/samples/sample.json";

    public static void main(String[] args) throws IOException, MalformedURLException {
        URL url = new URL(JSON_URL);
        InputStream urlStream = null;
        try {
            urlStream = url.openStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(urlStream));
            JsonSlurper jsonSlurper = new JsonSlurper();
            Object result = jsonSlurper.parse(reader);

            Map jsonResult = (Map) result;
            Map user = (Map) jsonResult.get("user");
            String name = (String) user.get("name");
            Integer age = (Integer) user.get("age");
            List interests = (List) user.get("interests");

            assert name.equals("mrhaki");
            assert age == 38;
            assert interests.size() == 2;
            assert interests.get(0).equals("Groovy");
            assert interests.get(1).equals("Grails");

        } finally {
            if (urlStream != null) {
                urlStream.close();
            }
        }

    }
}

Once we have the Groovy libraries in our classpath we can run the Java application with $ java -ea com.mrhaki.sample.JsonParser and the assertions should be okay.

September 22, 2010

Grassroots Groovy: Configure Logback with Groovy

Sometimes we have to work on a project with only Java source files. But we can introduce some small Groovy stuff at grassroots level if we use Logback as a logging framework. Logback supports configuration by a Groovy script file. This means we can define the configuration with Groovy code instead of the default XML.

The following sample is a very small Maven project for a Java application. We use the Maven exec plugin so we can run the application directly from the command-line. We add the necessary dependencies to the pom.xml so we can write the Logback configuration in Groovy code. We must add the Groovy JAR file so Logback can execute the configuration file.

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mrhaki</groupId>
    <artifactId>simple-app</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainClass>com.mrhaki.java.Simple</mainClass>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>0.9.24</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>1.7.5</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>
</project>

Our Java class is simple, just as the name suggests. We only want to demonstrate the different log levels that are used and how we can use that in our Logback configuration.

// File: src/main/java/com/mrhaki/java/Simple.java
package com.mrhaki.java;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Simple {
    private static final Logger LOGGER = LoggerFactory.getLogger(Simple.class);

    public Simple() {}

    public String sayHelloTo(String name) {
        return "Hello, " + name;
    }

    public static void main(String[] args) {
        LOGGER.info("Starting application.");
        Simple app = new Simple();
        String hello = app.sayHelloTo("mrhaki");
        LOGGER.debug("Saying: " + hello);
        LOGGER.info("Application ends.");
    }
}

Now it is time to look at the Groovy Logback configuration. Logback provides a simple DSL to configure loggers, appenders and other Logback configuration elements.

// File: src/main/resources/logback.groovy
import static ch.qos.logback.classic.Level.*
import ch.qos.logback.core.ConsoleAppender
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.core.status.OnConsoleStatusListener
import ch.qos.logback.core.FileAppender
import com.mrhaki.java.logsupport.SmileyConverter

displayStatusOnConsole()
scan('5 minutes')  // Scan for changes every 5 minutes.
setupAppenders()
setupLoggers()

def displayStatusOnConsole() {
    statusListener OnConsoleStatusListener 
}

def setupAppenders() {
    def logfileDate = timestamp('yyyy-MM-dd') // Formatted current date.
    // hostname is a binding variable injected by Logback.
    def filePatternFormat = "%d{HH:mm:ss.SSS} %-5level [${hostname}] %logger - %msg%n"
    appender('logfile', FileAppender) {
        file = "simple.${logfileDate}.log"
        encoder(PatternLayoutEncoder) {
            pattern = filePatternFormat
        }
    }

    // Add custom converter for %smiley pattern.
    conversionRule 'smiley', SmileyConverter

    appender('systemOut', ConsoleAppender) {
        encoder(PatternLayoutEncoder) {
            pattern = "%-5level %-12logger{12} %smiley - %msg%n"
        }
    }
}

def setupLoggers() {
    logger 'com.mrhaki.java.Simple', getLogLevel(), ['logfile']
    root DEBUG, ['systemOut']
}

def getLogLevel() {
    (isDevelopmentEnv() ? DEBUG : INFO)
}

def isDevelopmentEnv() {
    def env =  System.properties['app.env'] ?: 'DEV'
    env == 'DEV'
}

Logback looks for a file named logback.groovy in the classpath of the application. If the file is found it is parsed by a GroovyShell instance and Logback is configured.

We start by using the statusListener() method (line 14) so Logback logs the configuration details to the console.

To add a new appender, we use the appender() method. We use a closure to configure the appender. Loggers are configured with the logger() and root() methods. We can define the loglevel and a list of appenders that need to be used.

At line 9 we use the scan() method to define the scan interval used by Logback to check for changes in logback.groovy. If the file has changed, the new configuration is used.

At the bottom of the configuration file we define the method isDevelopmentEnv() to see if the application is running in development mode. If so we set the log level to DEBUG, otherwise it is set to INFO (see methods getLogLevel() and setupLoggers()). And because the configuration is a Groovy script this is very easy to achieve.

With the conversionRule() method at line 29 we assign the SmileyConverter class to the %smiley variable in the encoding pattern. The code for the SmileyConverter is here:

// File: src/main/java/com/mrhaki/java/logsupport/SmileyConverter.java
package com.mrhaki.java.logsupport;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;

import static ch.qos.logback.classic.Level.*;

public class SmileyConverter extends ClassicConverter {
    @Override
    public String convert(ILoggingEvent event) {
        return getSmiley(event.getLevel());
    }

    // Return a different smiley for different log levels.
    private String getSmiley(Level level) {
        String result = "";
        switch (level.toInt()) {
            case DEBUG_INT:
                result = ";)";
                break;
            case INFO_INT:
                result = ":)";
                break;
            default:
                break;
        }
        return result;
    }
}

We are ready to run the application and see our logging configuration at work:

$ mvn -q compile exec:java

11:01:52,087 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@6fa8bd74 - Added status listener of type [ch.qos.logback.core.status.OnConsoleStatusListener]
11:01:52,107 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@6fa8bd74 - Setting ReconfigureOnChangeFilter scanning period to 5 minutes
11:01:52,108 |-INFO in ch.qos.logback.classic.turbo.ReconfigureOnChangeFilter@14a97f68 - Will scan for changes in file [/Users/mrhaki/Projects/mrhaki.com/blog/posts/samples/logback/target/classes/logback.groovy] every 300 seconds. 
11:01:52,109 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@6fa8bd74 - Adding ReconfigureOnChangeFilter as a turbo filter
11:01:52,170 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@6fa8bd74 - About to instantiate appender of type [ch.qos.logback.core.FileAppender]
11:01:52,171 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@6fa8bd74 - Naming appender as [logfile]
11:01:52,311 |-INFO in ch.qos.logback.core.FileAppender[logfile] - File property is set to [simple.2010-09-21.log]
11:01:52,329 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@6fa8bd74 - registering conversion word smiley with class [com.mrhaki.java.logsupport.SmileyConverter]
11:01:52,380 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@6fa8bd74 - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
11:01:52,382 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@6fa8bd74 - Naming appender as [systemOut]
INFO  c.m.j.Simple :) - Starting application.
DEBUG c.m.j.Simple ;) - Saying: Hello, mrhaki
INFO  c.m.j.Simple :) - Application ends.

First we see the results from Logback, because we used the statusListener() method. Then at the bottom we see three output lines from our Simple java code. Now let's run the application again, but this time we use a system property to set the environment to a non-development one:

$ mvn -q -Dapp.env=TEST compile exec:java

11:04:01,588 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@563b100c - Added status listener of type [ch.qos.logback.core.status.OnConsoleStatusListener]
11:04:01,607 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@563b100c - Setting ReconfigureOnChangeFilter scanning period to 5 minutes
11:04:01,609 |-INFO in ch.qos.logback.classic.turbo.ReconfigureOnChangeFilter@364e50ee - Will scan for changes in file [/Users/mrhaki/Projects/mrhaki.com/blog/posts/samples/logback/target/classes/logback.groovy] every 300 seconds. 
11:04:01,610 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@563b100c - Adding ReconfigureOnChangeFilter as a turbo filter
11:04:01,655 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@563b100c - About to instantiate appender of type [ch.qos.logback.core.FileAppender]
11:04:01,656 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@563b100c - Naming appender as [logfile]
11:04:01,811 |-INFO in ch.qos.logback.core.FileAppender[logfile] - File property is set to [simple.2010-09-21.log]
11:04:01,832 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@563b100c - registering conversion word smiley with class [com.mrhaki.java.logsupport.SmileyConverter]
11:04:01,837 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@563b100c - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
11:04:01,841 |-INFO in ch.qos.logback.classic.gaffer.ConfigurationDelegate@563b100c - Naming appender as [systemOut]
INFO  c.m.j.Simple :) - Starting application.
INFO  c.m.j.Simple :) - Application ends.

No if we look at the last two lines we see the DEBUG message is not shown anymore. That is because we changed the log level accordingly to the sytem property app.env..

As we can see introducing Groovy into a Java project is easy if we use Logback. We only have to add the Groovy JAR as a dependency and we are ready to go. And once that Groovy JAR dependency is in the project definition... (grin)

August 28, 2009

Grassroots Groovy: the Spring Route (part 2)

We can introduce Groovy into our projects at grassroots level. In a previous post we learned how to invoke Groovy code from Spring configured applications. In this post we learn how to create the Spring configuration files with Groovy. We are using the BeanBuilder from Grails to achieve this. The builder implements a Spring DSL to configure beans. We can define beans and wire beans together using Groovy code, so this means we can add logic to the configuration. For example we could check an environment variable and depending on the value we define certain beans.

To define the beans we use Groovy, but we can still use Java code to read the configuration and get a valid Spring ApplicationContext. This way the impact on the Java code is minimal, but we can create the Spring configuration more dynamically. First we start with the Spring BeanBuilder file SpringBeansConfig.groovy:

import com.mrhaki.blog.*
import org.apache.commons.dbcp.*

beans {
    // We can use namespaces in the builder.
    xmlns util:"http://www.springframework.org/schema/util"
    
    // We can write code in this configuration file and reference
    // binding variables.
    def bindingEnv = env
    util.list(id: 'runningMode') {
        value new Date().format('yyyy-MM-dd')
        value bindingEnv
    }
    
    // Abstract bean definition with custom destroy-method.
    abstractDataSource(BasicDataSource) { bean ->
        bean.destroyMethod = 'close'
        driverClassName = 'com.mysql.jdbc.Driver'
        username = ''
        password = ''
    }
    
    // Create bean definitions dynamically and use abstract parent.
    def urls = [
        dev:  'jdbc:mysql://localhost/db',
        test: 'jdbc:mysql://localhost/test',
        prod: 'jdbc:mysql://prod'
    ]
    urls.each { key, value ->
        "${key}DataSource"(BasicDataSource) { bean -> 
            bean.parent = abtractDataSource
            url = value
        }
    }
    
    // Spring bean definitions for bean with id personDao
    // and class PersonDaoImpl. Sample switch statement to show
    // we can add Groovy code in this file.
    personDao(PersonDaoImpl) {
        switch (env) {
            case 'dev':  dataSource = devDataSource; break
            case 'test': dataSource = testDataSource; break
            case 'prod': dataSource = ref(prodDataSource); break
        }
    }
    
    // Equivalent of
    // <bean id="personService"
    //    class="com.mrhaki.blog.PersonServiceJavaImpl">
    //    <property name="dao" ref="personDao"/>
    // </bean>
    personService(PersonServiceJavaImpl) {
        dao = ref(personDao)
    }
}

We have now defined the following beans: runningMode, devDataSource, testDataSource, prodDataSource, abstractDataSource, personService, personDao and wired some together. With the following Java application we read this file and use the Spring ApplicationContext:

package com.mrhaki.blog;

import java.io.IOException;
import java.util.List;
import java.util.Date;
import java.text.SimpleDateFormat;
import grails.spring.BeanBuilder;
import groovy.lang.Binding;
import org.springframework.context.ApplicationContext;
import org.apache.common.dbcp.BasicDataSource;

public class SpringBuilderApp {
    public static void main(String[] args) throws IOException {
        // Create a binding to get "env" into the configuration script.
        final Binding binding = new Binding();
        binding.setProperty("env", "dev");
        
        // Create a builder and find all files on the classpath
        // ending with BeansConfig.groovy.
        final BeanBuilder builder = new BeanBuilder();
        builder.setBinding(binding);
        builder.loadBeans("classpath:**/**BeansConfig.groovy");
        
        // Make the Spring ApplicationContext.
        final ApplicationContext context = builder.createApplicationContext();
        
        assert 7 == context.getBeanDefinitionNames().length;
        assert context.containsBean("prodDataSource");
        assert context.containsBean("testDataSource");
        assert context.containsBean("devDataSource");
        assert context.containsBean("abstractDataSource");
        assert context.containsBean("personDao");
        assert context.containsBean("personService");
        assert context.containsBean("runningMode");

        final List mode = (List) context.getBean("runningMode");
        final Date now = new Date();
        assert new SimpleDateFormat("yyyy-MM-dd").format(now).equals(mode.get(0));
        assert "dev".equals(mode.get(1));
        
        final BasicDataSource ds = (BasicDataSource) context.getBean("testDataSource");
        assert "jdbc:mysql://localhost/test".equals(ds.getUrl());
        assert "com.mysql.jdbc.Driver".equals(ds.getDriverClassName());
        assert "".equals(ds.getUsername());
        assert "".equals(ds.getPassword());
    }
}

We can run this application with assertions enabled and we get no errors. We must include the grails-spring-<version>.jar and grails-bootstrap-<version>.jar, the Commons DBCP libraries and the Groovy libraries to the classpath. Now we can define the Spring context with Groovy and we can run Groovy code from Spring. More and more Groovy creepes into our Java projects.

August 27, 2009

Grassroots Groovy: the Templating Route

We can introduce Groovy into our projects at grassroots level. If we need some templating functionality in our Java application we can use Groovy templates. Groovy templates allow us to write Groovy code, use JSP expressions or use variables in the template. Basically a template contains static text with placeholders and we combine the template with 'live' objects through binding. The result is a the template with all placeholders replaced with the correct values from the binding and expressions.

Let's start with a template named mail.gtpl:

Hello $person.firstname $person.lastname,

Thank you registering with our company at ${ new Date().format('MMM dd, yyyy') }.

Details:
--------
Your username is <%= person.username %>.
You have signed up for the following <% out << (person.topics.size() == 1) ? ' topic' : person.topics.size() + ' topics' %>:
<% person.topics.each { %>
- $it
<% } %>


${greeting}

Because this is an example we use all possible ways to express values and Groovy code. We use the <% %>, <%= %>, $var and ${expression} syntax. At line 7 we use the out variable, which is bound to a Writer object. Now we write the Java code that can use and execute this Groovy template:

package com.mrhaki.blog;

import java.io.*;
import java.util.*;
import groovy.text.*;
import groovy.lang.*;

public class TemplateApp {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // Initialize template.
        final TemplateEngine engine = new GStringTemplateEngine();
        final Template template = engine.createTemplate(new File("mail.gtpl"));
        
        // Create Map for binding objects to template.
        final Map<String, Object> binding = new HashMap<String, Object>();
        binding.add("greeting", "Kind regards,\n\nThe Company");
        binding.add("person", new PersonObject());
        
        // Bind Map to template.
        final Writeable out = template.make(binding);
        
        // We use a Writer object, can be any Writer e.g. FileWriter.
        final StringWriter writer = new StringWriter();
        out.writeTo(writer);
        System.out.println(writer.toString());
    }
}

class PersonObject {
    public String getFirstname() { 
        return "Hubert"; 
    }
    
    public String getLastname() { 
        return "Klein Ikkink"; 
    }
    
    public String getUsername() { 
        return "mrhaki"; 
    }
    
    public List<String> getTopics() { 
        return Arrays.asList(new String[] { "Groovy", "Grails", "Java" }); 
    }
}

When we run the Java application (make sure the Groovy libraries are in the Java classpath) we get the following output:

Hello Hubert Klein Ikkink,

Thank you registering with our company at Aug 26, 2009.

Details:
--------
Your username is mrhaki.
You have signed up for the following 3 topics:
- Groovy
- Grails
- Java


Kind regards,

The Company

In this post we learned another way to introduce Groovy in Java projects: templates. Groovy templates are flexible and allow the use of Groovy code in the template. Integration with Java is simple and easy.

August 26, 2009

Grassroots Groovy: the Spring Route (part 1)

We can introduce Groovy into our projects at grassroots level. If we are already using Spring on our project we can use Groovy to define classes and define them in our Spring configuration files. It is even possible to have Groovy code in the configuration files themselves. The nice thing about the Groovy support in Spring is that we can define a reload interval on Groovy source files. This means new versions of the Groovy source file are automatically picked up and ready to be used.

Let's see how we can leverage the Groovy support with Spring by a little example. We have a simple Data Access Object (DAO) class and interface to get a list of Person objects. The DAO class is used by a service to get any person without an e-mail address. We are going to write the service in Groovy. All these classes are connected by a Spring configuration file. We start with a simple Person class to hold a username and e-mail address:

package com.mrhaki.blog;

public class Person {

    private String username;
    private String email;

    public Person() {
    }

    public Person(String username, String email) {
        this.username = username;
        this.email = email;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public String toString() {
        return "[Person: username=" + username + ", email=" + email + "]";
    }
}

Next we define a PersonDao interface and a Java implementation class PersonDaoImpl:

package com.mrhaki.blog;

import java.util.List;

public interface PersonDao {

    List<Person> list();
}
package com.mrhaki.blog;

import java.util.ArrayList;
import java.util.List;

public class PersonDaoImpl implements PersonDao {

    public List<Person> list() {
        final List<Person> result = new ArrayList<Person>();
        result.add(new Person("mrhaki", "test@email.com"));
        result.add(new Person("test", null));
        return result;
    }
}

We have our DAO part ready. It is time to create the interface PersonService:

package com.mrhaki.blog;

import java.util.List;

public interface PersonService {
    List<Person> listPersonsNoEmail();
}

Notice we only have created plain old Java classes, no Groovy to be seen. But that changes when we create the Spring configuration file. To use Groovy support we must have the Groovy libraries in our classpath, and we must use the lang namespace in the configuration file. First we write the Groovy code in our Spring configuration file. Later on we move the code from the configuration file to a separate source file. We create the file spring-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:lang="http://www.springframework.org/schema/lang"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd">

    <bean id="personDao" class="com.mrhaki.blog.PersonDaoImpl"/>

    <lang:groovy id="personService">
        <lang:inline-script>
            <![CDATA[
import com.mrhaki.blog.*

class PersonServiceImpl implements PersonService {

    def personDao

    List<Person> listPersonsNoEmail() {
        personDao.list().grep{ !it.email }
    }
}           
            ]]>
        </lang:inline-script>
       <lang:property name="dao" ref="personDao"/>
    </lang:groovy>

</beans>

At lines 9-25 we define the Groovy script which implements the PersonService interface. At line 9 we assign a value to the attribute id, so we can get the resulting object. The Groovy script has one property personDao and at line 24 we assign our Java DAO object to this property. The implementation method is simple and Groovy.

We are ready to use our Groovy service in a Java application:

package com.mrhaki.blog;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.ApplicationContext;

public class SpringApp {

    public static void main(String[] args) {
        final ApplicationContext context =
                new ClassPathXmlApplicationContext("classpath:com/mrhaki/blog/spring-config.xml");
        final PersonService service = (PersonService) context.getBean("personService");

        assert 1 == service.listPersonsNoEmail().size();
        assert "test".equals(service.listPersonsNoEmail().get(0).getUsername());
        assert null == service.listPersonsNoEmail().get(0).getEmail();
    }

}

We can run the application SpringApp and if we enable assertions we don't get any errors. Our Groovy code is invoked correctly and in the Java code we cannot see the service is implemented in Groovy. We are going to make an adjustment to the Spring configuration file. We move the script in the file to a separate source file PersonServiceImpl.groovy. And we use the attribute refresh-check-delay to define a reload interval for the source file. Spring will check if the file has changed and if so will load the new script.

package com.mrhaki.blog

class PersonServiceImpl implements PersonService {

    def personDao

    List<Person> listPersonsNoEmail() {
        personDao.list().grep{ !it.email }
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:lang="http://www.springframework.org/schema/lang"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd">

    <bean id="personDao" class="com.mrhaki.blog.PersonDaoImpl"/>

    <lang:groovy id="personService" refresh-check-delay="3000"
        script-source="classpath:com/mrhaki/blog/PersonServiceImpl.groovy">
       <lang:property name="dao" ref="personDao"/>
    </lang:groovy>

</beans>

In this post we have seen how easy it is to integrate Groovy code in our Java based project using Spring. In a next post we see how we can create the Spring configuration files in a Groovy way.

August 25, 2009

Grassroots Groovy: Configuration with ConfigSlurper

We can introduce Groovy into our projects at grassroots level. In this post we learn how to use Groovy configuration scripts instead of Java properties files to configure our application. Groovy has the ConfigSlurper class. We use a ConfigSlurper object to read in a Groovy script. This scripts contains a tree of objects with different values. These values can be Java types, which is not possible in a plain properties file. We can even add code to the script file.

The ConfigSlurper is capable of supporting different environments. We pass the environment to the constructor. This way we can set a default value for a property and override it for a specific environment in the same configuration file.

We start with a simple Java application to read in a Groovy configuration script:

package com.mrhaki.sample.config;

import java.net.*;
import java.util.*;
import groovy.util.*;

public class JavaConfig {
    public static void main(String[] args) throws MalformedURLException {
        // Read in 'config.groovy' for the development environment.
        ConfigObject conf = new ConfigSlurper("development").parse(new File("config.groovy").toURI().toURL());
        
        // Read in 'mail.groovy'.
        final ConfigObject mailConf = new ConfigSlurper().parse(new File("mail.groovy").toURI().toURL());
        
        // Merge both configurations into one.
        conf = (ConfigObject) conf.merge(mailConf);
        
        // Flatten configuration for easy access keys with dotted notation.
        final Map config = conf.flatten();
        
        assert "1.0".equals(config.get("app.version"));
        assert new Integer(20).equals(config.get("app.setting2"));
        assert new Date().after((Date) config.get("app.date"));
        assert config.get("app.active");
        assert "http://localhost".equals(config.get("server.URL"));
        assert "smtpservername".equals(config.get("mail.smtp.host"));
    }
}

It is not difficult to invoke the ConfigSlurper from our Java code. We must make sure the Groovy libraries are in the classpath when we run the application ($GROOVY_HOME/embeddable/groovy-all-<version>.jar). Next we make the configuration script config.groovy:

// We can group settings.
// The following settings are created:
// app.version, app.setting1, app.setting2, app.setting3, app.date, app.active
app {
    version = "1.0"
    
    // We can write code to set up settings.
    [1, 2, 3].each {
        this."setting${it}" = it * 10
    }
    
    // We can use Java objects
    date = new Date()
    active = true
}

server.URL = 'http://default'

// Environment specific settings override settings with the
// same name.
environments {
    development {
        server.URL = 'http://localhost'
    }
    test {
        server.URL = 'http://test:9080'
    }
    integrationtest {
        server.URL = 'http://integrationtest/url'
    }
    production {
        server.URL = 'http://prod/url'
    }
}

And we make the configuration script mail.groovy which is merged together with config.groovy:

// Classic way of specifying properties without grouping, 
// but we can use Java objects instead of only strings.
mail.smtp.host = "smtpservername"
mail.smtp.ssl = true

We are ready to run our Java application - $ java -ea com.mrhaki.sample.config.JavaConfig - and all works fine. We shouldn't get any assertion errors. In a real world application we can make a class to read in the Groovy configuration files. Other classes use this class to get the values of the settings. All in plain old Java, but we create the settings and their values in a Groovy way.

August 23, 2009

Grassroots Groovy: the Maven Route (part 2)

We can introduce Groovy into our projects at grassroots level. In a a previous blog we learned how we could add Groovy code to a Maven based Java project. In this blog post we see how we can use the GMaven plugin to add Groovy code to the Maven build process itself. Sometimes we want a bit more functionality than Maven supports by default. We could write our own Maven plugin to get this extra functionality, but sometimes we can get away with a little scripting. And for this scripting we use Groovy of course.

To execute Groovy code from Maven we only have to define the GMaven plugin in our POM. And then we write Groovy code in the POM itself to be executed, or from a local file, of from an URL. The Groovy code can access a couple of variables:

  • project: points to the Maven project and we can access everything.
  • pom: just another name for the project variable.
  • session: the current Maven session.
  • settings: the user's global settings.
  • log: the SLF4J logger instance to log messages to the console.
  • ant: a reference to an AntBuilder instance to execute Ant tasks.
  • fail(): a helper method to throw a MojoExecutionException.

Let's add the Maven plugin to our POM with a reference to a local Groovy script file:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mrhaki.sample</groupId>
    <artifactId>sample-app</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>sample-app</name>
    <url>http://maven.apache.org</url>
    <build>
        <plugins>
            <!-- GMaven plugin so we can run Groovy scripts. -->
            <plugin>
                <groupId>org.codehaus.groovy.maven</groupId>
                <artifactId>gmaven-plugin</artifactId>
                <version>1.0</version>
                <executions>
                    <execution>
                        <!-- Script will be executed in 
                                the generate-resources phase. -->
                        <phase>generate-resources</phase>
                        <goals>
                            <goal>execute</goal>
                        </goals>
                        <configuration>
                            <source>${pom.basedir}/src/main/scripts/MavenHelper.groovy</source>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <profiles>
        <!-- Extra profile to be used in Groovy script as an example. -->
        <profile>
            <id>dev</id>
        </profile>
    </profiles>
</project>

Next we create the Groovy script file in src/main/scripts. In this script we look for active profiles, and if we have a match for a profile with id dev we log some extra info and use the Antbuilder to copy a properties file:

// Get list of active profiles.
def profiles = project.getActiveProfiles()

profiles.each{ profile ->
    // Show off Groovy's switch for matching on strings.
    switch(profile.id) {
        case 'dev':
            // Show some extra logging info.
            log.info "*" * 70
            log.info "* You are running in DEVELOPMENT mode."
            log.info "* Version: ${pom.version}, Finalname: ${pom.build.finalName}"
            log.info "*" * 70
            
            // Using Antbuilder to copy properties file.
            ant.copy(file: 'src/main/resources/dev.properties', tofile: project.build.outputDirectory + '/app.properties')
            break;
        default:
            break;
    }
}

To execute Maven with the dev profile we run the following command: $ mvn install -Pdev. In the logging generated by Maven we get the following output:

[INFO] [groovy:execute {execution: default}]
[INFO]  **********************************************************************
[INFO]  * You are running in DEVELOPMENT mode.
[INFO]  * Version: 1.0-SNAPSHOT, Finalname: sample-app-1.0-SNAPSHOT
[INFO]  **********************************************************************
Copying 1 file to P:\samples\sample-app\target\classes

So we learned how to add Groovy scripts to our Maven build. The Groovy website contains more information about all the configuration we can do to use the GMaven plugin like this.

August 22, 2009

Grassroots Groovy: the Maven Route (part 1)

We can introduce Groovy into our projects at grassroots level. In a series of blog posts we learn different routes we can follow to get our Java projects more Groovy. First off we look at how we can add Groovy sources to our Maven based Java project. But we will also see how XML handling, unit testing, Spring integration and other routes allow us to add Groovyness to a Java project in other posts.

The GMaven plugin adds Groovy support to a Maven based Java project. We configure the plugin to allow Groovy classes to be compiled just like normal Java classes. The compiled Groovy classes can than be integrated with the Java classes.

Let's start with the Maven quickstart archetype to create a simple Java Maven project:

$ mvn archetype:generate -DgroupId=com.mrhaki.sample -DartifactId=sample-app -DinteractiveMode=false
$ cd sample-app

Maven creates a new directory sample-app with a basic Java application at src/main/java/com/mrhaki/sample/App.java. We open pom.xml to add the GMaven plugin so we can compile and use our Groovy code:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mrhaki.sample</groupId>
    <artifactId>sample-app</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>sample-app</name>
    <url>http://maven.apache.org</url>
    <build>
        <plugins>
            <!-- GMaven plugin so we can compile Groovy sources. -->
            <plugin>
                <groupId>org.codehaus.groovy.maven</groupId>
                <artifactId>gmaven-plugin</artifactId>
                <version>1.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generateStubs</goal>
                            <goal>compile</goal>
                            <goal>generateTestStubs</goal>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <!-- Extra dependency for Groovy libraries for runtime. -->
        <dependency>
            <groupId>org.codehaus.groovy.maven.runtime</groupId>
            <artifactId>gmaven-runtime-1.6</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

Now our Groovy sources ending with .groovy in the directory src/main/groovy are compiled into target/classes and Groovy sources in the directory src/test/groovy are compiled into the target/test-classes directory when we run mvn install. We create a Groovy source file at src/main/groovy/com/mrhaki/sample/MyGroovy.groovy:

package com.mrhaki.sample

class MyGroovy {

    String username
    
    def reverseName() {
        username.reverse()
    }
    
    def calculateBigDecimals() {
        40G + 2G
    }
}

For this example we add a new test method to the existing AppTest class in the directory src/test/java/com/mrhaki/sample. In this test method we create an instance of the Groovy class and invoke the methods to test them:

...
public void testGroovy() {
    MyGroovy groovy = new MyGroovy();
    groovy.setUsername("mrhaki");
    assertEquals("mrhaki", groovy.getUsername());
    assertEquals("ikahrm", groovy.reverseName());
    assertEquals(new java.math.BigInteger("42"), groovy.calculateBigDecimals());
}
...

Now we run $ mvn test and our Groovy class is compiled and the Java test class will be executed without errors. So we see integrating Groovy with Java is not that difficult when we already have a Maven based Java project. In a following post we learn how we can use Groovy in the Maven POM as another route to get Groovy into our Java project.