A JavaEE application with a multi-tier application generally has a presentation layer running in a servlet engine, a business logic layer running in a EJB container and a persistence layer facilitating JPA. During the development often there are occasions where a new functionality in the business logic (called backend from now on), which has no corresponding code in the presentation layer (let’s name it frontend), yet. So, what you need is a way to try out your code. This post shows you how to use the groovy shell to connect via JNDI to your remote session beans and call them in order to test your application fast. You may use it for a fast monitoring or maintenance API to your system, too. The groovy code of your efforts to test your code (monitor your application) may even be read from the history of the groovy shell and compiled into byte code. This code may be called from a test case or in a monitoring software (like nagios).
At first download the latest groovy binary from codehaus. Second, unpack it to a folder you like, add ${GROOVY_HOME}/bin
to environment variable PATH and export a new environment variable called GROOVY_HOME
pointing at the main directory of the groovy installation. On a UNIX system you may add this to your ~/.profile
or ~/.bashrc
. source
your changed config like this: . ~/.bashrc
. Start groovysh
in order to create the .groovy
-directory in your home directory. Copy the following grapeConfig.xml
to this directory:
<?xml version="1.0"?> <ivysettings> <settings defaultResolver="downloadGrapes" checkmodified="true" checkUpToDate="true" changingPattern=".*-SNAPSHOT"/> <resolvers> <chain name="downloadGrapes"> <filesystem name="cachedGrapes"> <ivy pattern= "${user.home}/.groovy/grapes/[organisation]/[module]/ivy-[revision].xml"/> <artifact pattern= "${user.home}/.groovy/grapes/[organisation]/[module]/[type]s/[artifact]-[revision].[ext]"/> </filesystem> <ibiblio name="ibiblio" m2compatible="true"/> <ibiblio name="JBoss Maven Repo" root="http://repository.jboss.com/maven2/" m2compatible="true" /> <ibiblio name="localM2" root="file://${user.home}/.m2/repository" m2compatible="true" /> </chain> </resolvers> </ivysettings>
The order of resolvers in the chain is important. Don’t put your local m2 repository at the beginning of the chain. Maven 3.0.x seems to omit some jars and download the pom files only. This leads to download failures in Grapes. What we have done so far is install groovy and setup Ivy for dependency resolving with Grape.
Next, you should add a little maven project, handling the retrieval of the remote session beans and the authentication to the jboss for us. Use the following pom.xml:
<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>my.group.id</groupId> <artifactId>myapp-cli</artifactId> <version>0.0.1</version> <name>MYAPP - Command Line Interface</name> <description>A small package, which can be used in a script interpretert like groovy shell for a command line interface to myapp</description> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>jboss</groupId> <artifactId>jbosssx-client</artifactId> <version>3.2.3</version> </dependency> <dependency> <groupId>org.jboss.security</groupId> <artifactId>jboss-security-spi</artifactId> <version>2.0.4</version> </dependency> <dependency> <groupId>org.jboss.jbossas</groupId> <artifactId>jboss-as-client</artifactId> <version>5.1.0.GA</version> <type>pom</type> </dependency> <dependency> <groupId>my.group.id</groupId> <artifactId>myapp-backend-api</artifactId> <version>SNAPSHOT</version> <type>jar</type> <scope>compile</scope> </dependency> </dependencies> <repositories> <repository> <id>JBoss Maven Repo</id> <name>JBoss Maven Repo</name> <url>http://repository.jboss.com/maven2/</url> </repository> </repositories> </project>
In src/main/resources/
you will need an auth.conf
like this, for authentication with jaas to the jboss:
myapp { org.jboss.security.ClientLoginModule required debug=true; };
Last but not least you need a util class connecting to jboss, authenticate via jaas and retrieve the session bean from JNDI:
public class BeanLoaderUtil { private static MySessionBeanRemote mySB; public static void login(String host, String port, String username, String password) throws Exception { ClassLoader cl = ControllerUtil.class.getClassLoader(); // The context class loader does not do anything in the // groovy shell, so we replace him by the classloader of the class. // This will help jaas code to load the class ClientLoginModule. Thread.currentThread().setContextClassLoader(cl); URL authconf = cl.getResource("auth.conf"); String p = URLDecoder.decode(authconf.toExternalForm(), "UTF-8"); System.setProperty("java.security.auth.login.config", p); loginContext = new LoginContext("myapp", new UsernamePasswordHandler(username, password)); loginContext.login(); Properties env = new Properties(); env.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.JndiLoginInitialContextFactory"); env.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces"); env.setProperty("java.naming.factory.initial", "org.jboss.naming.NamingContextFactory"); env.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces"); env.setProperty("java.naming.provider.url", "jnp://" + host +":" + port); InitialContext ctx = new InitialContext(env); try { mySB = (MySessionBeanRemote) ctx.lookup("MySessionBean/remote"); } finally { ctx.close(); } } public static void logout() throws Exception { if(loginContext != null) { loginContext.logout(); } } public static PaperController getMySB() { return mySB; } public static void main(String args[]) throws Exception { login("localhost", "1099", "myuser", "mypwd"); } }
The mvn clean install
the artifact myapp-cli-0.0.1.jar
will be installed in the local repository. We could use grape in the groovy shell in order to load the myapp-cli artifact and import the BeanLoaderUtil in order to start working with your beans, but unfortunately is the Grape-class not very verbose, so lets load all the transitive dependencies with the grape
command line tool instead:
$ grape install my.group.id myapp-cli 0.0.1 :: loading settings :: url = jar:file:/opt/groovy-1.7.10/lib/ivy-2.2.0.jar!/org/apache/ivy/core/settings/ivysettings.xml :: resolving dependencies :: caller#all-caller;working confs: [default] found my.group.id#myapp-cli;0.0.1 in localM2 found jboss#jbosssx-client;3.2.3 in ibiblio found org.jboss.security#jboss-security-spi;2.0.4 in JBoss Maven Repo found org.jboss.jbossas#jboss-as-client;5.1.0.GA in JBoss Maven Repo found commons-logging#commons-logging;1.1.0.jboss in JBoss Maven Repo found oswego-concurrent#concurrent;1.3.4-jboss-update1 in JBoss Maven Repo found org.hibernate#ejb3-persistence;1.0.2.GA in ibiblio found org.hibernate#hibernate-annotations;3.4.0.GA in ibiblio found org.hibernate#hibernate-commons-annotations;3.1.0.GA in ibiblio found org.slf4j#slf4j-api;1.5.6 in ibiblio ...
There may be problems loading some artifacts, as your maven repository has grown uncontrolled over different maven versions. If this is the case, try deleting your local maven repository or parts of it (it is only a cache), in order to get it up and running. The grape command will be really slow the first time, because it checks all resolvers for every dependency and downloads/copies it to the local grapeCache. So, further calls will be much faster (though they are still slow…). As soon as the grape install
command returns successfully start the groovy shell and type the following statements:
groovy:000> import static groovy.grape.Grape.*; ===> [import static groovy.grape.Grape.*;] groovy:000> grab([group:"my.group.id", module:"myapp-cli", version:"0.0.1"]); ===> null groovy:000> import static my.group.id.BeanLoaderUtil.*; ===> [import static groovy.grape.Grape.*;, import static my.group.id.BeanLoaderUtil.*;] groovy:000> login("localhost", "1099", "myuser", "mypwd"); ===> null groovy:000> mySB = getMySB(); ===> Proxy to jboss.j2ee:ear=myapp-SNAPSHOT.ear,jar=myapp-backend-impl-SNAPSHOT.jar,name=MySessionBean,service=EJB3 implementing [interface my.group.id.backend.MySessionBeanRemote] groovy:000> myPojo = mySB.getFoo("The incredible foo bar"); ===> Foo[id=1,version=10,longName=The incredible foo bar] groovy:000> println myPojo.longName; The incredible foo bar ===> null
Of course you need a jboss up and runnning, listening on jndi port 1099 with a corresponding EJB application. Jeehaa!
Addendum
If you are encountering EJBAccess
exceptions you might try to change the authentication type. Replace lines 11-17 in your BeanLoaderUtil
with the following code:
SecurityClient client = SecurityClientFactory.getSecurityClient(); client.setSimple(username, password); client.login();
You won’t need the auth.conf anymore, too.