Tuesday, February 24, 2009

A Simple RestEasy Maven Archetype

I've been looking for better and faster ways to develop some of my solutions, while Gradle is quite promising in my opinion, I still prefer Apache Maven for collaborative projects, even Ant sounds good when you can predict any scenario for your application/project.

I had searching a lot about a RestEasy Archetype, but I haven't found. RestEasy is a project which Maven is strongly used, although I am not sure if I did my search properly, but just in case I create a simple RestEasy Archetype, which you can download from here.

Once you have Maven installed and configured, you just will unzip this zip file, and will type mvn install. You will see the following results into your console:

[INFO] [jar:jar]
[INFO] [install:install]
[INFO] Installing /Users/edgarsilva/redhat/dev/NetBeansProjects/resteasy-archetype/target/resteasy-archetype-1.0-SNAPSHOT.jar to /Users/edgarsilva/.m2/repository/org/jboss/resteasy/resteasy-archetype/1.0-SNAPSHOT/resteasy-archetype-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3 seconds
[INFO] Finished at: Wed Feb 25 04:26:00 BRT 2009
[INFO] Final Memory: 9M/16M
[INFO] ------------------------------------------------------------------------
edgar-silvas-macbook:resteasy-archetype edgarsilva$


Now, you are ready to create RestEasy projects using Maven Archetypes, to do that, you can use your preferred IDE or just can type in the console for instance, the following command:

mvn archetype:create -DarchetypeVersion=1.0-SNAPSHOT -Darchetype.interactive=false -DgroupId=sample -DarchetypeArtifactId=resteasy-archetype -Dversion=1.0-SNAPSHOT -DarchetypeGroupId=org.jboss.resteasy -DartifactId=sample

This command, will create a project called "sample" which contains everything you need for developing and deploying RestEasy Applications into JBoss Application Server.

In the following image, you can see the project opened using NetBeans:


If you run mvn:install you will see Maven in action downloading everything required for building your project. In addition, this archetype includes JBoss AppServer tasks, which you can use for deploying, starting or stooping the server anytime you want. After typing mvn install, this goal will compile and generated a war file into target folder, however you may call the command mvn jboss:start that you will see the following output:

[jsilva@jsilva esresteasy]$ mvn jboss:start
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'jboss'.
[INFO] artifact org.codehaus.mojo:jboss-maven-plugin: checking for updates from central
[INFO] ------------------------------------------------------------------------
[INFO] Building esresteasy
[INFO] task-segment: [jboss:start]
[INFO] ------------------------------------------------------------------------
[INFO] [jboss:start]
[INFO] Starting JBoss...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 second
[INFO] Finished at: Wed Feb 25 16:30:56 BRT 2009
[INFO] Final Memory: 3M/74M
[INFO] ------------------------------------------------------------------------
[jsilva@jsilva esresteasy]$


Not only starting JBoss AppServer, you are also able to deploy your application using the command: mvn jboss:deploy :

[jsilva@jsilva esresteasy]$ mvn jboss:deploy
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'jboss'.
[INFO] ------------------------------------------------------------------------
[INFO] Building esresteasy
[INFO] task-segment: [jboss:deploy]
[INFO] ------------------------------------------------------------------------
[INFO] [jboss:deploy]
[INFO] Deploying /opt/java/workspace/esresteasy/target/esresteasy.war to JBoss.
[INFO] No server specified for authentication - using defaults
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2 seconds
[INFO] Finished at: Wed Feb 25 16:39:41 BRT 2009
[INFO] Final Memory: 3M/74M
[INFO] ------------------------------------------------------------------------



If you look the JBossApp Server console you can see your project deployed into JBoss:

16:39:39,812 INFO [TomcatDeployment] deploy, ctxPath=/esresteasy, vfsUrl=
16:39:39,930 ERROR [STDERR] 52 [http-127.0.0.1-8080-1] INFO org.jboss.resteasy.plugins.providers - Added built in provider DataSourceProvider
16:39:39,935 ERROR [STDERR] 57 [http-127.0.0.1-8080-1] INFO org.jboss.resteasy.plugins.providers - Added built in provider DefaultTextPlain
16:39:39,936 ERROR [STDERR] 58 [http-127.0.0.1-8080-1] INFO org.jboss.resteasy.plugins.providers - Added built in provider org.jboss.resteasy.plugins.providers.StringTextStar
16:39:39,937 ERROR [STDERR] 59 [http-127.0.0.1-8080-1] INFO org.jboss.resteasy.plugins.providers - Added built in provider org.jboss.resteasy.plugins.providers.InputStreamProvider
16:39:39,939 ERROR [STDERR] 61 [http-127.0.0.1-8080-1] INFO org.jboss.resteasy.plugins.providers - Added built in provider org.jboss.resteasy.plugins.providers.ByteArrayProvider
16:39:39,941 ERROR [STDERR] 63 [http-127.0.0.1-8080-1] INFO org.jboss.resteasy.plugins.providers - Added built in provider org.jboss.resteasy.plugins.providers.FormUrlEncodedProvider
16:39:39,942 ERROR [STDERR] 64 [http-127.0.0.1-8080-1] INFO org.jboss.resteasy.plugins.providers - Added built in provider org.jboss.resteasy.plugins.providers.FormUrlEncodedProvider
16:39:39,944 ERROR [STDERR] 66 [http-127.0.0.1-8080-1] INFO org.jboss.resteasy.plugins.providers - Added built in provider org.jboss.resteasy.plugins.providers.StreamingOutputProvider
16:39:39,950 ERROR [STDERR] 72 [http-127.0.0.1-8080-1] INFO org.jboss.resteasy.plugins.providers - Adding built in provider org.jboss.resteasy.plugins.providers.IIOImageProvider
16:39:40,084 ERROR [STDERR] 206 [http-127.0.0.1-8080-1] INFO org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap - Adding scanned resource: esresteasy.Hello
16:39:40,087 INFO [STDOUT] FOUND JAX-RS resource: esresteasy.Hello



I am looking for an easy way to pass information of some users inputs to fill some information into my pom.xml, the same strategy used in seam-gen for instance and also in esb-gen, but I am still looking for how to do that.

Seems that Maven Archetype is changing or moving for a next generation (http://docs.codehaus.org/display/MAVEN/ArchetypeNG) , hopefully the actual archetypes are still working fine.

Friday, February 13, 2009

Combining ApacheCamel+BSF to make JBoss ESB polyglot

Some time ago I published here one of the ways I built for integrating services such as Apache Camel into JBoss ESB.

Hopefully Tom Fennelly (JBoss ESB CoreDev) also published an awesome documentation in how create new Listeners into JBoss via Schedulers, as I had done, in addition showing how do that using Groovy, which in my opinion is much better, safer and easier, I will show you the new implementation here right now.

When do I need new Listener into JBoss ESB?


Many many times I faced situations where some customers have unpredictable scenarios related with integration, that's why I liked Apache Camel since the first moment I had contact with! You can find out a clear and easy programming model(using DSLs), and a very nice set of components for integrating even with some providers not available in JBoss, like JBI(ServiceMix), Esper(CEP/ESP) etc.


Groovy in Action into ESB

Once the events in Camel happens into an specific RouteBuilder object, I just want to make it available as a "Service", so once JBoss ESB is running, the Camel is ready to answer any event.

To make it possible, I just created a classes called ApacheCamelListener, where I must fill some life-cycle methods, in order to ensure that everything will be executed properly in runtime, see the class: ApacheCamelListener.java:



package org.jboss.soa.esb.integration.apache.camel;

import java.io.File;
import java.util.logging.Logger;

import org.apache.bsf.BSFEngine;
import org.apache.bsf.BSFManager;
import org.apache.camel.CamelContext;
import org.apache.camel.impl.DefaultCamelContext;
import org.jboss.soa.esb.ConfigurationException;
import org.jboss.soa.esb.helpers.ConfigTree;
import org.jboss.soa.esb.listeners.message.ActionProcessingPipeline;
import org.jboss.soa.esb.util.FileUtil;

public class ApacheCamelListener {

private ActionProcessingPipeline pipeline;

protected CamelContext context = new DefaultCamelContext();

protected Logger log;

protected boolean started = false;

public ApacheCamelListener() {
log = Logger.getLogger(ApacheCamelListener.class.getName());
}

public void start(ConfigTree config) throws ConfigurationException {
// Create and initialize the pipeline..
pipeline = new ActionProcessingPipeline(config);
pipeline.initialise();
log.info("Initilizing ApacheCamel into JBoss Esb Server ....");
if (!started) {
CamelContext context = new DefaultCamelContext();

try {

log.info("...Adding Routes");

File scriptsDir = new File((config.getAttribute("scripts-folder")));

File[] scripts = scriptsDir.listFiles();

if (null != scripts && scripts.length>0) {

String theScript = null;

JBossEsbRoute router = null;

BSFManager manager = new BSFManager();

BSFEngine bsfEngine = manager.loadScriptingEngine(config.getAttribute("script-language"));

for (File file : scripts) {

theScript = FileUtil.readTextFile(file);

router = (JBossEsbRoute) bsfEngine.eval(config.getAttribute("script-language"), 0, 0, theScript);

log.info(router.toString());

context.addRoutes(new ScriptingRoute(router));

}

}

} catch (Exception e) {

e.printStackTrace();

}

try {
context.start();
started = true;
log.info("Camel is ready and waiting events");

} catch (Exception e) {

e.printStackTrace();
}
}

}

public void stop() {
try {

started = false;

try {
context.stop();

} catch (Exception e) {

log.info("Error trying close Camel Context: " + e.getMessage());
}

} finally {
if (pipeline != null) {
pipeline.destroy();
}
}
}

}

Time for Innovating : Putting Ruby, Groovy and other scripting language to dispatch messages to existing Services

You can use JBoss jBPM Actions to call deployed Services, based in the service name, service category and the variables, so what I did is basically is allow users via Camel listen many others components and call an existing Service, the following image can describe my idea:


Basically when I configure my ApacheCamelListener, I can configure the "scripts-folder" and "script-language" properties for my listener, these propertis basically works to tell where in the filesystem this listener will looking for "other dinamic listeners", and then you can tell the orign of the event, and when some message/even happens in the provider, it will be forwarded via ServiceInvoker converting a Camel Message to an ESB Message Aware. See the Listener configuration:




Or you can simply see the jboss-esb.xml configuration here:



Now, I can use a Ruby Script to invoke some service from my ESB Server, and using a IRC room to interact with JBoss ESB.


require 'java'
include_class 'org.jboss.soa.esb.integration.apache.camel.JBossEsbRoute'
route = JBossEsbRoute.new
route.from = 'irc:localhost:667#room1'
route.to = 'irc:localhost:667#room2'
route.serviceCategory= 'Transformadores'
route.serviceName = 'TransformaChamadaXMLparaISO'
return route




In Apache Camel, I must pass a org.apache.camel.builder.RouteBuilder, to say how interact with the message arrived in the configured protocol. To do that, I extended this class for a JBossEsbRoute, as you can see in the following code-listing:



package org.jboss.soa.esb.integration.apache.camel;

public class JBossEsbRoute {

private String serviceName;
private String serviceCategory;
private String from;
private String to;


public JBossEsbRoute() {
// TODO Auto-generated constructor stub
}

@Override
public String toString() {
return String.format("This ServiceInvoker will listen events from %s " +
"and will forward to Service %s from category %s and route to %s",
this.from,this.serviceName,this.serviceCategory, this.to);
}

public JBossEsbRoute(String serviceName, String category, String from, String to) {

this.serviceName = serviceName;
this.serviceCategory = category;
this.from = from;
this.to = to;
}


Here is my extension for Camel understands any script written in PHP, ruby or perl etc, and make it integrated with JBoss ESB:



package org.jboss.soa.esb.integration.apache.camel;

import org.apache.camel.Exchange;
import org.apache.camel.Processor;

public class ScriptingRoute extends org.apache.camel.builder.RouteBuilder {

protected JBossEsbRoute route;

public ScriptingRoute() {
// TODO Auto-generated constructor stub
}

public ScriptingRoute(JBossEsbRoute r) {

this.route = r;

}


@Override
public void configure() throws Exception {

from(route.getFrom()).process(
new Processor() {
public void process(Exchange e) {

Object message = e.getIn().getBody();

System.out.println("#########" +
e.getContext().getExchangeConverter().convertTo(String.class, e));


System.out.println("Received event: " + message);


}
}).to(route.getTo());


}



The Ruby Script, basically creates a new Instance of JBossEsbRoute, which I can use to register a new Event Listener as well as a Invoker for an existing Services hosted into JBoss ESB. The following code-listing will allow you figure out how it is done:




String theScript = null;

JBossEsbRoute router = null;

BSFManager manager = new BSFManager();

BSFEngine bsfEngine = manager.loadScriptingEngine(config.getAttribute("script-language"));

for (File file : scripts) {

theScript = FileUtil.readTextFile(file);

router = (JBossEsbRoute) bsfEngine.eval(config.getAttribute("script-language"), 0, 0, theScript);

log.info(router.toString());

context.addRoutes(new ScriptingRoute(router));

}

}


Now, any language supported by Bean Scripting Framework can be used to invoke services into JBoss ESB, using Apache Camel for Events notifying and even forwarding after get processed into JBoss ESB pipelines.

I will be updating the sources and publishing in GitHub, if you are interested in that idea, reach me via email into edgarsilva (using) gmail.com.

Hope you enjoy!

ps- JBoss Esb 4.5 with Embedded Console is really great!