Friday, September 14, 2012

Boost your Groovy with NailGun

Are you working on a large Hibernate project that takes long time to load up all the hbm.xml files when creating the Session object? This is fine during deployment and runtime because it only loads it once. However, often time we also need to the same Session object to do some ad-hoc HQL queries to debug or validate data. Loading and re-loading large mapping files in a Session to just execute single query is very painful.

Now, I like to poke around Java things with Groovy, and it's a great tool to peek at your data as ad-hoc queries as well. You can easily do this with their groovyConsole GUI tool and add --classpath option to include your project classes. This will bring up a tiny Editor, and you can script to load your hibernate Session there. Once the first run is loaded (the hibenrate Session created), then second run is almost in an instant.

Running the little groovyConsole had wet my appetite, and I was hungry for a better text editor, but yet I don't really want a full blow IDE for scripting. I like do my scripting in a plain editor. Now if you have an editor such as Sublime Text 2 (ST2) that has a "build" feature to execute a external command, then you will enjoy scripting much more. With ST2, I can have it call groovy.bat from inside the editor on the script that I am editing. However, there is another problem: the external command will restart a new JVM process on each run! Now I am back to square one.

To solve this problem, and still have my cake (editor), I recalled an awesome tool called NailGun. This works perfectly with Groovy and my problem. I can start a server like this

java -cp "groovy-all-2.0.1.jar:nailgun-0.7.1.jar" -server com.martiansoftware.nailgun.NGServer

And then in my ST2 editor, I can run an external command like this as the NailGun client:

/path/to/nailgun-0.7.1/ng groovy.ui.GroovyMain test.groovy

Nail gun client sends the script file content to the server and prints the result. Again, after first run, the second run should be instantaneously.

There, I scratched my itch.

Details on how to setup Sublime Text 2 to run NailGun client

  1. Go to menu: "Preference > Browse Packages"
  2. Open the Groovy folder
  3. Save a file named "GroovyNailGunClient.sublime-build" with the following:
       {
         "cmd": ["/path/to/nailgun-0.7.1/ng", "groovy.ui.GroovyMain", "$file"],
         "file_regex": "^(...?):([0-9]):?([0-9]*)",
         "selector": "source.groovy"
       }
    
  4. Select menu "Tool > Build System > GroovyNailGunClient"
  5. Press CTRL+B to run any groovy file in your editor.

Saturday, September 8, 2012

Improving java.util.Properties

The Java built-in java.util.Properties class could really use some love. I have written a slightly improved version called timemachine.scheduler.support.Props, and below are some features that I use often.

You can use it as a "String Map" of properties

Props props1 = new Props();
props1.put("foo", "bar");

// It can load from/to the Java Properties
Props props2 = new Props(System.getProperties());
java.util.Properties javaProps = props3.toProperties();

// It can load from/to a basic java.util.Map
Props props3 = new Props(System.getenv());

// Props is a HashMap<String, String>, so no need to convert. Just use it
for(Map.Entry<String, String> entry : props3.entrySet())
    System.our.println(entry.getKey() + ": " + entry.getValue());

You can load from a file in a single line

Props props1 = new Props("config.properties");
Props props2 = new Props("/path/to/config.properties");
Props props3 = new Props(new java.net.URL("http://myhost/config/config.properties"));
Props props4 = new Props(ClasspathURLStreamHandler.createURL("classpath://config/config.properties"));

// You can re-load on top of existing instance to override values
props4.load("config2.properties");

NOTE: The ClasspathURLStreamHandler is a utility class from the same package under timemachine.scheduler.support that can load any resources that's in the classpath.

You can get many basic types conversion

Props props = new Props();
props.put("str", "foo");
props.put("num", "123");
props.put("dec", "99.99");
props.put("flag", "true");

String str = props.getString("str");
int num = props.getInt("num");
double dec = props.getDouble("dec");
boolean flag = props.getBoolean("flag");

// You can even get default value when key is not found too
int num2 = props.getInt("num2", -1);

You can auto expand ${variable} from any existing properties

Props props = new Props(System.getProperties());
props.put("configDir", "${user.home}/myapp/config");
props.expandVariables();

// The ${user.home} should be expanded to actual user home dir value.
File dir = new File(props.get("configDir"));

There you have it. You see more code than words in this post, but I believe simple code speak louder than words and docs. I find these features very convenient and practical for many Java applications to use. I wish the JDK would provide these out of the box, and make the java.util.Properties more developer friendly.

Sunday, September 2, 2012

How to write better POJO Services

In Java, you can easily implement some business logic in Plain Old Java Object (POJO) classes, and then able to run them in a fancy server or framework without much hassle. There many server/frameworks, such as JBossAS, Spring or Camel etc, that would allow you to deploy POJO without even hardcoding to their API. Obviously you would get advance features if you willing to couple to their API specifics, but even if you do, you can keep these to minimal by encapsulating your own POJO and their API in a wrapper. By writing and designing your own application as simple POJO as possible, you will have the most flexible ways in choose a framework or server to deploy and run your application. One effective way to write your business logic in these environments is to use Service component. In this article I will share few things I learned in writing Services.

What is a Service?

The word Service is overly used today, and it could mean many things to different people. When I say Service, my definition is a software component that has minimal of life-cycles such as init, start, stop, and destroy. You may not need all these stages of life-cycles in every service you write, but you can simply ignore ones that don't apply. When writing large application that intended for long running such as a server component, definining these life-cycles and ensure they are excuted in proper order is crucial!

I will be walking you through a Java demo project that I have prepared. It's very basic and it should run as stand-alone. The only dependency it has is the SLF4J logger. If you don't know how to use logger, then simply replace them with System.out.println. However I would strongly encourage you to learn how to use logger effectively during application development though. Also if you want to try out the Spring related demos, then obviously you would need their jars as well.

Writing basic POJO service

You can quickly define a contract of a Service with life-cycles as below in an interface.

package servicedemo;

public interface Service {
    void init();
    void start();
    void stop();
    void destroy();
    boolean isInited();
    boolean isStarted();
}

Developers are free to do what they want in their Service implementation, but you might want to give them an adapter class so that they don't have to re-write same basic logic on each Service. I would provide an abstract service like this:

package servicedemo;

import java.util.concurrent.atomic.*;
import org.slf4j.*;
public abstract class AbstractService implements Service {
    protected Logger logger = LoggerFactory.getLogger(getClass());
    protected AtomicBoolean started = new AtomicBoolean(false);
    protected AtomicBoolean inited = new AtomicBoolean(false);

    public void init() {
        if (!inited.get()) {
            initService();
            inited.set(true);
            logger.debug("{} initialized.", this);
        }
    }

    public void start() {
        // Init service if it has not done so.
        if (!inited.get()) {
            init();
        }
        // Start service now.
        if (!started.get()) {
            startService();
            started.set(true);
            logger.debug("{} started.", this);
        }
    }

    public void stop() {
        if (started.get()) {
            stopService();
            started.set(false);
            logger.debug("{} stopped.", this);
        }
    }

    public void destroy() {
        // Stop service if it is still running.
        if (started.get()) {
            stop();
        }
        // Destroy service now.
        if (inited.get()) {
            destroyService();
            inited.set(false);
            logger.debug("{} destroyed.", this);
        }
    }

    public boolean isStarted() {
        return started.get();
    }

    public boolean isInited() {
        return inited.get();
    }

    @Override
    public String toString() {
            return getClass().getSimpleName() + "[id=" + System.identityHashCode(this) + "]";
    }

    protected void initService() {
    }

    protected void startService() {
    }

    protected void stopService() {
    }

    protected void destroyService() {
    }
}

This abstract class provide the basic of most services needs. It has a logger and states to keep track of the life-cycles. It then delegate new sets of life-cycle methods so subclass can choose to override. Notice that the start() method is checking auto calling init() if it hasn't already done so. Same is done in destroy() method to the stop() method. This is important if we're to use it in a container that only have two stages life-cycles invocation. In this case, we can simply invoke start() and destroy() to match to our service's life-cycles.

Some frameworks might go even further and create separate interfaces for each stage of the life-cycles, such as InitableService or StartableService etc. But I think that would be too much in a typical app. In most of the cases, you want something simple, so I like it just one interface. User may choose to ignore methods they don't want, or simply use an adaptor class.

Before we end this section, I would throw in a silly Hello world service that can be used in our demo later.

package servicedemo;

public class HelloService extends AbstractService {
    public void initService() {
        logger.info(this + " inited.");
    }
    public void startService() {
        logger.info(this + " started.");
    }
    public void stopService() {
        logger.info(this + " stopped.");
    }
    public void destroyService() {
        logger.info(this + " destroyed.");
    }
}

Managing multiple POJO Services with a container

Now we have the basic of Service definition defined, your development team may start writing business logic code! Before long, you will have a library of your own services to re-use. To be able group and control these services into an effetive way, we want also provide a container to manage them. The idea is that we typically want to control and manage multiple services with a container as a group in a higher level. Here is a simple implementation for you to get started:

package servicedemo;

import java.util.*;
public class ServiceContainer extends AbstractService {
    private List<Service> services = new ArrayList<Service>();

    public void setServices(List<Service> services) {
        this.services = services;
    }
    public void addService(Service service) {
        this.services.add(service);
    }

    public void initService() {
        logger.debug("Initializing " + this + " with " + services.size() + " services.");
        for (Service service : services) {
            logger.debug("Initializing " + service);
            service.init();
        }
        logger.info(this + " inited.");
    }
    public void startService() {
            logger.debug("Starting " + this + " with " + services.size() + " services.");
            for (Service service : services) {
                logger.debug("Starting " + service);
                service.start();
            }
            logger.info(this + " started.");
    }
    public void stopService() {
            int size = services.size();
            logger.debug("Stopping " + this + " with " + size + " services in reverse order.");
            for (int i = size - 1; i >= 0; i--) {
                Service service = services.get(i);
                logger.debug("Stopping " + service);
                service.stop();
            }
            logger.info(this + " stopped.");
    }
    public void destroyService() {
            int size = services.size();
            logger.debug("Destroying " + this + " with " + size + " services in reverse order.");
            for (int i = size - 1; i >= 0; i--) {
                Service service = services.get(i);
                logger.debug("Destroying " + service);
                service.destroy();
            }
            logger.info(this + " destroyed.");
    }
}

From above code, you will notice few important things:

  1. We extends the AbstractService, so a container is a service itself.
  2. We would invoke all service's life-cycles before moving to next. No services will start unless all others are inited.
  3. We should stop and destroy services in reverse order for most general use cases.

The above container implementation is simple and run in synchronized fashion. This mean, you start container, then all services will start in order you added them. Stop should be same but in reverse order.

I also hope you would able to see that there is plenty of room for you to improve this container as well. For example, you may add thread pool to control the execution of the services in asynchronized fashion.

Running POJO Services

Running services with a simple runner program.

In the simplest form, we can run our POJO services on our own without any fancy server or frameworks. Java programs start its life from a static main method, so we surely can invoke init and start of our services in there. But we also need to address the stop and destroy life-cycles when user shuts down the program (usually by hitting CTRL+C.) For this, the Java has the java.lang.Runtime#addShutdownHook() facility. You can create a simple stand-alone server to bootstrap Service like this:

package servicedemo;

import org.slf4j.*;
public class ServiceRunner {
    private static Logger logger = LoggerFactory.getLogger(ServiceRunner.class);

    public static void main(String[] args) {
        ServiceRunner main = new ServiceRunner();
        main.run(args);
    }

    public void run(String[] args) {
        if (args.length < 1)
            throw new RuntimeException("Missing service class name as argument.");

        String serviceClassName = args[0];
        try {
            logger.debug("Creating " + serviceClassName);
            Class<?> serviceClass = Class.forName(serviceClassName);
            if (!Service.class.isAssignableFrom(serviceClass)) {
                throw new RuntimeException("Service class " + serviceClassName + " did not implements " + Service.class.getName());
            }
            Object serviceObject = serviceClass.newInstance();
            Service service = (Service)serviceObject;

            registerShutdownHook(service);

            logger.debug("Starting service " + service);
            service.init();
            service.start();
            logger.info(service + " started.");

            synchronized(this) {
                this.wait();
            }
        } catch (Exception e) {
            throw new RuntimeException("Failed to create and run " + serviceClassName, e);
        }
    }

    private void registerShutdownHook(final Service service) {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                logger.debug("Stopping service " + service);
                service.stop();
                service.destroy();
                logger.info(service + " stopped.");
            }
        });
    }
}

With abover runner, you should able to run it with this command:

$ java demo.ServiceRunner servicedemo.HelloService

Look carefully, and you'll see that you have many options to run multiple services with above runner. Let me highlight couple:

  1. Improve above runner directly and make all args for each new service class name, instead of just first element.
  2. Or write a MultiLoaderService that will load multiple services you want. You may control argument passing using System Properties.

Can you think of other ways to improve this runner?

Running services with Spring

The Spring framework is an IoC container, and it's well known to be easy to work POJO, and Spring lets you wire your application together. This would be a perfect fit to use in our POJO services. However, with all the features Spring brings, it missed a easy to use, out of box main program to bootstrap spring config xml context files. But with what we built so far, this is actually an easy thing to do. Let's write one of our POJO Service to bootstrap a spring context file.

package servicedemo;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class SpringService extends AbstractService {
    private ConfigurableApplicationContext springContext;

    public void startService() {
        String springConfig = System.getProperty("springContext", "spring.xml);
        springContext = new FileSystemXmlApplicationContext(springConfig);
        logger.info(this + " started.");
    }
    public void stopService() {
        springContext.close();
        logger.info(this + " stopped.");
    }
}

With that simple SpringService you can run and load any spring xml file. For example try this:

$ java -DspringContext=config/service-demo-spring.xml demo.ServiceRunner servicedemo.SpringService

Inside the config/service-demo-spring.xml file, you can easily create our container that hosts one or more service in Spring beans.

<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="helloService" class="servicedemo.HelloService">
    </bean>

    <bean id="serviceContainer" class="servicedemo.ServiceContainer" init-method="start" destroy-method="destroy">
        <property name="services">
            <list>
                <ref bean="helloService"/>
            </list>
        </property>
    </bean>

</beans>

Notice that I only need to setup init-method and destroy-method once on the serviceContainer bean. You can then add one or more other service such as the helloService as much as you want. They will all be started, managed, and then shutdown when you close the Spring context.

Note that Spring context container did not explicitly have the same life-cycles as our services. The Spring context will automatically instanciate all your dependency beans, and then invoke all beans who's init-method is set. All that is done inside the constructor of FileSystemXmlApplicationContext. No explicit init method is called from user. However at the end, during stop of the service, Spring provide the springContext#close() to clean things up. Again, they do not differentiate stop from destroy. Because of this, we must merge our init and start into Spring's init state, and then merge stop and destroy into Spring's close state. Recall our AbstractService#destory will auto invoke stop if it hasn't already done so. So this is trick that we need to understand in order to use Spring effectively.

Running services with JEE app server

In a corporate env, we usually do not have the freedom to run what we want as a stand-alone program. Instead they usually have some infrustructure and stricter standard technology stack in place already, such as using a JEE application server. In these situation, the most portable way to run POJO services is in a war web application. In a Servlet web application, you can write a class that implements javax.servlet.ServletContextListener and this will provide you the life-cycles hook via contextInitialized and contextDestroyed. In there, you can instanciate your ServiceContainer object and call start and destroy methods accordingly.

Here is an example that you can explore:

package servicedemo;
import java.util.*;
import javax.servlet.*;
public class ServiceContainerListener implements ServletContextListener {
    private static Logger logger = LoggerFactory.getLogger(ServiceContainerListener.class);
    private ServiceContainer serviceContainer;

    public void contextInitialized(ServletContextEvent sce) {
        serviceContainer = new ServiceContainer();
        List<Service> services = createServices();
        serviceContainer.setServices(services);
        serviceContainer.start();
        logger.info(serviceContainer + " started in web application.");
    }

    public void contextDestroyed(ServletContextEvent sce) {
        serviceContainer.destroy();
        logger.info(serviceContainer + " destroyed in web application.");
    }

    private List<Service> createServices() {
        List<Service> result = new ArrayList<Service>();
        // populate services here.
        return result;
    }
}

You may configure above in the WEB-INF/web.xml like this:

    <listener>
        <listener-class>servicedemo.ServiceContainerListener</listener-class>
    </listener>

</web-app>

The demo provided a placeholder that you must add your services in code. But you can easily make that configurable using the web.xml for context parameters.

If you were to use Spring inside a Servlet container, you may directly use their org.springframework.web.context.ContextLoaderListener class that does pretty much same as above, except they allow you to specify their xml configuration file using the contextConfigLocation context parameter. That's how a typical Spring MVC based application is configure. Once you have this setup, you can experiment our POJO service just as the Spring xml sample given above to test things out. You should see our service in action by your logger output.

PS: Actually what we described here are simply related to Servlet web application, and not JEE specific. So you can use Tomcat server just fine as well.

The importance of Service's life-cycles and it's real world usage

All the information I presented here are not novelty, nor a killer design pattern. In fact they have been used in many popular open source projects. However, in my past experience at work, folks always manage to make these extremely complicated, and worse case is that they completely disregard the importance of life-cycles when writing services. It's true that not everything you going to write needs to be fitted into a service, but if you find the need, please do pay attention to them, and take good care that they do invoked properly. The last thing you want is to exit JVM without clean up in services that you allocated precious resources for. These would become more disastrous if you allow your application to be dynamically reloaded during deployment without exiting JVM, in which will lead to system resources leakage.

The above Service practice has been put into use in the TimeMachine project. In fact, if you look at the timemachine.scheduler.service.SchedulerEngine, it would just be a container of many services running together. And that's how user can extend the scheduler functionalities as well, by writing a Service. You can load these services dynamically by a simple properties file.

Tuesday, August 28, 2012

How to manage Quartz remotely

Option 1: JMX

Many people asked can they manage Quartz via JMX, and that the documentation on this is not clear enough to help them get started. So, let me highlight couple ways you can do this.

Yes you can enable JMX in quartz with the following in quartz.properties

org.quartz.scheduler.jmx.export = true

After this, you use standard JMX client such as $JAVA_HOME/bin/jconsole to connect and manage remotely.

Option 2: RMI

Another way to manage quartz remotely is to enable RMI in Quartz. If you use this, you basically run one instance of Quartz as RMI server, and then you can create second Quartz instance as RMI client. These two can talk remotely via a TCP port.

For server scheduler instance, you want to add these in quartz.properties

org.quartz.scheduler.rmi.export = true
org.quartz.scheduler.rmi.createRegistry = true
org.quartz.scheduler.rmi.registryHost = localhost
org.quartz.scheduler.rmi.registryPort = 1099
org.quartz.scheduler.rmi.serverPort = 1100

And for client scheduler instance, you want to add these in quartz.properties

org.quartz.scheduler.rmi.proxy = true
org.quartz.scheduler.rmi.registryHost = localhost
org.quartz.scheduler.rmi.registryPort = 1099

The RMI feature is mentioned in Quartz doc here. Quartz doesn't have a client API, but use the same org.quartz.Scheduler for both server and client. It's just the configuration are different. By different configuration, you get very different behavior. For server, your scheduler is running all the jobs, while for client, it's simply a proxy. Your client scheduler instance will not run any jobs! You must be really careful when shutting down client because it does allow you to bring down the server!

These configurations have been highlighted in the MySchedule project. If you run the webapp, you should see a screen like this demo, and you will see it provided many sample of quartz configurations with these remote managment config properties.

If configure with RMI option, you can actually still use MySchedule web UI to manage the Quartz as proxy. You can view and drill down jobs, and you can even stop or shutdown remote server!

Based on my experience, there is a down side of using Quartz RMI feature though. That is it creates a single point of failure. There is no fail over if your RMI server port is down!

Monday, August 27, 2012

Taming those Java editors on MacOSX

Today, I learned that you can open multiple Eclipse instances in MacOSX like this

$ open -n -a Eclipse

This comes pretty handy if you want a separate workspace per large project that has dozen or so modules (try importing the Camel or SpringFramework project source and you will see what I mean!)

The -a is for name of an application to open, and -n means to open with new instance.

Finding a programmer friendly text editor on MacOSX

Despite I use Eclipse for most of my large Java projects, I still often find myself the need of a plain text editor. I use plain text editor for most of my scripting programming. I also use it for notes taking, text file browsing, or even writing Blog post in markdown format!

I guess for most programmers, choosing an Editor is a very personally thing. So I am not here to convert anybody. However, for those who never heard of jEdit, you ought to give it a try. It's open source, full features, programmers friendly text editor that works across many of OS systems consistenly. It works because it's Java based! If you use one of decent computer now a day, the performance is excellent as well.

However, for some strange reason, the jedit installer on MacOSX doesn't comes with a normal java command line script wrapper. The only thing I can see is the actual binary under /Applications/jEdit.app/Contents/MacOS/jedit. We can certainly run this as full jedit command, but then it always liter the console with strange GUI warnings. So a better way to run it is actually to use the open command.

$ open -a jedit $HOME/.bash_profile

Or you can add this in your .bash_profile file:

function jedit(){ open -a jedit "$@" ; }

Now you can use jedit command on the terminal.

Some of my favorite features of jEdit

  • It's open source and has very active community of users.
  • It works across MacOSX, Windows and Linux Desktop.
  • Support many common programming language syntax highlights.
  • Support multi columns editing.
  • Support rich feature search (reg ex, hyper-search, all buffers search, search and replace etc.)
  • Support multi buffers tabs editing.
  • Supports Macro recording and scripting.
  • Support plugin extension and there are many external plugins available (eg: XML formater, Diff viewer, SFTP client/editing, etc).

Openning other stuff on MacOSX

The little open command can open not just application, but it can also open directories or files by extension associations. For example, to configure any .properties files to be open by jEdit, try the the following.

  1. Use Finder to browse and find one of properties
  2. Right click, "Open With" > "Other..."
  3. Choose "jEdit" under Applications folder.
  4. Enable "Always Open With", then click Open button.

This change should affect your Terminal open command as well, and if you run open my.properties, your jEdit should pop up.

You can find more options by running it without any options, and it will print you full help page.

Usage: open [-e] [-t] [-f] [-W] [-R] [-n] [-g] [-h] [-b <bundle identifier>] [-a <application>] [filenames] [--args arguments]
Help: Open opens files from a shell.
      By default, opens each file using the default application for that file.  
      If the file is in the form of a URL, the file will be opened as a URL.
Options: 
      -a                Opens with the specified application.
      -b                Opens with the specified application bundle identifier.
      -e                Opens with TextEdit.
      -t                Opens with default text editor.
      -f                Reads input from standard input and opens with TextEdit.
      -F  --fresh       Launches the app fresh, that is, without restoring windows. Saved persistent state is lost, excluding Untitled documents.
      -R, --reveal      Selects in the Finder instead of opening.
      -W, --wait-apps   Blocks until the used applications are closed (even if they were already running).
          --args        All remaining arguments are passed in argv to the application's main() function instead of opened.
      -n, --new         Open a new instance of the application even if one is already running.
      -j, --hide        Launches the app hidden.
      -g, --background  Does not bring the application to the foreground.
      -h, --header      Searches header file locations for headers matching the given filenames, and opens them.

Tuesday, August 21, 2012

myschedule-2.4.4 is out!

For those of you who are using Quartz, you might find MySchedule useful. I've made another minor release to upgrade it to latest Quartz 2.1.6 and few minor fixes. Enjoy!

Sunday, August 19, 2012

Getting started with Apache Camel using Groovy

From their site, it says the Apache Camel is a versatile open-source integration framework based on known Enterprise Integration Patterns. It might seem like a vague definition, but I want to tell you that this is a very productive Java library that can solve many of typical IT problems! You can think of it as a very light weight ESB framework with "batteries" included.

In every jobs I've been to so far, folks are writing their own solutions in one way or another to solve many common problems (or they would buy some very expensive enterprisy ESB servers that takes months and months to learn, config, and maintain). Things that we commonly solve are integration (glue) code of existing business services together, process data in a certain workflow manner, or move and transform data from one place to another etc. These are very typical need in many IT environments. The Apache Camel can be used in cases like these; not only that, but also in a very productive and effective way!

In this article, I will show you how to get started with Apache Camel along with just few lines of Groovy script. You can certainly also start off with a full Java project to try out Camel, but I find Groovy will give you the shortest working example and learning curve.

Getting started with Apache Camel using Groovy

So let's begin. First let's see a hello world demo with Camel + Groovy.

@Grab('org.apache.camel:camel-core:2.10.0')
@Grab('org.slf4j:slf4j-simple:1.6.6')
import org.apache.camel.*
import org.apache.camel.impl.*
import org.apache.camel.builder.*

def camelContext = new DefaultCamelContext()
camelContext.addRoutes(new RouteBuilder() {
    def void configure() {
        from("timer://jdkTimer?period=3000")
            .to("log://camelLogger?level=INFO")
    }
})
camelContext.start()

addShutdownHook{ camelContext.stop() }
synchronized(this){ this.wait() }

Save above into a file named helloCamel.groovy and then run it like this:

$ groovy helloCamel.groovy
388 [main] INFO org.apache.camel.impl.DefaultCamelContext - Apache Camel 2.10.0 (CamelContext: camel-1) is starting
445 [main] INFO org.apache.camel.management.ManagementStrategyFactory - JMX enabled.
447 [main] INFO org.apache.camel.management.DefaultManagementLifecycleStrategy - StatisticsLevel at All so enabling load performance statistics
678 [main] INFO org.apache.camel.impl.converter.DefaultTypeConverter - Loaded 170 type converters
882 [main] INFO org.apache.camel.impl.DefaultCamelContext - Route: route1 started and consuming from: Endpoint[timer://jdkTimer?period=3000]
883 [main] INFO org.apache.camel.impl.DefaultCamelContext - Total 1 routes, of which 1 is started.
887 [main] INFO org.apache.camel.impl.DefaultCamelContext - Apache Camel 2.10.0 (CamelContext: camel-1) started in 0.496 seconds
898 [Camel (camel-1) thread #1 - timer://jdkTimer] INFO camelLogger - Exchange[ExchangePattern:InOnly, BodyType:null, Body:[Body is null]]
3884 [Camel (camel-1) thread #1 - timer://jdkTimer] INFO camelLogger - Exchange[ExchangePattern:InOnly, BodyType:null, Body:[Body is null]]
6884 [Camel (camel-1) thread #1 - timer://jdkTimer] INFO camelLogger - Exchange[ExchangePattern:InOnly, BodyType:null, Body:[Body is null]]
...

The little script above is simple but it presented few key features of Camel Groovyness. The first and last section of the helloCamel.groovy script are just Groovy featuers. The @Grab annotation will automatically download the dependency jars you specify. We import Java packages to use its classes later. At the end we ensure to shutdown Camel before exiting JVM through the Java Shutdown Hook mechanism. The program will sit and wait until user press CTRL+C, just as a typical server process behavior.

The middle section is where the Camel action is. You would always create a Camel context to begin (think of it as the server or manager for the process.) And then you would add a Camel route (think of it as a workflow or pipeflow) that you like to process data (Camel likes to call these data "messages"). The route consists of a "from" starting point (where data generated), and one or more "to" points (where data going to be processed). Camel calls these destination 'points' as 'Endpoints'. These endpoints can be expressed in simple URI string format such as "timer://jdkTimer?period=3000". Here we are generating timer message in every 3 secs into the pipeflow, and then process by a logger URI, which will simply print to console output.

After Camel context started, it will start processing data through the workflow, as you can observe from the output example above. Now try pressing CTRL+C to end its process. Notice how the Camel will shutdown everything very gracefully.

7312 [Thread-2] INFO org.apache.camel.impl.DefaultCamelContext - Apache Camel 2.10.0 (CamelContext: camel-1) is shutting down
7312 [Thread-2] INFO org.apache.camel.impl.DefaultShutdownStrategy - Starting to graceful shutdown 1 routes (timeout 300 seconds)
7317 [Camel (camel-1) thread #2 - ShutdownTask] INFO org.apache.camel.impl.DefaultShutdownStrategy - Route: route1 shutdown complete, was consuming from: Endpoint[timer://jdkTimer?period=3000]
7317 [Thread-2] INFO org.apache.camel.impl.DefaultShutdownStrategy - Graceful shutdown of 1 routes completed in 0 seconds
7321 [Thread-2] INFO org.apache.camel.impl.converter.DefaultTypeConverter - TypeConverterRegistry utilization[attempts=2, hits=2, misses=0, failures=0] mappings[total=170, misses=0]
7322 [Thread-2] INFO org.apache.camel.impl.DefaultCamelContext - Apache Camel 2.10.0 (CamelContext: camel-1) is shutdown in 0.010 seconds. Uptime 7.053 seconds.

So that's our first taste of Camel ride! However, we titled this section as "Hello World!" demo, and yet we haven't seen any. But you might have also noticed that above script are mostly boiler plate code that we setup. No user logic has been added yet. Not even the logging the message part! We simply configuring the route.

Now let's modify the script little bit so we will actually add our user logic to process the timer message.

@Grab('org.apache.camel:camel-core:2.10.0')
@Grab('org.slf4j:slf4j-simple:1.6.6')
import org.apache.camel.*
import org.apache.camel.impl.*
import org.apache.camel.builder.*

def camelContext = new DefaultCamelContext()
camelContext.addRoutes(new RouteBuilder() {
    def void configure() {
        from("timer://jdkTimer?period=3000")
            .to("log://camelLogger?level=INFO")
            .process(new Processor() {
                def void process(Exchange exchange) {
                    println("Hello World!")
                }
            })
    }
})
camelContext.start()

addShutdownHook{ camelContext.stop() }
synchronized(this){ this.wait() }

Notice how I can simply append the process code part right after the to("log...") line. I have added a "processor" code block to process the timer message. The logic is simple: we greet the world on each tick.

Making Camel route more concise and practical

Now, do I have you at Hello yet? If not, then I hope you will be patient and continue to follow along for few more practical features of Camel. First, if you were to put Camel in real use, I would recommend you setup your business logic separately from the workflow route definition. This is so that you can clearly express and see your entire pipeflow of route at a glance. To do this, you want to move the "processor", into a service bean.

@Grab('org.apache.camel:camel-core:2.10.0')
@Grab('org.slf4j:slf4j-simple:1.6.6')
import org.apache.camel.*
import org.apache.camel.impl.*
import org.apache.camel.builder.*
import org.apache.camel.util.jndi.*

class SystemInfoService {
    def void run() {
        println("Hello World!")
    }
}
def jndiContext = new JndiContext();
jndiContext.bind("systemInfoPoller", new SystemInfoService())

def camelContext = new DefaultCamelContext(jndiContext)
camelContext.addRoutes(new RouteBuilder() {
    def void configure() {
        from("timer://jdkTimer?period=3000")
            .to("log://camelLogger?level=INFO")
            .to("bean://systemInfoPoller?method=run")
    }
})
camelContext.start()

addShutdownHook{ camelContext.stop() }
synchronized(this){ this.wait() }

Now, see how compact this workflow route has become? The Camel's Java DSL such as "from().to().to()" for defining route are so clean and simple to use. You can even show this code snip to your Business Analysts, and they would likely be able to verify your business flow easily! Wouldn't that alone worth a million dollars?

How about another demo: FilePoller Processing

File polling processing is a very common and effective way to solve many business problems. If you work for commercial companies long enough, you might have written one before. A typical file poller would process incoming files from a directory and then process the content, and then move the file into a output directory. Let's make a Camel route to do just that.

@Grab('org.apache.camel:camel-core:2.10.0')
@Grab('org.slf4j:slf4j-simple:1.6.6')
import org.apache.camel.*
import org.apache.camel.impl.*
import org.apache.camel.builder.*
import org.apache.camel.util.jndi.*

class UpperCaseTextService {
    def String transform(String text) {
        return text.toUpperCase()
    }
}
def jndiContext = new JndiContext();
jndiContext.bind("upperCaseTextService", new UpperCaseTextService())

def dataDir = "/${System.properties['user.home']}/test/file-poller-demo"
def camelContext = new DefaultCamelContext(jndiContext)
camelContext.addRoutes(new RouteBuilder() {
    def void configure() {
        from("file://${dataDir}/in")
            .to("log://camelLogger")
            .to("bean://upperCaseTextService?method=transform")
            .to("file://${dataDir}/out")
    }
})
camelContext.start()

addShutdownHook{ camelContext.stop() }
synchronized(this){ this.wait() }

Here you see I defined a route to poll a $HOME/test/file-poller-demo/in directory for text files. Once it's found it will log it to console, and then process by a service that transform the content text into upper case. After this, it will send the file into $HOME/test/file-poller-demo/out directory. My goodness, reading the Camel route above probably express what I wrote down just as effective. Do you see the benefits here?

What's the "batteries" included part.

If you've used Python programming before, you might have heard the pharase that they claim often: Python has "batteries" included. This means their interpreter comes with a rich of libaries for most of the common programming need. You can often write python program without have to download separated external libraries.

I am making similar analogies here with Apache Camel. The Camel project comes with so many ready to use components that you can find just about any transport protocals that can carry data. These Camel "components" are ones that support different 'Endpoint URI' that we have seen in our demos above. We have simply shown you timer, log, bean, and file components, but there are over 120 more. You will find jms, http, ftp, cfx, or tcp just to name a few.

The Camel project also has an option for you to define route in declarative xml format. The xml is just an extension of a Spring xml config with Camel's namespace handler added on top. Spring is optional in Camel, but you can use it together in a very powerful way.