Groovy, JMX and MBeans

It’s really easy to create a MBean, export it with the platform MBean server and access the bean with Groovy.
Here’s how (it’s more or less an extended rewrite of this post).

The main trick is to implement ApplicationContextAware, which let Spring call the setApplicationContext method with the prepared application context (not tried, could be even shorter: is autowiring with the type “ApplicationContext” possible as well?)

Java part

The ManagementFactory lets you register your MBean in the platform MBean server (used to serve the application context).
Important: The easiest way to access the MBean remotely is by providing -Dcom.sun.management.jmxremote.port=6666 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false as System parameters (VM arguments in Eclipse) – obviously, this is not very secure.

package com.commons.blog;

import java.lang.management.ManagementFactory;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class AppCtxGlobalExporter implements AppCtxGlobalExporterMBean, ApplicationContextAware {

	private ApplicationContext appCtx;

    public AppCtxGlobalExporter() {}

	public void setApplicationContext(ApplicationContext appCtx) throws BeansException {
		this.appCtx = appCtx;
    	initMBeanServer();
	}

	private void initMBeanServer() {
		try {
			ManagementFactory.getPlatformMBeanServer().
				registerMBean(this, new ObjectName("jmxsample:type=AppCtxGlobalMBeanExporter"));
		} catch (InstanceAlreadyExistsException e) {
            Logger.getLogger(AppCtxGlobalExporter.class.getName()).log(Level.SEVERE, null, e);
		} catch (MBeanRegistrationException e) {
            Logger.getLogger(AppCtxGlobalExporter.class.getName()).log(Level.SEVERE, null, e);
		} catch (NotCompliantMBeanException e) {
            Logger.getLogger(AppCtxGlobalExporter.class.getName()).log(Level.SEVERE, null, e);
		} catch (MalformedObjectNameException e) {
            Logger.getLogger(AppCtxGlobalExporter.class.getName()).log(Level.SEVERE, null, e);
		} catch (NullPointerException e) {
            Logger.getLogger(AppCtxGlobalExporter.class.getName()).log(Level.SEVERE, null, e);
		}
	}

    public String[] getBeanNames() {
    	return appCtx.getBeanDefinitionNames();
    }

}

with the interface:

package com.commons.blog;

public interface AppCtxGlobalExporterMBean {

    String[] getBeanNames();

}

Here the main class:

package com.commons.blog;

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

public class AppCtxRegistry {

	public static void main(String[] args) {
		ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
		SampleBean sample = (SampleBean) app.getBean("sample");
		System.out.println(sample);
		while(true) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

}

the sample bean is left out, it’s not important and could even be empty.
The important part is the applicationContext.xml, the bean which implements ApplicationContextAware must just be instantiated, the Method setApplicationContext is called with the appropriate appcontext on startup.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
   "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
  <bean class="com.commons.blog.AppCtxGlobalExporter"/>

  <bean id="sample" class="com.commons.blog.SampleBean"/>
</beans>

Now comes the fun (Groovy!) part:

import javax.management.ObjectName
import javax.management.remote.JMXConnectorFactory as JmxFactory
import javax.management.remote.JMXServiceURL as JmxUrl

class JmxClient {

    def jmx() {
        def serverUrl = 'service:jmx:rmi:///jndi/rmi://localhost:6666/jmxrmi'
        def server = JmxFactory.connect(new JmxUrl(serverUrl)).MBeanServerConnection
        def mbean = new GroovyMBean(server, "jmxsample:type=AppCtxGlobalMBeanExporter")
       	mbean.BeanNames.each {
        	println it
        }
    }

    public static void main(String[] args) {
        new JmxClient().jmx()
    }

}

Spring and Groovy, again…

No real news here, just another example for Spring and Groovy in a simple web project.

Github for server version is here.
Github for client version is here.

What does it do?

We needed a simple Request/Response Mock for SOAP Web Services. Since the real sending component uses EJB and Weblogic t3-protocol specific stuff, I wanted to decorate this component.
The simplest way seemed to create an own endpoint, which accepts the SOAP web service requests, searches for templates based on the payload-root-element and evaluates the determined template (which itself is a Groovy template).

How does it work?

Quite straightforward. If a directory with the file template.groovy and the name of the root element of the payload exists, the template is loaded and evaluated with the input data and finally returned by the DispatcherServlet.
Spring MVC is used, however it was not necessary for this little sample.
The most interesting part is the injection (with @Autowired) of the Groovy script (which resides in src/main/resources/, which is not really correct).

<!-- this is really important to start the annotation processing in Spring -->
<context:annotation-config/>

<!-- the controller is instantiated, via @Autowired the Groovy Script is set -->
<bean id="RequestMockController" class="com.mock.sample.RequestMockController"/>

<!-- local repository (must be changed most likely) -->
<bean id="localRepo" class="java.lang.String">
   <constructor-arg value="c:/temp/repo/"/>
</bean>

<!-- instantiate Groovy as a Spring bean -->
<lang:groovy id="xml" script-source="classpath:XmlToolImpl.groovy"/>

IMPORTANT: to be able to use Groovy-Spring beans, the Groovy object should implement a Java interface (which is then used in the Java code).

How do I test it?

Use the client code with the parameters supplied in the README.
The request could look like this:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wss="http://wsssample.com.mock.sample">
  <soapenv:Header/>
    <soapenv:Body>
      <wss:getString>
        <wss:name>?</wss:name>
      </wss:gettring>
   </soapenv:Body>
</soapenv:Envelope>

For this request to succeed, the file REPO/getString/template.groovy must exist (see resources).

Specials

In the sample, there is one special behaviour, which requires two passes – if the template returns something like “>redirect”, the request is redirected to the new file (this works one time only and is just included to easy the “dispatching or controller pattern”)

Groovy Spring

Though the not really persuading (Open Source) IDE support, Groovy is my favorite script language for the Java VM. To have at least simplest support for Groovy, the Eclipse Plugin can be used. However, do not expect too much of it – it seems to be quite unstable (there are some suspicious OOME under Linux), but the Syntax Highlighting is ok. It is said that IntelliJ has the best Groovy IDE support by far, but I didn’t test it.
There exists nice Spring support for Groovy – you can transparently use Java- and Groovybeans. Combining this with Maven makes it really easy to make Spring even groovier.

Preparation

  • Install Maven Plugin for Eclipse: http://m2eclipse.sonatype.org/update/
  • Create New Maven Project
  • Choose “Maven Quickstart” as artifact

Setup

This post will focus on the Groovy usage within Spring, therefore the use case is quite simple.

  • A central Java bean has a list of several beans (ie. resembles a workflow)
  • The injected beans must implement an interface ITestStep which is very generic (Object execute(Object))
  • Implementing an interface seems the only way to inject Groovybeans transparently

Code

The Maven POM:

<?xml version="1.0" encoding="UTF-8"?>
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>maven.groovy</groupId>
  <artifactId>maven.groovy</artifactId>
  <name>maven.groovy</name>
  <version>0.0.1-SNAPSHOT</version>
  <description/>
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring</artifactId>
      <version>2.5.1</version>
    </dependency>
    <dependency>
      <groupId>groovy</groupId>
      <artifactId>groovy</artifactId>
      <version>1.1-rc-1</version>
    </dependency>
  </dependencies>
</project>

The Spring config:

<?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.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd">

	<lang:groovy id="groovyTestStep"
		script-source="classpath:SimpleGroovyClass.groovy">
	</lang:groovy>

	<bean id="testFlow" class="de.groovysample.JavaGroovyTest">
<property name="testSteps">
	<list>
				<ref bean="groovyTestStep" />
			</list>
		</property>
	</bean>

</beans>

The Beans (ie. workflowsteps) interface:

package de.groovysample;

public interface ITestStep {

	Object execute(Object arg);

}

The Groovybean (NOTE: this gose to src/main/resources as SimpleGroovyClass.groovy):

import de.groovysample.ITestStep

class SimpleGroovyClass implements ITestStep {

	Object execute(Object arg) {
		println "groovy called with arg: $arg"
	}

}

The Workflow Javaclass the Groovybean is injected to:

package de.groovysample;

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

public class JavaGroovyTest {

	private List<ITestStep> testSteps = new ArrayList<ITestStep>();

	public void setTestSteps(List<ITestStep> testSteps) {
		this.testSteps = testSteps;
	}

	public Object execute(Object arg) {
		for (ITestStep testStep : testSteps) {
			testStep.execute(arg);
		}
		return null;
	}

}

and the Main class:

package de.groovysample;

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

public class Main {

	public static void main(String[] args) {
		ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
		JavaGroovyTest test = (JavaGroovyTest) app.getBean("testFlow");
		System.out.println(test.execute("called from Java"));
	}

}

Resulting in the overall project setup

That’s all, this way you can easily combine Java and Groovy beans (which must implement an interface).

Posted in Groovy, Maven. Tags: , . 1 Comment »