@Singleton - The Simplest Possible JMX MXBean

You will need an interface:

public interface MonitoringResourceMXBean {
    Map getDiagnostics();
}
...and and a @Singleton implementation:
@Singleton
@Startup
public class MonitoringResource implements MonitoringResourceMXBean {


    private ConcurrentHashMap diagnostics = new ConcurrentHashMap();

    private MBeanServer platformMBeanServer;
    private ObjectName objectName = null;


    @PostConstruct
    public void registerInJMX() {
        this.exceptionCount = new AtomicLong();
        try {
            objectName = new ObjectName("XRayMonitoring:type=" + this.getClass().getName());
            platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
            platformMBeanServer.registerMBean(this, objectName);
        } catch (Exception e) {
            throw new IllegalStateException("Problem during registration of Monitoring into JMX:" + e);
        }
    }
//bookkeeping methods omitted

    @Override
    public Map getDiagnostics() {
        return diagnostics;
    }

    @PreDestroy
    public void unregisterFromJMX() {
        try {
            platformMBeanServer.unregisterMBean(this.objectName);
        } catch (Exception e) {
            throw new IllegalStateException("Problem during unregistration of Monitoring into JMX:" + e);
        }
    }
}

With the MXBean naming convention the contents of the exposed java.util.Map will be nicely rendered in JConsole / visualVM as a table. Exposed accessors will appear as fields and remaining methods as buttons...

A Singleton is a perfect MXBean, because:
  1. Its automatic (@Startup) registration and unregistration at the MBeanServer. This solves the redeployment issues like multiple registrations of the same bean
  2. Singleton is able to cache diagnostic state and expose it on demand
  3. Singleton can be injected to other components like Interceptors
  4. A Singleton can also receive events
  5. A Singleton can be exposed as a REST-resource

@Singleton is also a perfect cache (facade)...

The code above is an excerpt from the X-ray code. In X-ray JMX almost entirely replaced logging. Diagnostic events are fired from various components and aggregated in the MonitoringResource singleton. The MonitoringResource EJB is also exposed with JAX-RS what makes the statistics also accessible via HTTP. [See also page 77, section "Who Reads Logs—Or How to Monitor Your Application" in Real World Java EE Night Hacks--Dissecting the Business Tier. You will find the entire code in the GIT repo]

Comments:

A couple of comments:

1. Leaking a "this" reference from an EJB is not really an especially good thing to do - better to use SessionContext.getBusinessObject() I think. Especially if your singleton is going to hold state.

2. You should try to convince the EE EG to let you inject the MBeanServer using @Resource. Or at least get the Weld/Seam guys to implement a CDI portable extension that lets you do it using @Inject.

3. Actually most of the code above looks like it could be easily factored out into an AbstractEJMXBean superclass and reused by inheritance, or into a CDI portable extension and reused by an @MXBean annotation.

Posted by Gavin King on May 31, 2011 at 01:25 PM CEST #

@Gavin,

"Leaking a "this" reference from an EJB is not really an especially good thing to do - better to use SessionContext.getBusinessObject()"

A good point. I used "this" because the MXBean interface is not a business interface of the singleton. I will test it with SessionContext.getBusinessObject()

"You should try to convince the EE EG to let you inject the MBeanServer using @Resource. Or at least get the Weld/Seam guys to implement a CDI portable extension that lets you do it using @Inject."

A very good idea -> we should consider that.

" Actually most of the code above looks like it could be easily factored out into an AbstractEJMXBean superclass and reused by inheritance, or into a CDI portable extension and reused by an @MXBean annotation."

Yes -> but I'm not sure whether it would be still a "Simplest Possible Solution"

I assume Ceylon would solve this issue even more elegantly :-)

thanks for your comment!,

adam

Posted by Adam Bien on May 31, 2011 at 01:50 PM CEST #

Hi,

Again an inspiring post :-)

I used the singleton pattern to implement a JMX monitorable configuration injecter (see http://insidecoffe.blogspot.com/2011/05/configuration-parameter-injection-with.html).
However there are two things that took me some time to figure out:
1) In order to declare producer methods on the @javax.ejb.Singleton (which has an ...MXBean interface) I had to annotate it with @LocalBean, otherwise it refuses deployment with >>... must be declared on a business interface of Session bean<<
2) Methods called via JMX may also fire CDI Events. However there is a problem that the context class loader is not the one of the container when the JMX method is called and so I had to set it manualy. Otherwise I got an Exception during runtime saying >>java.lang.IllegalStateException: Singleton not set for sun.misc.Launcher$AppClassLoader@...<<

I would like to ask if using CDI (specially events) during JMX calls is not conform to the specification, if its a bug, or if its intended to switch the classloader manually. Any Idea?

Thx for your input!

Jan Wiemer

Posted by Jan Wiemer on May 31, 2011 at 03:39 PM CEST #

@Jan,

checkout x-ray: http://java.net/projects/x-ray

The here described Singleton receives CDI-events.

thanks for your comment!,

adam

Posted by Adam Bien on May 31, 2011 at 04:26 PM CEST #

@Adam,

wow, really fast reply :-)

I will have a look at the x-ray project again, but maybe my problem description was misleading. Receiving events in the Singleton was no problem.
The problem was firing an event from a method (like e.g. setValue) called via JMX from the jconsole. The thread executing the JMS call has a different context-classloader than the classloader used to load the web application...

Thanks for your reply!
Jan

Posted by 80.146.242.90 on May 31, 2011 at 04:52 PM CEST #

This would be so much easier if we had JMX annotations... Unfortunately that got dropped from Java7 for other 'more important' things like syntax sugar.

Posted by Jonathan Fisher on May 31, 2011 at 09:14 PM CEST #

@Gavin,

I'm trying it:

https://java.net/jira/browse/EJB_SPEC-7

thanks!,

adam

Posted by Adam Bien on June 18, 2011 at 01:11 PM CEST #

Very interesting, but how about deploying this singleton in cluster? there will be multiple instances

Posted by WANG CHI on July 22, 2011 at 07:23 AM CEST #

Great post, thanks. But I am also curious with Wang Chi's question. Is it possible to deploy this singleton in an AS7x cluster and still remain a singleton? If not, are there workarounds?

Posted by Patty on March 21, 2012 at 09:07 PM CET #

Hi Adam,

I have tried code like yours on JBoss 6.1 and could not get the MXBean registration to work. (JBoss complains that the MonitoringResource does not expose a management interface).

This is the same issue described in https://community.jboss.org/thread/167796 and the fix described there did the job for me, too.

If you happen to know the reason, I'd be glad to know.

Night Hacks is an awesome little book, BTW!

Jan

Posted by Jan Algermissen on April 02, 2012 at 12:03 AM CEST #

I implemented this pattern, but when the Singleton @Injects another @Stateless which again @Injects a bean that is @RequestScoped, I receive this Exception: WELD-001303 No active contexts for scope type javax.enterprise.context.RequestScoped

So it looks like, in this case (since it is a @Singleton), there is no RequestScope...

Any idea?

Posted by Darko Krizic on October 15, 2012 at 09:25 PM CEST #

This post really helped out. I appreciate it and thanks again.

Posted by sagneta on October 17, 2012 at 06:46 PM CEST #

Nice post! Thank you.
Would be interesting how to implement in the same simple stye an JMX client which hosts in JEE7. Considering it should receive JMX notifications.
Denis.

Posted by DenisL on July 18, 2013 at 03:14 PM CEST #

Hi, Can you suggest me books with main concentration on MXBeans.

Thanks.

Posted by Yaks on July 23, 2013 at 07:34 PM CEST #

One notice for JBoss users (related to JBoss AS 6.1.0 Community Edition).

Interface name has to finish with MBean instead with MXBean.

With MXBean you receive exception in MBean registration time: javax.management.NotCompliantMBeanException: Class does not expose a management interface: java.lang.Object

Posted by Aleksandar Brankovic on November 07, 2015 at 01:47 PM CET #

Post a Comment:
  • HTML Syntax: NOT allowed
...the last 150 posts
...the last 10 comments
License