1 2 3 Previous Next

emcmanus

87 posts

 I feel a bit guilty saying bad things about Apache Ant.  It's free, it's available everywhere,         and a lot of volunteers have put a lot of work into making it what it is.  You can very         quickly and easily make a build file for simple Java projects.  But.         It seems to have been more accreted than designed, and if you try to use the core system to accomplish         anything outside the most basic stuff you can look forward to hours staring alternately at those         horribly illegible XML files and that huge and frustratingly disorganized online manual.  So I         was pleasantly surprised recently to realize that you can use JavaScript directly inside your         build.xml files to avoid having to fight with Ant's enormous but haphazard collection of concepts         and tags.

It could well be that I am the last person in the world to learn this and that everyone else         has been using JavaScript to work around Ant's deficiencies since         2001.  Perhaps not,         though, because it used to be the case that if you wanted to use a scripting language with         Ant then you needed to go off and get the relevant jars and put them where Ant could find them.         What's changed is that you can now pretty much assume that you will have at least JDK 6 everywhere         (it came out in December 2006), which means you automatically have a JavaScript engine.  If Ant is         running on JDK 6, it can find and use this engine without any configuration.

This is not the only solution when you run up against the limits of what         you can straightforwardly do with Ant.  Several other approaches exist.  One is to use         XSLT to generate your build.xml files.  I think that should only ever be the very last of         last resorts.  Imagine someone coming upon your system for the first time and trying to         understand how it works.  Where do they start?  How do they find out what will actually         happen when the system is built? Where do they start if they need to change something?  If there's one thing I've learnt over the years it's that         an extra degree of "meta-ness" dramatically increases the difficulty of learning and using         a system.  Certainly it can also make it more powerful, but in this case there are less         meta-ish alternatives that are no less powerful.

A second approach is to write your own Ant tasks         using Java code.  Aside from the constant nagging question "why I am having to do this?"         as you do so, the result is again a build system that is hard to understand.  Part of your         build file will be devoted to compiling the custom tasks; and of course the source of those         tasks, showing what they actually do, is off in some other files somewhere.

A third approach is to use ant-contrib to add to         Ant things that should already be there, in particular the <if> and especially <for>         constructs.  (I'm sure I'm not alone in finding it completely inexplicable that Ant still does         not come with these tasks as standard.)  The right way to use ant-contrib is not to         plonk it in your Ant install directory, because then you're using a non-standard Ant and your         projects will not work if you transfer them to another machine.  Instead, you should copy         ant-contrib-1.0b3.jar (or whatever the version is) into the lib directory of your project, and         explicitly activate it in your build.xml with a line like this:

<taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${basedir}/lib/ant-contrib-1.0b3.jar" />

Using ant-contrib is actually a fine solution to many of the most annoying Ant deficiencies, and you         may prefer it to the final approach, which is my subject here: using JavaScript.

Using JavaScript in Ant tasks

Here is a complete Ant project that says hello using JavaScript:

    <?xml version="1.0" encoding="UTF-8"?>
    <project name="hello" default="default">
        <target name="default">
            <script language="javascript">println("hello, world")</script>
        </target>
    </project>
    

Now, the first thing to say is that I am living dangerously here.  If ever my script contained a         character with meaning to XML (basically < and &) then the whole Ant build would fail         with a mysterious parse error.  So to avoid that danger, I need to add some extra XML gobbledygook         (you can tell I love XML very very much):

        <script language="javascript"><![CDATA[
            println("hello, world")
        ]]></script>
    

Obviously I could have achieved as much with the <echo> task, so let's look at a real problem.

Checking classpath dependencies

Probably Zig and Zag and Dustin the first time I realized that I didn't like Ant very much was when I tried to solve the         following problem.  I was working on a big application that had been split into several Ant projects.         One of these projects (call it Big) depended on a number of other projects (let's say Zig and Zag).         We were using NetBeans, which is quite good at managing inter-project dependencies.  It automatically         set things up so when I built Big it would first build Zig and Zag.  The problem is that Big needed         the resulting Zig.jar and Zag.jar, and it used them in a very expensive processing step that would         take about 30 seconds.  So I really wanted to ensure that that processing step would only happen         if a new Zig.jar or Zag.jar had been built.         If building Zig and Zag had made no change,         because Zig.jar and Zag.jar already existed, then I didn't want to reconstruct Big for nothing.

The obvious way to solve this problem would be to insert a simple <uptodate> check in Big's         build.xml that would test whether Big.jar was more recent than Zig.jar and Zag.jar.  I didn't much         like that, though.  What if I added a new dependency, on project Zog?  Would I have to remember to         add Zog to the <uptodate> check?  Surely I could write things in a way that didn't require me         to list the upstream jars explicitly.  Surely I could derive that list from something that NetBeans         would set automatically when the project dependencies changed.  Surely.

Let's state the problem a bit more formally.  I have a property ${javac.classpath} that contains         a list of jars and directories separated by File.pathSeparator.         I want to set a property ${jar.up.to.date} only if Big.jar is more recent than every jar         mentioned in ${javac.classpath}.  I think it should be straightforward to do that in Ant, and it         might even be that there is a straightforward way to do it, but even after spending         hours puzzling over filesets and selectors and filterchains and resources and patternsets I never         succeeded in finding one.  Something is wrong when you have to spend endless time trying to see if it         is possible to fit the random available jigsaw pieces together to make up the picture you want.         I basically ended up writing ${javac.classpath} to a file and performing         a series of transformations on that file so that it ended up being the required <uptodate>         definition, which I could read in using <import>.  Ugh.

Here's how I could solve that problem with the <for> construct which ought to be in Ant but is         at least in ant-contrib:

    <for list="${javac.classpath}" delimiter="${path.separator}" param="jar">
        <sequential>
            <condition property="jar.out.of.date">
                <and>
                    <matches string="@{jar}" pattern=".*\.jar" />
                    <not>
                        <and>
                            <available file="@{jar}" />
                            <uptodate srcfile="@{jar}" targetfile="${dist.jar}" />
                        </and>
                    </not>
                </and>
            </condition>
        </sequential>
    </for>
    

(It's easier to compute "not up to date" and use "unless=" here; each loop iteration gets a         chance to set jar.out.of.date and it only remains unset if no iteration sets it.  Once it's set         a property stays set, so there's no easy way to achieve the opposite effect, though of course         I could then set jar.up.to.date based on jar.out.of.date.)

But maybe I don't feel like fighting against Ant and XML today, searching through the manual         to find the magic <sequential> and <condition> and <available> tags I need.  What         would I write if I used JavaScript instead?

    <script language="javascript"><![CDATA[
        importClass(java.io.File)
        var base = new File(basedir)
        var targetJarName = project.getProperty("dist.jar")
        var targetJar = new File(base, targetJarName)
        var classpath = project.getProperty("javac.classpath")
        var parts = classpath.split(File.pathSeparator)
        var uptodate = targetJar.exists()
        for each (var part in parts) {
            if (part.endsWith(".jar")) {
                var jar = new File(base, part)
                uptodate &= jar.exists() && jar.lastModified() < targetJar.lastModified()
            }
        }
        if (uptodate) {
            project.setProperty("jar.up.to.date", "true")
        }
    ]]></script>
    

That's arguably no simpler than the <for> version, though it is vastly simpler than my         solution with writing out files and <import>ing them again.  But the big win is really         familiarity: every Java developer should know enough JavaScript syntax and enough of         the basic Java APIs to understand what is going on here.  Relatively few         developers are so unfortunate as to have had to master enough Ant arcana to be able to         plunge without fear into the <for> version.

You do need to know a few basic things about the environment in which scripts execute:

       
  • The script variable project is set to Ant's Project         object, and you can use it to get and set Ant properties with getProperty         and setProperty         (or, better, setNewProperty),             as above, as well as executing other tasks and even adding new targets.
  •    
  • Every property, target, and resource collection (such as filesets and dirsets) whose name         is a valid JavaScript identifier appears as a script variable of the same name.  That's         how we can reference ${basedir} as above.
  •    
  • As in the first example, println() is available         if you need to debug your script.
  •    
  • You cannot assume that you are executing in any particular         directory so in general you will need to make absolute File values using         basedir as above, or project.getBaseDir()         which is already a File.

(Incidentally I share Attila Szegedi's mystification at the absence of online Ant API docs at apache.org.)

You have the full power of the standard Java APIs available to you, but you also have access to         Ant's APIs if you prefer to         use Ant's internal logic to solve the problems it's best at, such as dependency checking.  For         example, another way to write the script above, which is more like the <for> version, is         this:

    <macrodef name="check-against-jar">
        <attribute name="jar" />
        <sequential>
            <condition property="jar.out.of.date">
                <not>
                    <and>
                        <available file="@{jar}" />
                        <uptodate srcfile="@{jar}" targetfile="${dist.jar}" />
                    </and>
                </not>
            </condition>
        </sequential>
    </macrodef>
    <script language="javascript"><![CDATA[
        importClass(java.io.File)
        var classpath = project.getProperty("javac.classpath")
        var parts = classpath.split(File.pathSeparator)
        for each (var part in parts) {
            if (part.endsWith(".jar")) {
                var checkAgainstJar = project.createTask("check-against-jar")
                // println(checkAgainstJar.getClass()) to discover that it's a MacroInstance
                checkAgainstJar.setDynamicAttribute("jar", part)
                checkAgainstJar.execute()
            }
        }
    ]]></script>
    

So now when I'm faced with a problem that doesn't seem to be easy to solve with plain Ant, I know         I have two alternatives to banging my head against the wall of Ant's obtuseness: ant-contrib and         Blue Meanies         JavaScript.

But what do I know?

 I've hacked my fair share of buildfiles but I wouldn't consider that I'm any kind         of expert on Ant.         Am I being unduly mean in my opinions?         Is it actually really easy to solve problems like mine but I am too dim to see?         Have all the cool kids abandoned Ant long ago to move on to a shiny new alternative?         Let me know in the comments.

Here is the text of the message I recently sent to the JSR 255     Expert Group, in my capacity as Specification Lead.

 
   

Dear experts,

   

I'm sure that you saw some months ago that our work on JSR 255       will not be part of the JDK 7 release       (http://openjdk.java.net/projects/jdk7/features/). This       decision was made here at Sun in order that some of the higher       priority features could be properly resourced, in particular for       the TCK work.

   

So, we need to retarget our work for JDK 8. This note is to       give you an update on how I plan on handling that properly.

   

Over the next month or so, I'll be setting up a new OpenJDK       project called "JMX2" where the Reference Implementation work       for JSR 255 will live. This means that all our specification and       RI work on JSR 255 will continue to be available to all to       evaluate, critique and try out, and it will be up to date with       the stable JDK milestone releases.

   

In order to do this, I will prepare a big changeset (call it       the "undo changeset"), which will change the JMX API back to       what it was in JDK 6, and apply that to JDK 7. Then, I will kick       off the new workspace as a clone of the JDK 7 repository,       including the undo changeset. I will immediately apply a       "backout" changeset that undoes the undo (using Mercurial's       backout command), so JMX2 is where JDK 7 was before I       started.

   

I hope to have better news about making progress with the TCK       as the JDK team starts planning JDK 8, which is likely to be       towards the end of the JDK 7 cycle       (http://openjdk.java.net/projects/jdk7/calendar/),       at the beginning of next year.

 

The MXBean       framework gives you a way to define MBeans with custom       types, and map those types to standard       ("open")       types so generic clients can deal with them.  Sometimes you want       to do this mapping outside an MBean.  For example, we recommend       that the custom payload       ("userData")       of       a Notification       should use open types, but open values can be a bit painful to       construct.  It would be nice to use the MXBean framework to map       from a custom payload type to an open type.  Is there a way to       do that?

 

Let's take an example.  Suppose you are tracking coordinates read     from some device, and you have a notification that indicates that     an (x,y) value has been read that was outside the expected bounds.     You'd like the notification to include the value that was     read.

 

In the JMX 2.0 API, you can do this easily, using interfaces I     described before:

 
    public class Coordinate {
        @ConstructorProperties({"x", "y"})
        public Coordinate(int x, int y) {...}
        public int getX() {...}
        public int getY() {...}
    }

    MXBeanMapping coordinateMapping =
        MXBeanMappingFactory.DEFAULT.mappingForType(Coordinate.class, MXBeanMappingFactory.DEFAULT);

    Coordinate outOfBounds = ...;
    Notification notif = new Notification(Coordinate.class.getName(), source, seqNo++);
    notif.setUserData(coordinateMapping.toOpenValue(outOfBounds));
  
 

Though you don't have to, you can also make the corresponding     OpenType available to clients, by putting it in     the Descriptor     of the     corresponding MBeanNotificationInfo.     The Descriptor     field openType     is defined with this meaning, so the code would look like this:

 
    OpenType<?> coordinateOpenType = coordinateMapping.getOpenType();
    Descriptor notifDescr = new ImmutableDescriptor(
            new String[] {
                "openType",
            }, new Object[] {
                coordinateOpenType
            });
    MBeanNotificationInfo mbni = new MBeanNotificationInfo(
        new String[] {"com.example.bounds.exceeded"},
        Notification.class.getName(),
        "Read a coordinate value outside the expected bounds",
        notifDescr);
  
 

That's all very well, but the JMX 2.0 API will only be available     in the JDK 7 platform.  What if you want to do this today?

 

The good news is that it is possible, although it requires     writing some throwaway classes (or generating them at runtime, as I     discussed     previously).     I'll show some general-purpose     code later, but for now here's a simple     way you could do it.  Create an MXBean with an attribute X of type     Coordinate, register it in an MBeanServer (perhaps one created     specially for the purpose), then arrange for the original value of     X to be the Coordinate you want to convert.  Calling     getAttribute(objectName, "X") should then give you     the converted value, and you can get the OpenType by looking at     getMBeanInfo(objectName).getAttributes()[0].

 

But actually, that's overkill.  You don't need to register an MXBean at all.  You can simply use the StandardMBean class to create a private MXBean, and do the same trick.  For example, you could write this:

 
    public interface CoordinateWrapperMXBean {
        public Coordinate getX();
    }
    public class CoordinateWrapper implements CoordinateWrapperMXBean {
        public Coordinate x;
        public Coordinate getX() {
            return x;
        }
    }
    CoordinateWrapper coordinateWrapper = new CoordinateWrapper();
    StandardMBean coordinateMBean = new StandardMBean(
        coordinateWrapper, CoordinateWrapperMXBean.class, true);

    Coordinate outOfBounds = ...;
    coordinateWrapper.x = outOfBounds;
    Object userData = coordinateMBean.getAttribute("X");
  
 

That's kind of unwieldy, and it's not thread-safe as written, but     you can see the general idea.

 

A general-purpose MXBean conversion class

 

To reduce the unwieldiness, we can generalize this for any type,     in such a way that you only need to write this...

 
    public interface CoordinateCaller extends Callable<Coordinate> {
        public Coordinate call();
    }
  
 

...and you can feed it to a simple conversion framework that I'll     show below, like this:

 
    MXBeanConverter coordinateConverter =
        MXBeanConverter.getInstance(CoordinateCaller.class);
    Coordinate outOfBounds = ...;
    Object userData = coordinateConverter.toOpenValue(outOfBounds);
  
 

You can also get the OpenType like this:

 
    OpenType<?> coordinateOpenType = coordinateConverter.getOpenType();
  
 

And you can convert in the opposite direction (for example, when     you receive the Notification and you want to reconstruct the     original Coordinate object) like this:

 
    Coordinate outOfBounds =
        coordinateConverter.fromOpenValue(notification.getUserData());
  
 

If you only have a handful of types that you need to convert,     having to create a FooCaller interface for each one shouldn't be     too big a burden.  If you have a huge number of types, then it     would be worth looking at generating each FooCaller interface at     runtime, for example     using ASM.  (Actually, I'd     recommend generating an interface with getX and setX methods     instead.)

 

By the way, if you look closely at the CoordinateCaller     interface...

 
    public interface CoordinateCaller extends Callable<Coordinate> {
        public Coordinate call();
    }
  
 

...you might reasonably wonder why you need to define     the call() method when     a Callable<Coordinate> already has one.  Ideally     you would not have to, but this is a shortcoming of the current     MXBean framework.

 

The approach used here is a variant on     the getAttribute("X") approach I explained above.     Since we're using a call() method and not     a getX() method, we need to use invoke     and not getAttribute on the StandardMBean.

 

To do the reverse conversion, we make     an MXBean     proxy for the CoordinateCaller, and arrange for its call     to MBeanServerConnection.invoke     to return the open-type value, so that the proxy will convert it     back into a Coordinate that it returns from     its call() method.  (Don't worry if you didn't     understand that; you don't need to in order to use the     converter.)

 

OK, so here's the code:

package mxbeanconverter;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.Callable;
import javax.management.JMX;
import javax.management.MBeanServer;
import javax.management.MBeanServerDelegate;
import javax.management.StandardMBean;
import javax.management.openmbean.OpenType;

public class MXBeanConverter<T> {
    private final StandardMBean mbean;
    private final Callable<T> proxy;
    private final ThreadLocal<Object> threadLocal = new ThreadLocal<Object>();

    public OpenType getOpenType() {
        return (OpenType) mbean.getMBeanInfo().getOperations()[0]
                .getDescriptor().getFieldValue("openType");
    }

    public Object toOpenValue(T javaValue) {
        threadLocal.set(javaValue);
        try {
            return mbean.invoke("call", null, null);
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
            // Should not happen
        }
    }

    public T fromOpenValue(Object openValue) {
        threadLocal.set(openValue);
        try {
            return proxy.call();
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
            // Should not happen
        }
    }

    private MXBeanConverter(Class<? extends Callable<T>> intf) {
        mbean = makeMBean(intf);
        proxy = makeProxy(intf);
    }

    public static <T> MXBeanConverter<T> getInstance(Class<? extends Callable<T>> intf) {
        return new MXBeanConverter(intf);
    }

    private <I extends Callable<T>> StandardMBean makeMBean(Class<I> intf) {
        I impl = intf.cast(Proxy.newProxyInstance(
                intf.getClassLoader(), new Class<?>[] {intf}, threadLocalIH));
        return new StandardMBean(impl, intf, true);
    }

    private <I extends Callable<T>> I makeProxy(Class<I> intf) {
        MBeanServer threadLocalMBS = (MBeanServer) Proxy.newProxyInstance(
                MBeanServer.class.getClassLoader(),
                new Class<?>[] {MBeanServer.class},
                threadLocalIH);
        return intf.cast(JMX.newMXBeanProxy(
                threadLocalMBS, MBeanServerDelegate.DELEGATE_NAME, intf));
    }

    // An InvocationHandler that returns threadLocal.get() from every method.
    // This means that we can make an implementation of FooCallable where
    // the call() method returns threadLocal.get(), and it also means that
    // we can make an implementation of MBeanServer where
    // invoke(...any parameters...) returns threadLocal.get().
    private class GetThreadLocalIH implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) {
            return threadLocal.get();
        }
    }
    private final InvocationHandler threadLocalIH = new GetThreadLocalIH();
}

[Tags: jmx mxbean ]

You can't construct a JMX ObjectName without handling     MalformedObjectNameException, which is a checked exception.  Here's     why that is a pain, how to relieve that pain, and what we're doing     to make it less painful in the next version.

 

If you've done any programming at all with the JMX API, you'll     have noticed that all of     the ObjectName     constructors, and all of     the getInstance     methods, are declared as     throwing MalformedObjectNameException.

 

MalformedObjectNameException is a checked exception, which means     that you have to either declare it in the throws     clause of your method, or catch it within the method.  Having this     exception be a checked one was a mistake, in the light of modern     practice.  For example, Effective Java 2 says: Use checked     exceptions for recoverable conditions and runtime exceptions for     programming errors. Clearly a malformed ObjectName is a     programming error.

 

When the ancestor of the JMX API was being designed about ten     years ago this was all much less clear, and there were plenty of     misleading precedents     like MalformedURLException.     If the API were being designed over again,     MalformedObjectNameException would surely be a subclass of     IllegalArgumentException, or perhaps the constructors would just     throw IllegalArgumentException itself.

 

As it stands, this is painful, especially when you want to     initialize a static final field to be an ObjectName.  For example,     you might want to write something like this:

 
    public interface EventClientDelegateMBean {
        public static final ObjectName OBJECT_NAME =
            new ObjectName("javax.management.event:type=EventClientDelegate");
        ...
    }
  
 

Alas, that doesn't compile, because field initializers can't     throw checked exceptions.  You might try to write this:

 
    public interface EventClientDelegateMBean {
        public static final ObjectName OBJECT_NAME;
        static {
            try {
                OBJECT_NAME =
                    new ObjectName("javax.management.event:type=EventClientDelegate");
            } catch (MalformedObjectNameException e) {
                throw new IllegalArgumentException(e);
            }
        }
        ...
    }
  
 

But that doesn't compile either, because interfaces can't have     static initializers.  Don't ask me why not.

 

So the solution today is to write a simple     static newObjectName method that wraps the     MalformedObjectNameException as an IllegalArgumentException, park     it in some class, say Util, and call that every time     you need to construct an ObjectName:

 
    public class Util {
        ...
        public static ObjectName newObjectName(String s) {
            try {
                return ObjectName.getInstance(s);
            } catch (MalformedObjectNameException e) {
                throw new IllegalArgumentException(e);
            }
        }
        ...
    }
  
 

Thus our troublesome interface becomes:

 
    public interface EventClientDelegateMBean {
        public static final ObjectName OBJECT_NAME =
            Util.newObjectName("javax.management.event:type=EventClientDelegate");
        ...
    }
  
 

That does compile, and it does work.  (Although if the string     really is incorrect you will get bashed with     an ExceptionInInitializerError     when you first reference the interface.)

 

My favourite tiny change in the JMX 2.0 API is that we do now     provide standard methods to do this, so you no longer need to define     them.  The hardest part was to decide what to call them!  As of     JDK 7, you can write:

 
    public interface EventClientDelegateMBean {
        public static final ObjectName OBJECT_NAME =
            ObjectName.valueOf("javax.management.event:type=EventClientDelegate");
        ...
    }
  
 

[Tags: jmx     java.]

Version 2.0 of the JMX API is being defined       by JSR 255.       I've written about some of the features in the new API before.       They are trickling into the JDK 7 sources over time, so you can       now play with some shiny new things.  Here's a description of what       they are, and how you can even access them from JDK 6 if you are       brave.

As you probably know, the JDK 7 platform is being developed in       open source, which means that you can see the changes as soon as       the JMX team commits them.

You can browse the current mainline JDK 7 sources directly from       the Mercurial repository,       at http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/tip.

These sources correspond to the Javadoc snapshot       at http://download.java.net/jdk7/docs/api/index.html,       and to the JDK 7 snapshot binary       at http://download.java.net/jdk7/binaries/.

If you download the JDK 7 snapshot binary, you can use it the       same way you would use any other JDK installation.  Of course,       this is work in progress, so don't use it for anything       critical.  But it tends to be surprisingly stable, and I       often use it to run NetBeans, for example.

Recent JMX API changes in the JDK 7 sources

You can also see all of the changes that have gone into the JDK       7 sources       at http://hg.openjdk.java.net/jdk7/jdk7/jdk/shortlog.       At the time of writing, one interesting thing you will see there       (if you find the JMX API interesting) is this:

                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
4 weeks agoemcmanus6323980: Annotations to simplify MBean developmentchangeset | manifest
           

I wrote about this        feature in        detail before, and here it finally is.  Have a look at        the Javadoc for the        new @MBean        annotation for example, or        for MBeanRegistration,        where resource injection is described.

           
           

You can also see:

           
2 months agoemcmanus6562936: Support custom type mappings in MXBeanschangeset | manifest
           

I wrote        about that          one before as well.

           
           

And much further back, you can see:

           
5 months agoemcmanus6602310: Extensions to Query API for JMX 2.0changeset | manifest
           

You probably won't be surprised to learn          that I wrote          about that          before too.

           
           

There's a small related change...

           
4 months agoemcmanus6610917: Define a generic NotificationFilterchangeset | manifest
           

...which I only wrote          about in          passing before, but you can read all about it in the          specification for the          new QueryNotificationFilter          class.

           

Changes that are on the way

For a project as big and important as the JDK 7 project,       there's a lot of extra engineering that has to happen between       the time the JMX team pushes a change into a publicly-visible       repository and the time that change actually shows up in the       snapshots.  I think of the changes as being "in the pipes"       during this time.  You can see our changes as soon as we push       them by looking       at http://hg.openjdk.java.net/jdk7/tl/jdk.       (Here, tl stands for "tools and libraries", which       is the subproject where the JMX API lives.)

At the time of writing, this will show the change
5108776:       Add reliable event handling to the JMX API
which is the       new Event Service.  You might have already seen this in       the Early       Draft Review of the JMX 2.0 API, but if not it will       eventually appear in the Javadoc snapshots in the       package javax.management.event, or if you can't       wait you could always read       the source       of the javadoc for that package.

There are two other chunks of functionality that should be       showing up in the next couple of months, one big and one       somewhat smaller.  The big one       is namespaces.       The smaller one is the stuff that will build on namespaces to       support "client contexts" (also described in the slides at that       link) and localization of descriptions in MBeanInfo.

Once those are in we will be looking at a smallish subset of       the       various RFEs       open against the JMX API.  Now would be a good time to       agitate for anything you particularly want to see.

Using the JMX 2.0 API with the JDK 6 platform

Using the JDK 7 sources, you can in fact build a jar with just       the JMX classes and run that with a JDK 6 installation.  Of       course this is even less supported than running a JDK 7       snapshot, but once again assuming you're not using it for       anything critical here's how you would go about it.

First download the JDK 7 sources, either using Mercurial if you       have it, with a command like this...

hg clone http://hg.openjdk.java.net/jdk7/jdk7/jdk myjdk

...or by downloading the sources       from http://download.java.net/jdk7/.       The "JDK 7 Source under the JRL license" link on that page is a       jar which you download and run using a command like this...

java -jar jdk-7-ea-src-b32-jrl-04_aug_2008.jar

Now cd to the jdk subdirectory of the sources, if you       downloaded the bundle, or into the Mercurial repository you cloned       if you did that (you only cloned the jdk subdirectory).  Run this       command...

ant -f make/netbeans/jmx/build.xml

If it works, it'll make you a jmx.jar       in dist/lib and that's what you can use with your       JDK 6 installation.  (If it doesn't work, tell me what went       wrong and I'll update the instructions here.)

Now you can use your new jmx.jar in either of two       ways.  The simplest is to make a directory       called endorsed inside the jre/lib       subdirectory of your JDK installation (if there isn't one       already), and then drop jmx.jar into it.  (I would       recommend renaming it too, to something like       jmx-2.0-snapshot-2008-08-06.jar.)  But       beware that if you do this you are replacing the JMX       implementation for all users of that JDK installation!

The second way is to run your programs like this...

java -Xbootclasspath/p:/path/to/jmx.jar ...

Then only programs that are explicitly run in that way will be       using the new JMX implementation.

Let us know how you get on

If you play with the new JMX API, or even if you are just       browsing through it, we're very interested in hearing about your       experiences.  Feel free to add your comments here, or send mail       to jmx-spec-comments@sun.com,       or write a blog entry       with tag       "jmx".  Thanks!

[Tags: jmx       jdk7.]

Filter Blog

By date: