<?xml version="1.0" encoding="utf-8"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en">
<title>Eamonn McManus&apos;s Blog</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/" />
<modified>2008-05-02T17:07:50Z</modified>
<tagline></tagline>
<id>tag:weblogs.java.net,2008:/blog/emcmanus/254</id>
<generator url="http://www.movabletype.org/" version="3.01D">Movable Type</generator>
<copyright>Copyright (c) 2008, emcmanus</copyright>
<entry>
<title>JavaOne next week!</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/archive/2008/05/javaone_next_we_1.html" />
<modified>2008-05-02T17:07:50Z</modified>
<issued>2008-05-02T17:07:50Z</issued>
<id>tag:weblogs.java.net,2008:/blog/emcmanus/254.9665</id>
<created>2008-05-02T17:07:50Z</created>
<summary type="text/plain">Next week is JavaOne 2008!  I&apos;ll be speaking there with
      Jean-Francois Denise, about upcoming developments in JMX
      technology.  Here are some of the other sessions you might want
      to attend if you&apos;re interested in that...</summary>
<author>
<name>emcmanus</name>

<email>eamonn.mcmanus@sun.com</email>
</author>
<dc:subject>JavaOne</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/emcmanus/">
<![CDATA[    <script src=
      "http://weblogs.java.net/blog/emcmanus/archive/j1button.js" type=
      "text/javascript">
    </script>

    <p>Next week is JavaOne 2008!  I'll be speaking there with
      Jean-Fran&ccedil;ois Denise, about upcoming developments in JMX
      technology.  Here are some of the other sessions you might want
      to attend if you're interested in that.</p>

    <ul>
      <li><p><a
      href="http://www28.cplan.com/sb191/session_details.jsp?isid=295552&ilocation_id=191-1">BOF-5552</a>,
	  "<b>Java Observability by Bytecode Instrumentation</b>",
	  K&nbsp;Balasubramainan and A&nbsp;Sunararajan,
	  Tuesday&nbsp;7:30pm, Esplanade 300.</p>

	<p>How to attach to an already-running JVM and insert
	  instrumentation code into it.  Not necessarily directly
	  related to the JMX world but of interest nevertheless.</p>

      <li><p><a
      href="http://www28.cplan.com/sb191/session_details.jsp?isid=295199&ilocation_id=191-1">TS-5199</a>,
	"<b>JMX Technology Update</b>", E&nbsp;McManus and J-F&nbsp;Denise,
	Wednesday&nbsp;4:10pm, Esplanade 304/306.</p>

	<p>That's us!  I'll be talking about some of the changes to
	  the JMX API being planned in <a
	    href="http://jcp.org/en/jsr/detail?id=255">JSR 255</a>, and
	  Jean-Fran&ccedil;ois will be talking about the Web Services
	  Connector being designed in <a
	    href="http://jcp.org/en/jsr/detail?id=262">JSR
	    262</a>.</p>

	<li><p><a
	    href="http://www28.cplan.com/sb191/session_details.jsp?isid=295698&ilocation_id=191-1">BOF-5698</a>,
	    "<b>Practical JMX Security Options</b>", J&nbsp;Gould and
	    D&nbsp;Smith, Wednesday&nbsp;6:30pm, Hall E 134.</p>

	<p>Although we've put a lot of effort into make JMX technology
	  secure, it's always possible to get your configuration wrong
	  and leave yourself inadvertently open.  It looks as if this
	  BOF will show some good ways to avoid that.</p>

	<li><p><a
	    href="http://www28.cplan.com/sb191/session_details.jsp?isid=296947&ilocation_id=191-1">LAB-1430LT</a>,
	  "<b>Java Hotspot VM Trouble Shooting Tools in a
	  Nutshell</b>", M&nbsp;Li and J&nbsp;Shen,
	  Thursday&nbsp;12:30pm--2:30pm, Hall E 132.</p>
	
	<p>This hands-on lab is full but you might be able to sneak
	  in.  It promises to show you how to use JConsole, jps, jmap,
	  jhat, and hprof.</p>

	<li><p><a
	    href="http://www28.cplan.com/sb191/session_details.jsp?isid=296145&ilocation_id=191-1">TS-6145</a>,
	  "<b>Using DTrace with Java Applications: Bridging the
	  Observability Gap</b>", J&nbsp;Haslam and S&nbsp;Ritter,
	  Thursday&nbsp;1:30pm and Friday&nbsp;2:50pm, North Mtg
	  121.</p>

	<p>DTrace is an excellent piece of technology that allows you
	  to add probes to an application and summarize the data they
	  provide, by writing scripts in a special language.  The
	  application itself doesn't need to be modified to add the
	  probes.  DTrace is available on Solaris 10 and on Mac OS X
	  Leopard, at least.</p>

	<li><p><a
	    href="http://www28.cplan.com/sb191/session_details.jsp?isid=294945&ilocation_id=191-1">BOF-4945</a>,
	  "<b>Designing Manageable Java EE Applications in a Clustered
	  Environment</b>", J&nbsp;Jensen and P&nbsp;Kristiansson,
	  Thursday&nbsp;7:30pm, Hall E 134.</p>

	<p>This looks to be a very interesting BOF for JMX weenies.
	  The presenters are from a telecoms background but their
	  abstract promises broad applicability.</p>

	<li><p><a
	    href="http://www28.cplan.com/sb191/session_details.jsp?isid=295223&ilocation_id=191-1">BOF-5223</a>,
	  "<b>VisualVM: Integrated and Extensible Troubleshooting Tool
	  for the Java Platform</b>", L-M&nbsp;Alventosa and
	  Tomas&nbsp;Hurka, Thursday&nbsp;7:30pm, Gateway 104.</p>

	<p>If you haven't seen the excellent <a
	    href="https://visualvm.dev.java.net/">VisualVM</a> tool, this
	  is the occasion to discover it.  A simplistic way to
	  describe it is that it is like JConsole but with added
	  support for CPU profiling and heap walking, and the ability
	  to download plugins from a plugin centre.  Unfortunately
	  this BOF clashes with the previous one.</p>

	<li><p><a
	    href="https://www28.cplan.com/cc191/session_details.jsp?isid=296028&ilocation_id=191-1">TS-6028</a>,
	  "<b>Near-Real-Time Distributed Enterprise Infrastructure for
	  Traffic Data Collection...</b>", J&nbsp;Carroll and
	  B&nbsp;Smyth, Friday&nbsp;2:50pm, Hall E 134.</p>

	<p>The JMX API is just one of a bunch of APIs mentioned in the
	  abstract so I don't expect it to be the focus of the talk,
	  but the subject looks pretty interesting anyway.</p>
    </ul>

    <p>In addition to all that, Sun's Pod 136 in the Pavilion area
      will be staffed by JMX experts a lot of the time.  Catch me
      there on Wednesday and Thursday from 11:15am to 2pm.
      Jean-Fran&ccedil;ois is likely to be around then too, if you
      have Web Services Connector questions.  And Luis-Miguel
      Alventosa will be there in the same time-slot on Tuesday and
      Wednesday if you have questions or comments about JConsole or
      VisualVM.</p>

    <p>See you there!</p>

    <p>[Tags: <a href="http://java.sun.com/javaone"
    rel="tag">javaone</a> <a
    href="http://technorati.com/tag/javaone2008"
    rel="tag">javaone2008</a> <a href="http://java.sun.com/jmx"
    rel="tag">jmx</a>]]]>

</content>
</entry>
<entry>
<title>A query language for the JMX API</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/archive/2008/04/a_query_languag.html" />
<modified>2008-04-25T16:23:31Z</modified>
<issued>2008-04-25T16:21:42Z</issued>
<id>tag:weblogs.java.net,2008:/blog/emcmanus/254.9607</id>
<created>2008-04-25T16:21:42Z</created>
<summary type="text/plain">The JMX API is being updated by JSR 255. That JSR is currently
      planned to be part of Java SE 7, and some of the API changes it
      defines have started to appear in JDK 7. So far, the main one is a
      Query Language. Here&apos;s what that is and what it&apos;s for. ...</summary>
<author>
<name>emcmanus</name>

<email>eamonn.mcmanus@sun.com</email>
</author>
<dc:subject>Community: JDK</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/emcmanus/">
<![CDATA[    <script src=
      "http://weblogs.java.net/blog/emcmanus/archive/j1button.js" type=
      "text/javascript">
    </script>

    <p>The JMX API is being updated by <a href=
	"http://jcp.org/en/jsr/detail?id=255">JSR 255</a>. That JSR is
      currently planned to be part of Java SE 7, and some of the API
      changes it defines have started to appear in <a href=
	"http://openjdk.java.net/projects/jdk7/">JDK 7</a>. So far, the
      main one is a Query Language. Here's what that is and what it's
      for.</p>

    <p>The JMX API has always included the idea of <em>queries</em>.
      The idea is that you can tell the <a href=
	"http://download.java.net/jdk7/docs/api/javax/management/MBeanServerConnection.html#queryNames(javax.management.ObjectName,%20javax.management.QueryExp)">
	<code>queryNames</code></a> method to filter the set of objects
      that it returns, using an object that implements the <a href=
	"http://download.java.net/jdk7/docs/api/javax/management/QueryExp.html">
	<code>QueryExp</code></a> interface. For example, you can pick out
      only those MBeans that have an attribute called
      <code>Enabled</code> with the value <code>true</code> and an
      attribute called <code>Owner</code> with the value
      <code>"Duke"</code>.</p>

    <p>The recommended way to obtain <code>QueryExp</code> objects is
      using the static methods of the <a href=
	"http://download.java.net/jdk7/docs/api/javax/management/Query.html">
	<code>Query</code></a> class. That way, your <code>QueryExp</code>
      consists only of standard classes that must be present on all JMX
      implementations and there are no worries about classes that are
      present on the client but not the server.</p>

    <p>Up until now, the way to code the query I described above was
      this:</p>

    <pre>
 QueryExp query =
     Query.and(Query.eq(Query.attr("Enabled"), Query.value(true)),
               Query.eq(Query.attr("Owner"), Query.value("Duke")));
    </pre>

    <p>While it's possible to decipher that and determine that it does
      indeed mean what I described, it isn't very easy. The idea of the
      query language is that you can get the <em>same</em>
      <code>QueryExp</code> object like this:</p>

    <pre>
 QueryExp query = Query.fromString("Enabled = true and Owner = 'Duke'");
    </pre>

    <p>Much easier to understand! (Let me stress that this is just an
      alternative way of writing existing queries. It doesn't introduce
      any new types of query.)</p>

    <p>The query language is closely based on the <code>WHERE</code>
      clause of SQL <code>SELECT</code> queries. Here are the other
      examples from the specification:</p>

    <dl>

      <dt><code>Message = 'OK'</code></dt>
      <dd>Selects MBeans that have a <code>Message</code> attribute whose
	value is the string <code>OK</code>.</dd>

      <dt><code>FreeSpacePercent &lt; 10</code></dt>
      <dd>Selects MBeans that have a <code>FreeSpacePercent</code>
	attribute whose value is a number less than 10.</dd>

      <dt><code>FreeSpacePercent &lt; 10 and WarningSent =
	  false</code></dt>
      <dd>Selects the same MBeans as the previous example, but they must
	also have a boolean attribute <code>WarningSent</code> whose value
	is false.</dd>

      <dt><code>SpaceUsed &gt; TotalSpace * (2.0 / 3.0)</code></dt>
      <dd>Selects MBeans that have <code>SpaceUsed</code> and
	<code>TotalSpace</code> attributes where the first is more than
	two-thirds the second.</dd>

      <dt><code>not (FreeSpacePercent between 10 and 90)</code></dt>
      <dd>Selects MBeans that have a <code>FreeSpacePercent</code>
	attribute whose value is not between 10 and 90, inclusive.</dd>

      <dt><code>FreeSpacePercent not between 10 and 90</code></dt>
      <dd>Another way of writing the previous query.</dd>

      <dt><code>Status in ('STOPPED', 'STARTING', 'STARTED')</code></dt>
      <dd>Selects MBeans that have a <code>Status</code> attribute whose
	value is one of those three strings.</dd>

      <dt><code>Message like 'OK: %'</code></dt>
      <dd>Selects MBeans that have a <code>Message</code> attribute whose
	value is a string beginning with <code>"OK: "</code>. <b>Notice
	  that the wildcard characters are SQL's ones.</b> In the query
	language, <code>%</code> means "any sequence of characters" and
	<code>_</code> means "any single character". In the rest of the JMX
	API, these correspond to <code>*</code> and <code>%</code>
	respectively.</dd>

      <dt><code>instanceof
	  'javax.management.NotificationBroadcaster'</code></dt>
      <dd>Selects MBeans that are instances of <a href=
	  "http://download.java.net/jdk7/docs/api/javax/management/NotificationBroadcaster.html">
	  <code>javax.management.NotificationBroadcaster</code></a>, as
	reported by <a href=
	  "http://download.java.net/jdk7/docs/api/javax/management/MBeanServer.html#isInstanceOf(javax.management.ObjectName,%20java.lang.String)">
	  <code>MBeanServer.isInstanceOf</code></a>.</dd>

      <dt><code>like 'mydomain:*'</code></dt>
      <dd>Selects MBeans whose <a href=
	  "http://download.java.net/jdk7/docs/api/javax/management/ObjectName.html">
	  <code>ObjectName</code></a>s have the domain
	<code>mydomain</code>.</dd>
    </dl>

    <p>If you're familiar with SQL, all of these should be familiar,
      except the last two, which have no SQL equivalent.</p>

    <p>The full specification also <a href=
	"http://download.java.net/jdk7/docs/api/javax/management/Query.html#formal-ql">
	includes</a> a formal grammar, which I won't reproduce here. I'll
      just say that I got to liberate my repressed inner compiler geek
      when writing the <a href=
	"http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/tip/src/share/classes/javax/management/QueryParser.java">
	parser</a>.</p>

    <h3>Other uses for the Query Language</h3>

    <p>Apart from making it easier to write code that does queries, a
      standard query language is very practical for tools like <a href=
	"http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html">
	JConsole</a> or <a href=
	"https://visualvm.dev.java.net/">VisualVM</a> that might want to
      allow the user to select a subset of MBeans using a query. A simple
      text field can now be used to do this.</p>

    <p>The query language also provides one solution to a problem with
      the existing Query API.  The methods of the <code>Query</code>
      class allow you to construct objects that implement
      <code>QueryExp</code>.  But if you have such an object, there is
      no easy way to look inside to see what kind of query it is.  As
      well as <code>Query.fromString</code>, the new API includes <a
      href=
	"http://download.java.net/jdk7/docs/api/javax/management/Query.html#toString(javax.management.QueryExp)">
	<code>Query.toString</code></a> to do the reverse
      transformation.  With these two methods you can for example save
      a query in a text file, or send it over a text-based protocol
      like SOAP, and reconstruct it later.</p>

    <p>(You might be wondering why we bothered defining
      <code>Query.toString</code>.  Couldn't we just have said that the
      standard <a
	href="http://download.java.net/jdk7/docs/api/java/lang/Object.html#toString()"><code>toString()</code></a>
      method would do the right thing?  The main reason it can't is that
      <a
	href="http://download.java.net/jdk7/docs/api/javax/management/ObjectName.html"><code>ObjectName</code></a>
      is a <code>QueryExp</code>, but the syntax to include an
      <code>ObjectName</code> in a query is for example "<code>like
	'*:type=Foo,*'</code>", while <code>ObjectName.toString()</code>
      will be just "<code>*:type=Foo,*</code>".)</p>

    <h3>Custom queries</h3>

    <p>Nothing prevents you from writing your own class that
      implements <code>QueryExp</code> and giving it to <a
	href="http://download.java.net/jdk7/docs/api/javax/management/MBeanServer.html#queryNames(javax.management.ObjectName,%20javax.management.QueryExp)"><code>queryNames</code></a>.
      Although custom queries are powerful, they're also discouraged.
      Most queries that you want can be composed out of the standard
      set.  The problem with custom implementations is that, if you
      want to do your query remotely, you need to arrange for the
      implementation class to be present on both client and
      server.</p>

    <p>This is why <code>Query.toString</code> and
      <code>Query.fromString</code> don't specify any handling for
      non-standard queries.  Although various possibilities could be
      imagined for what that might look like, people could be seduced
      into using custom queries without realizing the deployment
      headaches that that can lead to down the road.</p>


    <h3>Why SQL?</h3>

    <p>You might be wondering why the query language is based on SQL,
      which is a database query language.  Is that really appropriate to
      query management objects?</p>

    <p>Although it's far from obvious, the original JMX query API was
      closely based on SQL too.  In fact, the places where the query
      language described here differs from SQL are essentially the
      places where the JMX query API has changed since its original
      version.  One strong historical hint here is that the Reference
      Implementation has always used SQL syntax in the
      <code>toString()</code> methods of the various
      <code>QueryExp</code> classes, even going as far as to replace
      <code>*</code> and <code>?</code> with their SQL equivalents
      <code>%</code> and <code>_</code>.</p>

    <p>Quite apart from this, SQL is familiar to very many
      programmers, and is also the inspiration for the query languages
      used by the Java Persistence API (JPA) and the Java Message
      Service (JMS).</p>


    <h3>Evolution of the standard queries</h3>

    <p>The set of available standard queries has expanded slightly
      over time.  The original set was defined in version 1.0 of the JMX
      API, way back in 2000.</p>
    
    <p>In version 1.2 of the API, we made <a
	href="http://download.java.net/jdk7/docs/api/javax/management/ObjectName.html"><code>ObjectName</code></a>
      implement <code>QueryExp</code>, which gave users a way to match
      <code>ObjectName</code> patterns themselves, and also meant that
      you could use <code>queryNames</code> to find MBeans that match
      a pattern <code>AND</code> another pattern, and various other
      Boolean combinations.  This is the last available standalone
      version, and the version that was included with Java SE 5.0.</p>

    <p>In Java SE 6 we added <a
	href="http://download.java.net/jdk7/docs/api/javax/management/Query.html#isInstanceOf(javax.management.StringValueExp)"><code>Query.isInstanceOf</code></a>.</p>

    <p>In Java SE 7 (assuming plausibly that that includes JSR 255,
      the new JMX API), in addition to the query language, we're
      including the ability to use dotted attribute expression like
      <code>A.b.c</code>, with the same meaning as for <a
      href="http://java.sun.com/javase/6/docs/api/javax/management/monitor/package-summary.html#package_description">monitors</a>.
      So for example you could find out which <a
      href="http://java.sun.com/javase/6/docs/api/java/lang/management/MemoryPoolMXBean.html">memory
      pools</a> still have <code>init</code> the same as
      <code>committed</code> in their <a
      href="http://java.sun.com/javase/6/docs/api/java/lang/management/MemoryUsage.html">MemoryUsage</a>
      using code like this:</p>

    <pre>
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName poolPattern = new ObjectName("java.lang:type=MemoryPool,*");
QueryExp q = Query.fromString("<b style="color: red">Usage.init = Usage.committed</b>");
// or: Query.eq(Query.attr("Usage.init"), Query.attr("Usage.committed"));
Set&lt;ObjectName&gt; names = mbs.queryNames(poolPattern, q);
</pre>

    <p>If you're sending either <code>isInstanceOf</code> or dotted
      attribute expressions over a network connection, you need to
      have some way of knowing that the other end supports those.
      Otherwise, you have to avoid using either of these.</p>

    <p>(We could add a method, say <code>Query.isSupported(QueryExp,
	MBeanServerConnection)</code> that tells you whether the given
      MBean Server supports the given query, by examining its <a
	href="http://download.java.net/jdk7/docs/api/javax/management/MBeanServerDelegateMBean.html#getSpecificationVersion()">specification
	version</a>.  But most of the time, either you wouldn't know what
      to do if it returned false; or you would know what to do, and
      you could just do that always.)</p>


    <h3>A pattern matching problem</h3>

    <p>One area where I'm not sure the query language does the right
      thing is with patterns.  In the existing API, if you want to query
      for all MBeans that have a <code>State</code> attribute that is a
      string in parentheses, you would use<br><code><a
	  href="http://download.java.net/jdk7/docs/api/javax/management/Query.html#match(javax.management.AttributeValueExp,%20javax.management.StringValueExp)">Query.match</a>(Query.attr("State"),
	Query.value("<b style="color: red">(*)</b>"))</code>.<br>In
      the Query Language, you can instead write<br>
      <code>Query.fromString("State&nbsp;like&nbsp;'<b style="color:
      red">(%)</b>'")</code>.<br> As before, that's much easier to
      read, but what's the story with <code>*</code> versus
      <code>%</code>?</p>

    <p><code>Query.match</code> uses the well-known "shell-style"
      wildcards, where <code>?</code> matches any single character and
      <code>*</code> matches zero or more characters.  On the other
      hand, the <code>LIKE</code> operator in the <a
      href="http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt">SQL
      standard</a> uses the characters <code>_</code> and
      <code>%</code> for the same thing.  Both the <a
      href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnbuf.html#bnbvg">Java
      Persistence Query Language</a> from Java EE and JMS <a
      href="http://java.sun.com/javaee/5/docs/api/javax/jms/Message.html">Message</a>
      Selectors have a <code>LIKE</code> operator that uses the SQL
      characters.  So people familiar with these will expect the
      <code>LIKE</code> operator in the JMX query API to work the same
      way.  On the other hand, people who are familiar with
      <code>Query.match</code> or shell wildcards or
      <code>ObjectName</code> wildcards will expect the other
      convention.  It's particularly messy when you compare a query
      that matches <code>ObjectNames</code>, corresponding to <a
      href="http://download.java.net/jdk7/docs/api/javax/management/ObjectName.html#apply(javax.management.ObjectName)">ObjectName.apply</a>,
      with one that matches strings:</p>

    <pre>
QueryExp objectNameQuery = new ObjectName("mydomain:*");
System.out.println(Query.toString(objectNameQuery));
// prints: LIKE 'mydomain:*'
// this is not a standard SQL query so we don't have to respect precedent

QueryExp objectNameStringQuery =
    Query.match(Query.attr("Name.canonicalName"), Query.value("mydomain:*"));
System.out.println(Query.toString(objectNameStringQuery));
// prints: Name.canonicalName like 'mydomain:%'
</pre>

    <p>Never mind the inconsistent case of <code>LIKE</code> (which I
      just noticed).  Can we really live with <code>*</code> in some
      places and <code>%</code> in others?</p>


    <h3>This is just the beginning</h3>

    <p>You can expect <a
	href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5072268">other
	new features</a> from 2.0 to show up in the <a
	href="https://jdk7.dev.java.net/">JDK 7 snapshots</a> in the
      coming months.  Namespaces, Event Service, localization
      support, you name it!</p>

<p>[Tags: <a href="http://java.sun.com/jmx" rel="tag">jmx</a> <a href="http://technorati.com/tag/sql" rel="tag">sql</a> <a href="http://technorati.com/tag/jdk" rel=tag">jdk</a>.]</p>]]>

</content>
</entry>
<entry>
<title>Do I really need all those jars in my classpath?</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/archive/2008/02/do_i_really_nee.html" />
<modified>2008-02-21T17:56:48Z</modified>
<issued>2008-02-21T17:56:40Z</issued>
<id>tag:weblogs.java.net,2008:/blog/emcmanus/254.9244</id>
<created>2008-02-21T17:56:40Z</created>
<summary type="text/plain">Big applications have a tendency to accumulate enormous
      classpaths.  Looking at such a classpath, you might be hard put to
      know whether any given jar is really needed.  Perhaps it was
      needed at the time it was added, but that need has long since
      evaporated.  How can you tell?  Kyrill Alyoshin has an elegant
      solution...</summary>
<author>
<name>emcmanus</name>

<email>eamonn.mcmanus@sun.com</email>
</author>
<dc:subject>Programming</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/emcmanus/">
<![CDATA[    <script src="http://weblogs.java.net/blog/emcmanus/archive/j1button.js" type="text/javascript"></script>

    <p>Big applications have a tendency to accumulate enormous
      classpaths.  Looking at such a classpath, you might be hard put
      to know whether any given jar is really needed.  Perhaps it was
      needed at the time it was added, but that need has long since
      evaporated.  How can you tell?  Having jars you don't need means
      your application will be slower starting up, and perhaps also
      while running.  It also means that you might be worrying
      unnecessarily about getting the latest version of a jar that
      you're not actually using.</p>

    <p><a
      href="http://www.linkedin.com/ppl/webprofile?id=6042912">Kyrill
      Alyoshin</a> has an elegant solution using a <a
      href="http://java.sun.com/javase/6/docs/api/java/lang/instrument/package-summary.html">java.lang.instrument</a>
      agent.  The basic idea is that you run your application with
      <code>java&nbsp;-javaagent:loosejar.jar&nbsp;...</code> and the
      agent in <code>loosejar.jar</code> can find all the classes that
      the application has loaded using <a
      href="http://java.sun.com/javase/6/docs/api/java/lang/instrument/Instrumentation.html#getAllLoadedClasses()">Instrumentation.getAllLoadedClasses()</a>.
      Then for each of those classes it can find what jar it came
      from.  Thus for each jar on the classpath it can compute the
      number of classes that have actually been loaded from it.  When
      this number is zero, the jar might be unnecessary.</p>

    <p>Of course for the results to be valid you have to exercise the
      application so that it does everything it can do.  That might
      not always be easy, but for a candidate jar you can often figure
      out what to do to make the jar be referenced.  To help you do
      this incrementally, the loosejar agent exports a <a
      href="http://java.sun.com/jmx" rel="tag">JMX</a> MBean that
      allows you to ask for a report while the application is
      running.  So you can connect with JConsole and get a report, see
      what jars might be unnecessary, try to provoke class-loading
      from those jars, get another report, and so on.</p>

    <blockquote>
    <p>One subtlety is that the set of jars is not just the contents
      of the classpath.  The jar could reference other jars through a <a
	href="http://java.sun.com/docs/books/tutorial/deployment/jar/downman.html">Class-Path</a>
      entry in its manifest.  You'd like to know if all of those other
      jars are really necessary too.  Kyrill and I were unable to find
      a better way to get the <a
      href="http://en.wikipedia.org/wiki/Transitive_closure">transitive
      closure</a> of referenced jar files than to use <a
      href="http://java.sun.com/javase/6/docs/api/java/lang/ClassLoader.html#getResources(java.lang.String)">ClassLoader.getResources</a>("META-INF/MANIFEST.MF")
      and parse the returned <code>jar:</code> URLs.  Every jar has a
      <code>META-INF/MANIFEST.MF</code> file, so every jar known by
      the ClassLoader will show up in the result of this call, but
      ugh.  There has to be a better way.</p>
    </blockquote>

    <p>Kyrill's <code>loosejar</code> project is hosted on <a
	href="http://code.google.com/p/loosejar/">Google Code</a>.</p>
]]>

</content>
</entry>
<entry>
<title>VisualVM - All-in-One Java Troubleshooting Tool</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/archive/2008/02/visualvm_allino.html" />
<modified>2008-02-20T15:40:15Z</modified>
<issued>2008-02-20T15:40:07Z</issued>
<id>tag:weblogs.java.net,2008:/blog/emcmanus/254.9238</id>
<created>2008-02-20T15:40:07Z</created>
<summary type="text/plain">VisualVM is a new graphical troubleshooting tool that is being developed in a project on java.net.</summary>
<author>
<name>emcmanus</name>

<email>eamonn.mcmanus@sun.com</email>
</author>

<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/emcmanus/">
<![CDATA[<script src="http://weblogs.java.net/blog/emcmanus/archive/j1button.js" type="text/javascript"></script>

<p><a href="https://visualvm.dev.java.net/">VisualVM</a> is a new graphical troubleshooting tool that is being developed in a project on java.net.  It gives access to the functionality that is available through existing JDK tools such as <a href="http://openjdk.java.net/tools/svc/jconsole" rel="tag">JConsole</a>, <a href="http://java.sun.com/javase/6/docs/technotes/tools/share/jinfo.html">jinfo</a>, and <a href="http://java.sun.com/javase/6/docs/technotes/tools/share/jstack.html">jstack</a>, and adds to that support for lightweight profiling of CPU and memory usage.</p>

<p>These screenshots from the project page give an idea of what the tool can do.</p>

<a href="https://visualvm.dev.java.net/images/screenshot2.png"><img src="https://visualvm.dev.java.net/images/screenshot2_small.png" alt="Basic telemetry of running Java app"></a>
<a href="https://visualvm.dev.java.net/images/screenshot3.png"><img src="https://visualvm.dev.java.net/images/screenshot3_small.png" alt="Profiling performance of running Java app"></a>

<p>The tool is extensible via downloadable plugins, and the latest milestone publishes an API for developing your own plugins.  Also, if you have developed plugins using the <a href="http://java.sun.com/javase/6/docs/jdk/api/jconsole/spec/index.html">JConsole Plugin API</a> it's possible to use them unchanged in VisualVM.</p>

<p>I'm not personally involved in this project but I'm certainly following it with great interest.</p>

<p>[Tags: <a href="http://technorati.com/tag/visualvm" rel="tag">visualvm</a>.]]]>

</content>
</entry>
<entry>
<title>Speaking at JavaOne</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/archive/2008/02/speaking_at_jav.html" />
<modified>2008-02-19T10:29:32Z</modified>
<issued>2008-02-19T10:29:21Z</issued>
<id>tag:weblogs.java.net,2008:/blog/emcmanus/254.9226</id>
<created>2008-02-19T10:29:21Z</created>
<summary type="text/plain"><![CDATA[I'll be speaking at JavaOne again this year, in a double act with Jean-Fran&ccedil;ois.]]></summary>
<author>
<name>emcmanus</name>

<email>eamonn.mcmanus@sun.com</email>
</author>

<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/emcmanus/">
<![CDATA[<script src="http://weblogs.java.net/blog/emcmanus/archive/j1button.js" type="text/javascript"></script>

<p>I'll be speaking at <a href="http://java.sun.com/javaone" rel="tag">JavaOne</a> again this year.  As in the previous two years, I'll be sharing the stage with <a href="http://blogs.sun.com/jmxnetbeans/">Jean-Fran&ccedil;ois Denise</a>.  The main subject will be the contents of the two <a href="http://java.sun.com/jmx rel="tag">JMX</a>-related JSRs that are nearing completion: <a href="http://jcp.org/en/jsr/detail?id=255">JSR 255</a>, which is defining version 2.0 of the JMX API, and <a href="http://jcp.org/en/jsr/detail?id=262">JSR 262</a>, which is defining a Web Services Connector.</p>

<p>Our session is <a href="https://www28.cplan.com/cc191/session_details.jsp?isid=295199&ilocation_id=191-1&ilanguage=english">TS-5199</a>.  Here's the abstract:</p>

<blockquote>
<p>The Java<font size="-1"><super>TM</super></font> Management Extensions (JMX<font size="-1"><super>TM</super></font>) API, part of the core Java platform since release 5.0, is being updated through two JSRs nearing completion: JSR 255 (JMX API 2.0) and JSR 262 (Web Services Connector). In this session, members of Sun’s JMX API team discuss the state of the art and explain how the new JSRs will improve scalability, ease of use, and interoperation.</p>

<p>Scalability covers larger applications with more managed objects and distributed management across many machines.</p>

<p>Ease of use covers several new annotations to make it easier to define managed objects. Annotations also make it easier to expose descriptions of those objects to management consoles, including internationalized descriptions. A new query language makes it easier to select objects that match certain criteria.</p>

<p>Interoperation covers management of Java technology-based applications by programs not running on the Java platform, such as scripts, or tools using the WS-Management standard. JSR 262 facilitates the integration of Java technology-based applications into heterogeneous management environments.</p>

<p>This session does not assume detailed knowledge of JMX technology.</p>

</blockquote>

<p>In all, there are <a href="https://www28.cplan.com/cc191/sessions_catalog.jsp?ilc=191-1&ilg=english&isort=&isort_type=&is=yes&icriteria1=+&icriteria2=+&icriteria9=&icriteria8=jmx&icriteria3=">six sessions</a> at the conference that mention "JMX" in the abstract - three Technical Sessions and three BOFs.  Our Technical Session looks like the only one where JMX technology is the principal focus, but two-and-a-half of the three BOFs will be about it too.  Should be interesting!</p>]]>

</content>
</entry>
<entry>
<title>Public Review of Web Services Connector for JMX Agents</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/archive/2008/02/public_review_o.html" />
<modified>2008-02-18T16:58:32Z</modified>
<issued>2008-02-18T16:52:35Z</issued>
<id>tag:weblogs.java.net,2008:/blog/emcmanus/254.9219</id>
<created>2008-02-18T16:52:35Z</created>
<summary type="text/plain">The Public Review of JSR 262, &quot;Web Services Connector for JMX Agents&quot;, is underway, and there&apos;s a new snapshot of the Reference Implementation that corresponds to the Public Review specification.</summary>
<author>
<name>emcmanus</name>

<email>eamonn.mcmanus@sun.com</email>
</author>
<dc:subject>JSR</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/emcmanus/">
<![CDATA[<p>The <a href="http://jcp.org/aboutJava/communityprocess/pr/jsr262/index.html">Public Review</a> of JSR 262, "Web Services Connector for JMX Agents", is underway, and there's a new snapshot of the <a href="https://ws-jmx-connector.dev.java.net/">Reference Implementation</a> that corresponds to the Public Review specification.</p>

<p>Jean-Fran&ccedil;ois's <a href="http://blogs.sun.com/jmxnetbeans/entry/web_services_connector_for_jmx">blog</a> has the full details.</p>

<p>[Tags: <a href="http://java.sun.com/jmx" rel="tag">jmx</a> <a href="http://technorati.com/tag/jsr262" rel="tag">jsr262</a> <a href="http://technorati.com/tag/ws-management" rel="tag">ws-management</a>.]]]>

</content>
</entry>
<entry>
<title>JMX API 2.0 Early Draft Review</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/archive/2007/12/jmx_api_20_earl_1.html" />
<modified>2007-12-28T10:14:36Z</modified>
<issued>2007-12-28T10:14:27Z</issued>
<id>tag:weblogs.java.net,2007:/blog/emcmanus/254.8898</id>
<created>2007-12-28T10:14:27Z</created>
<summary type="text/plain">The first draft of JSR 255 is out!  This defines version 2.0 of
      the JMX API.  We&apos;re planning to integrate it into the Java SE 7
      platform.  Here&apos;s a summary of the important changes.</summary>
<author>
<name>emcmanus</name>

<email>eamonn.mcmanus@sun.com</email>
</author>
<dc:subject>Community: JDK</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/emcmanus/">
<![CDATA[    <p>The <a
	href="http://jcp.org/aboutJava/communityprocess/edr/jsr255/index.html">first
	draft</a> of JSR 255 is out!  This defines version 2.0 of
      the JMX API.  We're planning to integrate it into the Java SE 7
      platform, subject to the approval of the Expert Group for that
      platform.</p>

    <p>Here's a summary of the important changes.  If you're
      interested, I'd encourage you to download the draft and look at
      the summary in the Overview Description, which has links into
      the relevant parts of the API.</p>

    <p>This draft contains all the major features that we are planning
      to add in this version of the API.  If there's anything you'd like
      to see changed, this would be a very good time to <a
	href="mailto:jmx-spec-comments@sun.com">let us know</a>!</p>
        
    <h3>Namespaces and Cascading</h3>
    
    <p>The concept of <b>namespaces</b> is new. All MBeans whose domain
      begins with <code>foo//</code>, for example
      <code>foo//com.example:type=CacheController</code>, belong
      to the namespace <code>foo//</code>. Previously,
      <code>MBeanServer.queryNames(null, null))</code> returned
      a list of all MBeans. Now, MBeans within namespaces do not
      appear in that list. Additionally, namespaces can contain
      <b>Virtual MBeans</b> which do not have to exist as Java
      objects when they are not being accessed.  Namespaces
      allow much improved scalability, especially when accessing
      certain MBeans is expensive.</p>

    <p><b>Cascading</b> or <b>Federation</b> means that it is
      straightforward to import MBeans from a remote MBean Server as if they
      were local. This <a
	href="http://weblogs.java.net/blog/emcmanus/archive/2007/02/cascading_its_a_1.html">blog
	entry</a> gives an overview of what Cascading is about.</p>
    
    <h3>Event Service and Notifications</h3>
    
    <p>The <b>Event Service</b> provides greater control over notification
      handling than the default technique using
      <code>MBeanServer.addNotificationListener</code>. The Event
      Service separates the logic for notification handling from the
      particular connector that you are using. You can transport
      notifications using that connector, or using a completely
      different transport. See the description of the
      <CODE>javax.management.event</CODE> package for more
      information.</p>

    <p>A new class <b><CODE>QueryNotificationFilter</CODE></b>
      allows notifications to be filtered using the existing query
      subsystem.</p>

    <p>Resource injection provides an alternative to implementing the
      <CODE>NotificationBroadcaster</CODE> interface or extending the
      <CODE>NotificationBroadcasterSupport</CODE> class. See the next
      section.</p>
    
    <h3>Annotations and Resource Injection</h3>
    
    <p>MBeans can now be defined using <b>annotations</b>. Also, the
      <b>@Resource</b> annotation allows an MBean to get a reference
      to its MBeanServer and ObjectName references, as an alternative
      to implementing <CODE>MBeanRegistration</CODE>.</p>

    <p><a
	href="http://weblogs.java.net/blog/emcmanus/archive/2007/08/defining_mbeans.html">This
        blog entry</a> provides details and rationale.</p>
    
    <h3>Client Contexts and Localization</h3>
    
    <p>MBeans now have access to a <b>context</b> that can contain
      information such as locale or transaction ids. (Note though that there
      is no explicit support for transactions in the API.)</p>

    <p>The descriptions in an <CODE>MBeanInfo</CODE> can be
      <b>localized</b> using a new method
      <CODE>MBeanInfo.localizeDescriptions</CODE>.  A way will be
      provided to cause this method to be called for all MBeans, using
      a locale communicated by a remote client. The details are still
      being sorted out so this area of the API will change.</p>
    
    <h3>Queries</h3>
    
    <p>A new <b>Query Language</b> provides an alternative way to
      specify queries that is often simpler than constructing
      <CODE>QueryExp</CODE> objects using the static methods of the
      <CODE>Query</CODE> class. (The idea of an SQL-like query
      language for JMX queries was first proposed by Norbert Lataille
      and Marc Fleury in 2000, although the language in this draft is
      not derived from that proposal.)</p>

    <p>Attributes appearing in a query can now use a dot (.) to
      specify a value contained in an <b>attribute of complex
      type</b>, similar to the existing support in the
      <CODE>javax.management.monitor</CODE> package.</p>
    
    <h3>MXBeans</h3>
    
    <p>The <b>type mappings</b> can now be customized for any MXBean
      using annotations or options.  Previously the mapping rules were
      fixed.</p>
    
    <h3>Options for StandardMBean and Proxies</h3>
    
    <p>A new <b><CODE>MBeanOptions</CODE></b>
      class provides control over details of <CODE>StandardMBean</CODE>
      and MXBean proxy operation.</p>
    
    <h3>DynamicWrapperMBean</h3>
    
    <p>A new interface <b><CODE>DynamicWrapperMBean</CODE></b> gives
      better behaviour for MBeans that wrap other objects, in
      particular as regards class loading.</p>
    
    <h3>NotificationManager interface</h3>
    
    <p>Three methods of the <CODE>MBeanServerConnection</CODE>
      interface are promoted to a <b>new parent interface</b>
      <CODE>NotificationManager</CODE>, which can be implemented by
      classes such as <CODE>EventClient</CODE> that provide
      addNotificationListener/removeNotificationListener
      functionality.</p>
    
    <h3>Model MBeans</h3>
    
    <p>It is no longer required that the <CODE>Descriptor</CODE>
      in, for example, ModelMBeanAttributeInfo contain redundant
      <code>descriptorType</code> and <code>name</code> fields. The
      previously-required values are <b>supplied
	by default</b> if omitted. (Thanks to Lars Westergren for this
      contribution.)</p>

    <h3>Send feedback!</h3>

    <p>Feel free to comment here, or send mail to <a
	href="mailto:jmx-spec-comments@sun.com">jmx-spec-comments@sun.com</a>.</p>

    <p>[Tags:
      <a href="http://java.sun.com/jmx" rel="tag">jmx</a>
      <a href="http://technorati.com/tag/jsr" rel="tag">jsr</a>
      <a href="http://technorati.com/tag/jsr255" rel="tag">jsr255</a>
      <a href="http://technorati.com/tag/jcp" rel="tag">jcp</a>
      <a href="http://jcp.org/aboutJava/communityprocess/edr" rel="tag">edr</a>]</p>
]]>

</content>
</entry>
<entry>
<title>Java SNMP now available in OpenDMK</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/archive/2007/10/java_snmp_now_a.html" />
<modified>2007-10-04T13:15:00Z</modified>
<issued>2007-10-04T13:14:52Z</issued>
<id>tag:weblogs.java.net,2007:/blog/emcmanus/254.8371</id>
<created>2007-10-04T13:14:52Z</created>
<summary type="text/plain">The OpenDMK project now includes the SNMP API from Sun&apos;s Java DMK product.  Kudos to Daniel Fuchs who put in the considerable work to make this happen!</summary>
<author>
<name>emcmanus</name>

<email>eamonn.mcmanus@sun.com</email>
</author>
<dc:subject>Open Source</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/emcmanus/">
<![CDATA[<p>The <a href="http://opendmk.dev.java.net/">OpenDMK</a> project now includes the SNMP API from Sun's <a href="http://java.sun.com/products/jdmk/index.jsp">Java DMK</a> product.  Kudos to <a href="http://blogs.sun.com/jmxetc/date/20071002">Daniel Fuchs</a> who put in the considerable work to make this happen!</p>

<p>This API includes the necessary interfaces to build both managers (clients) and agents (servers) that use SNMP.  It also includes a tool called mibgen which takes an SNMP MIB (schema) and generates skeleton JMX MBeans.  Implementing the MIB in an agent is then just a question of filling in the right behaviour in those MBeans.  <a href="http://blogs.sun.com/jmxetc/">Daniel's blog</a> has much more information about SNMP and about OpenDMK.</p>

<p>Some parts of this SNMP code are still encumbered so we're not yet able to release full source.  We're working on that, but in the meantime the missing parts are supplied as a binary plug, in the manner of <a href="http://openjdk.java.net/">OpenJDK</a>.</p>]]>

</content>
</entry>
<entry>
<title>Defining MBeans with annotations</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/archive/2007/08/defining_mbeans.html" />
<modified>2007-08-31T16:12:06Z</modified>
<issued>2007-08-31T16:11:57Z</issued>
<id>tag:weblogs.java.net,2007:/blog/emcmanus/254.8142</id>
<created>2007-08-31T16:11:57Z</created>
<summary type="text/plain">The number one question I get about the JMX API at conferences and other public
      events is whether there will be support for defining MBeans using
      annotations.  There will.  Here are some provisional details.</summary>
<author>
<name>emcmanus</name>

<email>eamonn.mcmanus@sun.com</email>
</author>
<dc:subject>Community: JDK</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/emcmanus/">
<![CDATA[    <p>The number one question I get about the JMX API at conferences
      and other public events is whether there will be support for
      defining MBeans using annotations.  People see that they can
      make EJBs or Web Services just by adding annotations to a <a
      href="http://en.wikipedia.org/wiki/Plain_Old_Java_Object">POJO</a>,
      and they ask why they can't make MBeans the same way.  In
      version 2.0 of the JMX API, being defined by <a
      href="http://jcp.org/en/jsr/detail?id=255">JSR 255</a>, this
      will be possible.</p>

    <p>The exact details are still subject to change as a result of
      discussions within the JSR 255 Expert Group, but here's a snapshot
      of where we are now.  I think the final version will be fairly
      close to this.</p>

    <p>In addition to defining MBeans with annotations, there are some
      new proposed annotations that will also apply to MBeans defined
      in the existing ways.</p>

    <h4>Prior art</h4>

    <p>Several projects already exist that provide this functionality,
      but the most developed is probably Spring. So our starting point
      was <a
      href="http://static.springframework.org/spring/docs/2.0.x/reference/jmx.html#jmx-interface-annotations">Spring's
	MBean annotations</a> (see also <a
	href="http://static.springframework.org/spring/docs/2.0.x/api/org/springframework/jmx/export/annotation/package-summary.html">API
	documentation</a>).</p>

    <h4>Defining an MBean</h4>

    <p>In the proposed design, an MBean can be defined through
      annotations to achieve the same effect as a <a
	href="http://java.sun.com/docs/books/tutorial/jmx/mbeans/standard.html">Standard
	MBean</a>.  In this and other examples, I'll show what you write
      with today's API, and what you'll be able to write with the new
      annotations.</p>

<table><tr><th>Today</th><th>Tomorrow</th></tr><tr><td><!--
--><pre style="width: 350px">public interface CacheMBean {
    public int getSize();
    public void setSize(int size);

    public int getUsed();

    public int dropOldest(int n);
}

public class Cache <b>implements CacheMBean</b> {

    public int getSize() {...}

    public void setSize(int size) {...}


    public int getUsed() {...}


    public int dropOldest(int n) {...}
}</pre></td><td><!--
--><pre style="width: 350px">&nbsp;







<b>@MBean</b>
public class Cache {
    <b>@ManagedAttribute</b>
    public int getSize() {...}
    <b>@ManagedAttribute</b>
    public void setSize(int size) {...}

    <b>@ManagedAttribute</b>
    public int getUsed() {...}

    <b>@ManagedOperation</b>
    public int dropOldest(int n) {...}
}</pre></td></tr></table>

    <p>This defines an MBean with read-only attribute <code>Used</code>,
      read-write attribute <code>Size</code>, and operation
      <code>dropOldest</code>.</p>

    <p>I'll call an MBean defined this way an <em>@MBean</em>.</p>

    <p>One way to look at this is that with the existing Standard MBeans,
      public methods from the class are picked out as being management
      methods by virtue of being in the Standard MBean interface that
      the class implements.  So in this example the
      <code>CacheMBean</code> interface defines which methods in
      <code>Cache</code> are the management methods.  In the new form,
      the methods are picked out by being annotated, and there is no
      need to define an interface.</p>

    <h4>Pros and cons of @MBeans</h4>

    <p>The new style appears considerably more convenient than
      Standard MBeans.  You only have to maintain one source file,
      rather than managing a class and an interface.</p>

    <p>There is a downside, however, which may show up in bigger
      projects.  The advantage of the Standard MBean approach is that
      the MBean interface tells you exactly what the attributes and
      operations of the MBean are.  There is no extraneous information
      in the MBean interface: every method defines an attribute or an
      operation.</p>

    <p>On the other hand, with @MBeans the management attributes and
      operations are potentially mixed in with many other methods,
      public or private.  So it is not immediately obvious what the
      management interface of the MBean is.</p>

    <p>This disadvantage applies both when reading the source code and
      when looking at the Javadoc output.</p>

    <p>A second disadvantage is that it is no longer possible to
      construct a <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/JMX.html#newMBeanProxy(javax.management.MBeanServerConnection,%20javax.management.ObjectName,%20java.lang.Class)">proxy</a>.
      Proxies simplify client code by allowing it to access attributes
      and operations as compiler-checked method calls.  They don't
      matter if you are only going to interact with your MBeans
      through a graphical interface like <a
      href="http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html">JConsole</a>,
      but they are a big help if you are writing an application that
      will interact with your MBeans specifically.</p>

    <p>For smallish projects, these disadvantages are likely to be
      minor.  Furthermore, it should be possible to define an <a
	href="http://weblogs.java.net/blog/emcmanus/archive/2006/06/using_annotatio.html">annotation
	processor</a> that extracts a Standard MBean interface from an
      @MBean, so it can be used for documentation and proxying.  In
      the example above, the annotation processor could create the
      <code>CacheMBean</code> interface every time you compile your
      program, based on the <code>@ManagedAttribute</code> and
      <code>@ManagedOperation</code> annotations in the
      <code>Cache</code> class.</p>

    <h4>Defining an MXBean</h4>

    <p>The existing <code><a
	  href="http://java.sun.com/javase/6/docs/api/javax/management/MXBean.html">@MXBean</a></code>
      annotation can be used instead of <code>@MBean</code> to define
      an <a
      href="http://weblogs.java.net/blog/emcmanus/archive/2006/02/what_is_an_mxbe.html">MXBean</a>
      rather than a Standard MBean.</p>

    <pre><b>@MXBean</b>
public class Cache {
    ...remainder as above...
}</pre>

    <h4>Descriptions</h4>

    <p>Although the JMX API allows for textual descriptions to be
      associated with attributes, operations, and parameters, when you
      use a Standard MBean today these descriptions have meaningless
      default values.  I've written <a
	href="http://weblogs.java.net/blog/emcmanus/archive/2005/07/adding_informat.html">before</a>
      about how you can add meaningful descriptions, but it isn't
      easy.  This is a really obvious use for annotations.</p>

    <p>The proposed new <code>@Description</code> annotation can be used with
      Standard MBeans, MXBeans, and @MBeans.  (Notice that both
      columns use the new API here!)</p>

<table><tr><th>Tomorrow's Standard MBean</th><th>Tomorrow's @MBean</th></tr><tr><td><!--
--><pre style="width: 350px"><b>@Description("some sort of cache")</b>
public interface CacheMBean {

    <b>@Description("number of cache slots in use")</b>
    public int getUsed();
    ...
}

public class Cache implements CacheMBean {

    public int getUsed() {...}
    ...
}</pre></td><td><!--
--><pre style="width: 350px"><b>@Description("some sort of cache")</b>
public class Cache {
    @ManagedAttribute
    <b>@Description("number of cache slots in use")</b>
    public int getUsed() {...}
    ...
}






</pre></td></tr></table>

    <p>We international types will of course be thinking about
      internationalization, and I'll have more to say about that <a
	href="#i18n">below</a>.</p>

    <h4>Finding the MBeanServer and/or ObjectName</h4>

    <p>Often an MBean needs to know what MBean Server it is registered
      in, or what its name is in that MBean Server.  To do this it
      currently needs to implement the <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/MBeanRegistration.html"><code>MBeanRegistration</code></a>
      callback interface.  The required values are passed to that
      interface's <a
      href="http://java.sun.com/javase/6/docs/api/javax/management/MBeanRegistration.html#preRegister(javax.management.MBeanServer,%20javax.management.ObjectName)"><code>preRegister</code></a>
      method.  But the interface contains three other methods, which
      the MBean must implement even if it has nothing interesting to
      do in them.</p>

    <p>In the new proposal, the <code><a
	  href="http://java.sun.com/javase/6/docs/api/javax/annotation/Resource.html">@Resource</a></code>
      annotation from <a
      href="http://java.sun.com/javase/6/docs/api/javax/annotation/package-summary.html"><code>javax.annotation</code></a>
      can be used instead of implementing
      <code>MBeanRegistration</code> when all that's needed is to
      discover what the MBeanServer or ObjectName is:</p>

<table><tr><th>Today</th><th>Tomorrow</th></tr><tr><td><!--
--><pre style="width: 350px">&nbsp;
public class Cache
    	implements CacheMBean, <b>MBeanRegistration</b> {

    private volatile MBeanServer mbs;

    private volatile ObjectName myName;

    public ObjectName <b>preRegister</b>(
    	    MBeanServer mbs, ObjectName name) {
    	this.mbs = mbs;
    	this.myName = name;
    	return name;
    }
    public void <b>postRegister</b>(Boolean done) {}
    public void <b>preDeregister</b>() {}
    public void <b>postDeregister</b>() {}

    ...
}</pre></td><td><!--
--><pre style="width: 350px">@MBean
public class Cache {

    <b>@Resource</b>
    private volatile MBeanServer mbs;
    <b>@Resource</b>
    private volatile ObjectName myName;











    ...
}
</pre></td></tr></table>

    <p>When the MBean is registered, the MBean Server will <a
	href="http://java.sun.com/javaee/5/docs/tutorial/doc/Resources4.html">inject</a>
      the appropriate values into these fields.</p>

    <p>This possibility is open to all types of MBeans, not just
      @MBeans.  You could continue to have a Standard MBean as today,
      but stop implementing <code>MBeanRegistration</code> in favour
      of <code>@Resource</code> annotations.</p>

<h4>Simplified notification handling</h4>

    <p>Today, if an MBean emits notifications then it must implement
      the <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/NotificationBroadcaster.html"><code>NotificationBroadcaster</code></a>
	or <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/NotificationEmitter.html"><code>NotificationEmitter</code></a>
      interface.  This means it must keep track of the set of listeners,
      as listeners are <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/NotificationBroadcaster.html#addNotificationListener(javax.management.NotificationListener,%20javax.management.NotificationFilter,%20java.lang.Object)">added</a>
      and <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/NotificationBroadcaster.html#removeNotificationListener(javax.management.NotificationListener)">removed</a>.
      It must also define the list of notification types that it can
      emit, by implementing <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/NotificationBroadcaster.html#getNotificationInfo()"><code>getNotificationInfo()</code></a>.</p>

    <p>In practice, everybody uses the <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/NotificationBroadcasterSupport.html"><code>NotificationBroadcasterSupport</code></a>
      class instead of doing all this work themselves.  In the simplest
      case, you just inherit from that class, and pass the list of
      notification types to the superclass constructor.  If you already
      have a superclass, then you need to have a private
      <code>NotificationBroadcasterSupport</code> instance and delegate
      the <code>NotificationBroadcaster</code> methods to it.</p>

    <p>New annotations allow you to define the list of notification
      types more simply, and to emit notifications without having to
      keep track of listeners.</p>

<table><tr><th>Today</th><th>Tomorrow</th></tr><tr><td><!--
--><pre style="width: 350px">&nbsp;


public class Cache
    	<b>extends NotificationBroadcasterSupport</b>
    	implements CacheMBean {
    public Cache() {
    	super(new MBeanNotificationInfo[] {
    	    new MBeanNotificationInfo(
    	    	new String[] {"my.notif.type"},
    	    	Notification.class.getName(),
    	    	"my notification"
    	    )}
    	);
    }

    ...
    void somethingHappened() {
    	Notification n = new Notification(...);
    	<b>super.sendNotification(n);</b>
    }
    ...
}</pre></td><td><!--
--><pre style="width: 350px">@MBean
<b>@NotificationInfo(types={"my.notif.type"},
    description=@Description("my notification"))</b>
public class Cache {


    <b>@Resource</b>
    private volatile <b>SendNotification send</b>;








    ...
    void somethingHappened() {
    	Notification n = new Notification(...);
        <b>send.sendNotification(n);</b>
    }
    ...
}
</pre></td></tr></table>

    <p>The <code>@NotificationInfo</code> annotation is what allows
      you to avoid constructing an <code>MBeanNotificationInfo</code>
      as in the messy "Today" code.</p>

    <p>The new <code>SendNotification</code> interface contains just
      the method <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/NotificationBroadcasterSupport.html#sendNotification(javax.management.Notification)"><code>sendNotification</code></a>.
      When you register this MBean in the MBean Server, it will inject
      an object into the <code>send</code> field which allows the MBean
      to send notifications.  The MBean no longer has to be concerned
      with managing listeners, which happens somewhere behind the
      scenes.</p>

    <p>Resource injection of <code>SendNotification</code> is
      available to all types of MBeans.  Defining the notification types
      with <code>@NotificationInfo</code> is not available to Dynamic
      MBeans, which are expected to provide a complete <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/MBeanInfo.html"><code>MBeanInfo</code></a>,
      including the <code>MBeanNotificationInfo[]</code> array.</p>

    <p>More detail than you want to know about
      <code>@NotificationInfo</code> appears <a
	href="#notifinfo">below</a>.</p>

    <h4>You can stop reading now</h4>

    <p>If your eyes are already glazing over with all this code, you
      can safely stop here, and you'll have seen the main ideas.  The
      remainder of this entry is about secondary items, and further
      details about the main ones.</p>

<h4>Descriptor contents</h4>

    <p>In the JMX API included in the Java SE 6 platform, we
      introduced a way to define your own annotations to specify
      Descriptor contents. So you might define @Units like this:</p>

<pre>@Documented @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface <b>Units</b> {
    <b>@DescriptorKey("units")
    </b>String value();
}
</pre>

    <p>The new API accepts such annotations on classes or methods that
      also have the @ManagedX annotations. For example:</p>

<pre>@MBean
public class Cache {
    ...
    <b>@Units("bytes")</b>
    @ManagedAttribute
    public int getUsed() {...}
    ...
}
</pre>

    <p>We've also added a new <code>@DesriptorFields</code>
      annotation, since the use of <code>@DescriptorKey</code> is
      somewhat non-obvious, and overkill for occasional use. So you
      can achieve the same effect like this:</p>

<pre>@MBean
public class Cache {
    ...
    <b>@DescriptorFields("units=bytes")</b>
    @ManagedAttribute
    public int getUsed() {...}
    ...
}
</pre>

    <p>This annotation can be used in Standard MBeans and MXBeans as well
      as @MBeans and @MXBeans.</p>

<h4>Operation impact</h4>

    <p>The <code>@ManagedOperation</code> annotation has an optional element <code>impact</code>
      of type <code>Impact</code>. This is a new enum with values
      <code>{INFO, ACTION, ACTION_INFO, UNKNOWN}</code> corresponding
      to the integer codes defined by <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/MBeanOperationInfo.html#INFO"><code>MBeanOperationInfo</code></a>.
      So you can do this:</p>

<pre>@MBean
public class Cache {
    ...
    <b>@ManagedOperation(impact = Impact.ACTION)</b>
    public int dropOldest(int n) {...}
}
</pre>

    <p>You can also apply <code>@ManagedOperation</code> to a method in a
      Standard MBean interface or an MXBean interface in order to
      specify the impact.</p>

<h4>MBean constructors</h4>

    <p>Each public constructor in an @MBean or @MXBean is converted into an
      <code>MBeanConstructorInfo</code> inside the MBean's
      <code>MBeanInfo</code>.  This is exactly the same as for
      existing Standard MBeans and MXBeans.</p>

<h4>StandardMBean class</h4>

    <p>The class <code><a
    href="http://java.sun.com/javase/6/docs/api/javax/management/StandardMBean.html">StandardMBean</a></code>
    can be used to customize an @MBean or an @MXBean in the same way
    as for a Standard MBean or MXBean today. You simply supply
    <code>null</code> for the <code>mbeanInterface</code> parameter in
    the constructor.</p>

<h4>Details on Resource injection</h4>

    <p>The <code>@Resource</code> annotation can be used to inject an
      <code>ObjectName</code>, <code>MBeanServer</code>, or
      <code>SendNotification</code>. The annotation can be applied to
      a field or to a <code>void</code> method with a single
      parameter. For example:</p>

<pre>    @Resource  // field injection
    private volatile ObjectName name;

    private MBeanServer mbs;
    @Resource  // method injection
    private synchronized void setMBeanServer(MBeanServer mbs) {
        this.mbs = mbs;
    }
</pre>

    <p>The MBean Server determines what to inject based on the
      type. The type is either the declared type of the field or
      parameter, or it is specified explicitly in the
      <code>@Resource</code> annotation. For example, the following
      annotations have the same effect:</p>

<pre>    @Resource
    private volatile ObjectName name;

    @Resource(<b>type = ObjectName.class</b>)
    private volatile <b>Object</b> name;
</pre>

    <p>I don't think the second form will be used very often, but it might
      be used to inject the <code>MBeanServer</code> into a field of
      type <code>MBeanServerConnection</code>, for example.</p>

    <p>The ObjectName (etc) will be injected as many times as there are
      appropriate <code>@Resource</code> annotations, including in parent
      classes.</p>

    <p><code>@Resource</code> annotations that don't match one of the given
      types are ignored. (Perhaps they are for some other API.) But
      even if the type is not recognized, <code>@Resource</code>
      fields and methods must be instance (not static), and
      <code>@Resource</code> methods must have exactly one parameter
      and return void.</p>

    <p>I've used <code>volatile</code> in all these examples because the <a
	href="http://www.cs.umd.edu/%7Epugh/java/memoryModel/">Java Memory
	Model</a> would not otherwise guarantee that the MBean would actually
      see the injected values. For method-based injection,
      <code>synchronized</code> is an alternative, provided the MBean
      also uses <code>synchronized</code> to access the injected
      value.  Notice that the same considerations apply to the
      existing <code>MBeanRegistration</code> technique.</p>

    <p>Resource injection happens after the MBean's <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/MBeanRegistration.html#preRegister%28javax.management.MBeanServer,%20javax.management.ObjectName%29"><code>preRegister</code></a>
      method (if any) is called, but before the MBean is registered in the
      MBean Server. If an injection method throws an exception, then <code><a
	  href="http://java.sun.com/javase/6/docs/api/javax/management/MBeanRegistration.html#postRegister%28java.lang.Boolean%29">postRegister(false)</a></code>
      will be called and the exception will be thrown in the same way
      as for <code>preRegister</code>.</p>

    <h4 id="i18n">More on descriptions</h4>

    <p>In addition to the description text, the <code>@Description</code>
      annotation can specify the values of the <code>descriptionResourceBundleBaseName</code>
      and <code>descriptionResourceKey</code> fields in the corresponding <code><a
	  href="http://java.sun.com/javase/6/docs/api/javax/management/Descriptor.html">Descriptor</a></code>.
	  This is enough to allow for internationalization:</p>

<pre>@Description(value="some sort of cache",
             key="cache.mbean.description",
             bundleBaseName="MyResources")
</pre>

    <p>To complete the story here, we need to have something that is
      able to apply these Descriptor fields to localize the
      <code>MBeanInfo</code>.  We have some ideas on what that
      something might look like, but they are not yet fully
      formed.</p>

<h4 id="notifinfo">More on @NotificationInfo</h4>

    <p>As I threatened, here is more information than you wanted to
      know about <code>@NotificationInfo</code>.</p>

    <p>If an MBean has a <code>@NotificationInfo</code> annotation, then that
      annotation is translated into an <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/MBeanNotificationInfo.html"><code>MBeanNotificationInfo</code></a>
      in the MBean's <code><a
	  href="http://java.sun.com/javase/6/docs/api/javax/management/MBeanInfo.html">MBeanInfo</a></code>.
      <code>MBeanNotificationInfo</code> includes a <a
      href="http://java.sun.com/javase/6/docs/api/javax/management/MBeanFeatureInfo.html#getName()">name</a>
      which is the name of the notification class.  It is usually
      <code>"javax.management.Notification"</code>, but it might be a
      subclass.  So <code>@NotificationInfo</code> has an optional
      <code>notificationClass</code> element which is a
      <code>Class&lt;?&nbsp;extends&nbsp;Notification&gt;</code>.  For
      example:</p>

    <pre>@NotificationInfo(types = {AttributeChangeNotification.ATTRIBUTE_CHANGE},
                  notificationClass = AttributeChangeNotification.class)
    </pre>

    <p>If the MBean can emit more than one class of MBean, then it can
      use <code>@NotificationInfos</code>:</p>

<pre>@NotificationInfos(
    @NotificationInfo(types = {"my.first.notif", "my.second.notif"})
    @NotificationInfo(types = {AttributeChangeNotification.ATTRIBUTE_CHANGE},
                      notificationClass = AttributeChangeNotification.class)
)
</pre>

    <p>The <code>@NotificationInfo</code> is applied to an MBean
      class, but a <code>@Description</code> on that class applies to
      the MBean, not its notifications. The existence of
      <code>@NotificationInfos</code> is another reason why we cannot
      use <code>@Description</code> straightforwardly.</p>

    <p>This is why there is an optional element of type
      <code>@Description</code>
      inside <code>@NotificationInfo</code>, so you would write:</p>

<pre>@NotificationInfo(types={"my.notif.type"},
      <b>description=@Description(value="my notification", key="my.notif.descr")</b>)
</pre>

    <p>You cannot use <code>@DescriptorFields</code>, for the same
      reason as <code>@Description</code>, so there's another optional
      element that allows you to write:<br>

<pre>@NotificationInfo(types={"my.notif.type"},
      <b>descriptorFields={"foo=bar"}</b>)</pre>

    <h4>Ideas still in progress</h4>

    <p>We're studying the possibility of providing a way to cause a
      notification that is sent every time a given operation is
      completed.</p>

    <p>We're looking at ways in which an MBean could say what its <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/ObjectName.html"><code>ObjectName</code></a>
      is.  Probably the MBean would only provide a subset of the
      information needed to construct the name.  It's still unclear
      exactly what this might look like.</p>

<h4>What next?</h4>

    <p>This is still work in progress, as you'll have gathered.  I'm
      very much interested in comments and suggestions, either here or
      at <a
	href="mailto:jmx-spec-comments@sun.com"><code>jmx-spec-comments@sun.com</code></a>.
      Thanks!</p>

    <p>[Tags:
      <a href="http://java.sun.com/jmx" rel="tag">jmx</a>
      <a href="http://technorati.com/tag/jsr" rel="tag">jsr</a>
      <a href="http://technorati.com/tag/jsr" rel="tag">jsr255</a>
      <a href="http://technorati.com/tag/annotations" rel="tag">annotations</a>]</p>]]>

</content>
</entry>
<entry>
<title>When can JMX notifications be lost?</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/archive/2007/08/when_can_jmx_no.html" />
<modified>2007-08-23T08:33:01Z</modified>
<issued>2007-08-23T08:32:53Z</issued>
<id>tag:weblogs.java.net,2007:/blog/emcmanus/254.8087</id>
<created>2007-08-23T08:32:53Z</created>
<summary type="text/plain">The JMX Best Practices guide says notifications can sometimes
      be lost.  Why is that?  When might it happen?  Some answers.</summary>
<author>
<name>emcmanus</name>

<email>eamonn.mcmanus@sun.com</email>
</author>
<dc:subject>Community: JDK</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/emcmanus/">
<![CDATA[    <p>The <a
    href="http://java.sun.com/javase/technologies/core/mntr-mgmt/javamanagement/best-practices.jsp">JMX
	Best Practices</a> guide says notifications can sometimes be lost.
      Why is that?  When might it happen?  Read on.</p>

    <p>Here's the <a
	href="http://java.sun.com/javase/technologies/core/mntr-mgmt/javamanagement/best-practices.jsp#mozTocId387765">relevant
	text</a> from the Best Practices guide:</p>

    <blockquote>
      <p>It is important to be aware of the semantics of notification
	delivery when defining how notifications are used in a
	model. Remote clients cannot assume that they will receive all
	notifications for which they are listening. The JMX Remote API
	only guarantees a weaker condition:</p>

      <blockquote>
	<p>A client either receives all notifications for which it is
	  listening, or can discover that notifications may have been
	  lost.</p>
      </blockquote>
    </blockquote>

    <p>This text might seem somewhat alarming.  First of all, notice
      that it only applies to <em>remote</em> clients.  A local client
      (within the same Java VM) will reliably get all notifications it
      asks for.</p>

    <p>Secondly, the text is describing something that will only
      happen in unusual circumstances.  Notifications will only be lost
      when they arrive so fast that they cannot be delivered to the
      remote client quickly enough, or if there is a long network outage
      during which enough notifications arrive to overflow the
      notification buffer on the server.  If you're sure that the rate
      of notifications is always low then you probably don't need to
      worry.  Long network outages will probably trigger other problems
      in your client, so you'll need to deal with them more generally
      than just worrying about lost notifications.</p>

    <h4>Careful clients</h4>

    <p>But if you have many notifications, you probably want to follow
      the advice in the subsequent paragraphs of the Best Practices
      guide:</p>

    <blockquote>
      <p>Notifications should never be used to deliver information
	that is not also available in another way. The typical client
	observes the initial state of the information model, then reacts
	to changes in the model signalled by notifications. If it sees
	that notifications may have been lost, it goes back and observes
	the state of the model again using the same logic as it used
	initially. The information model must be designed so that this
	is always possible. Losing a notification must not mean losing
	information irretrievably.</p>

      <p>When a notification signals an event that might require
	intervention from the client, the client should be able to
	retrieve the information needed to react. This might be an
	attribute in an MBean that contains the same information as was
	included in the notification. If the information is just that a
	certain event occurred, it is often enough just to have a
	counter of how many times it occurred. Then a client can detect
	that the event occurred just by seeing that the counter has
	changed.</p>
    </blockquote>

    <h4>Stateless servers</h4>

    <p>The design of the existing standard connectors is such that
      notification loss can happen when there are many notifications
      coming from the MBeans in the MBean Server.  This is true even for
      clients that are only listening for a small subset of those
      notifications.  In the extreme case, a client that is listening
      for a very rare notification might not see it, because other
      MBeans are generating frequent notifications that nobody is
      listening to.  Once again, the client can tell that this has
      happened (via <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/remote/JMXConnector.html#addConnectionNotificationListener(javax.management.NotificationListener,%20javax.management.NotificationFilter,%20java.lang.Object)">JMXConnector.addConnectionNotificationListener</a>).</p>

    <p>The existing connectors behave like this because they have been
      designed to have no non-transient state on the server.  A
      consequence is that the server has no non-transient record of
      which clients are interested in which notifications.  Therefore it
      has to store <em>all</em> notifications in its buffer, in case
      some client it doesn't remember is interested in them.</p>

    <p>The servers were designed to have no non-transient state for
      better scalability.  In retrospect, this was probably a design
      mistake.  In many client/server systems, you have one server, or
      just a few servers, and a large number of clients.  So limiting
      state in the server is an excellent idea, because it allows the
      server to handle many more clients.  But in management systems,
      the situation is usually the opposite: you typically have one
      client (a management program such as <a
	href="http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html">JConsole</a>)
      that may connect to and manage many servers.  There are no common
      use cases where a server might have a large number of JMX
      clients.</p>

    <p>In version 2.0 of the JMX API, being defined by <a
	href="http://jcp.org/en/jsr/detail?id=255">JSR 255</a>, we are
      adding an <a
	href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5108776">Event
	Service</a>.  Among other things, this will fix the problem where
      a client might lose notifications that it is interested in because
      there are many other notifications that it is not interested in.</p>

    <h4>Notification loss is inevitable</h4>

    <p>Even with the new Event Service, notification loss will still
      be possible, however.  Can't we get rid of it?</p>

    <p>To answer this question, consider what happens when
      notifications are produced faster than they can be handled.  This
      might be because of network delays, or because the client needs to
      do some work for each notification.  Suppose this situation
      persists.  What should the system do?</p>

    <p>There are basically three possibilities:</p>

    <ol>
      <li>Some notifications are eventually <b>dropped</b>.  This is
	what the JMX Remote API does, and it is also what the new Event
	Service will do.</li>

      <li>Notification senders are <b>slowed down</b>.  This is what
	usually happens in the local case.  An MBean sends a
	notification to a local listener by invoking the listener's <a
	  href="http://java.sun.com/javase/6/docs/api/javax/management/NotificationListener.html#handleNotification(javax.management.Notification,%20java.lang.Object)">handleNotification</a>
	method.  Unless it has multiple threads, the MBean will wait for
	that method to complete before doing anything else, including
	sending any more notifications.</li>

      <li>Notifications <b>accumulate</b> in an unbounded buffer.
	This is actually the worst solution.  In the real world there is
	no such thing as an unbounded buffer.  And even if you save the
	notifications in a giant disk, which is effectively unbounded,
	you still haven't fixed the problem that the client is getting
	further and further behind the server.  When the client finally
	gets a notification that was sent yesterday, is that still any
	use?</li>
    </ol>

    <p>When we were designing the JMX Remote API, we assumed that most
      MBeans that send notifications were not expecting sending to be
      slow.  In the local case, sending is just invoking a method, and
      that method is usually punctual.  If we had wanted to apply
      solution 2, slowing down senders, that could have broken the
      assumptions of existing MBeans.  Coding MBeans so that they can
      cope with a blocked send would also be considerably more
      difficult.  So, even though this solution (<a
	href="http://en.wikipedia.org/wiki/Flow_control"><em>flow
	  control</em></a>) is arguably better, we were reluctant to impose
      it.</p>

    <h4>The future: JMX Event Service</h4>

    <p>As I mentioned, in version 2.0 of the JMX API we are designing
      a new Event Service.  This will be part of the JDK 7 platform.
      Though it will not eliminate notification loss, it will
      significantly reduce the likelihood of such loss.  And it will
      also allow you to plug in your own transport for notifications.
      In particular you could plug in the <a
	href="http://java.sun.com/jms">Java Message Service</a> to use an
      existing message bus.</p>

    <p>[Tags: <a href="http://java.sun.com/jmx" rel="tag">jmx</a>
      <a href="http://java.sun.com/jms" rel="tag">jms</a>.]]]>

</content>
</entry>
<entry>
<title>Combining Cascading with the Attach API</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/archive/2007/08/combining_casca.html" />
<modified>2007-08-01T11:09:30Z</modified>
<issued>2007-08-01T11:09:14Z</issued>
<id>tag:weblogs.java.net,2007:/blog/emcmanus/254.7954</id>
<created>2007-08-01T11:09:14Z</created>
<summary type="text/plain">The Attach API lets you discover and attach to the Java VMs
      running on your local machine.  JMX Cascading lets you federate
      several JMX agents together.  Can we combine the two?</summary>
<author>
<name>emcmanus</name>

<email>eamonn.mcmanus@sun.com</email>
</author>
<dc:subject>Community: JDK</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/emcmanus/">
<![CDATA[    <p>The <a
	href="http://java.sun.com/javase/6/docs/jdk/api/attach/spec/">Attach
	API</a> lets you discover and attach to the Java VMs running
      on your local machine.  JMX <a
	href="http://weblogs.java.net/blog/emcmanus/archive/2007/02/cascading_its_a_1.html">Cascading</a>
      lets you federate several JMX agents together.  Can we combine
      the two?</p>

    <p>This is a question we've had fairly often, and I was prompted
      to write about it after <a
	href="http://queens.db.toronto.edu/~nilesh/">Nilesh Bansal</a>
      posted a <a
	href="http://forum.java.sun.com/thread.jspa?forumID=537&threadID=5200621">question</a>
      to the JMX forum in the Sun Developer Network to which one
      possible answer is to combine Cascading with the Attach API.</p>

    <p>The solution I propose here assumes that you are running on JDK
      6.  If you are stuck on JDK 5, I have a few suggestions <a
	href="#jdk5">below</a>, but there is inevitably a loss of
      functionality.</p>

    <h4>The basic idea</h4>

    <p>The Attach API is what <a
	href="http://java.sun.com/developer/technicalArticles/J2SE/jconsole.html">JConsole</a>
      uses to list the local Java processes in its Connect dialog.  It
      is a nonstandard but supported API, which means it should be
      present on any JDK-derived VM that is at least version 6.</p>

    <p>Once you select a Java process to connect to, JConsole again
      uses the Attach API to find the address of the JMX agent within
      that process, so it can connect.  And, thanks to some <a
	href="http://blogs.sun.com/alanb/entry/late_binding_agents_and_fun">deep
	magic</a>, JConsole can use the Attach API to create a JMX
      agent within the process if it doesn't already have one.</p>

    <p>So if we grab the code out of JConsole that does all this,
      we can combine it with Cascading.  The picture below is my
      standard Cascading picture.  Here, we're going to create a
      Master Agent that you can use to see the MBeans in all of your
      local Java processes.  The Subagents in the picture are these
      local processes, and all of their MBeans are imported into the
      Master Agent.  So if you connect JConsole to the Master Agent,
      then you can also see what's going on in each of the Subagents.
      In other words, you can use one JConsole connection to see all
      of your Java processes on that machine.</p>

    <img src="http://weblogs.java.net/blog/emcmanus/archive/mirror.png"
      width="663" height="332"
      alt="MBeans from every JVM on a machine are imported into a Master Agent">
    <p>If you set up the Master Agent to be remotely connectable, then
      you can also see all of your processes from a JConsole running
      on another machine.  The easiest way to do this is with
      <code>-Dcom.sun.management.jmxremote.port</code> and <a
	href="http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html">related
	properties</a>.  You need to pay attention to security in this
      case, of course.  You probably don't want just anyone to be
      able to see and modify the MBeans of your processes.</p>

    <p>Here's what we'd like JConsole to look like when it connects to
      the Master Agent:</p>

    <img alt="JConsole attached to Master Agent shows MBeans from every JVM"
      src="http://weblogs.java.net/blog/emcmanus/archive/cascade-attach.png"
      width="755" height="616" />

    <p>In the picture, you can see cascaded MBeans from processes
      16872, 18213, and 29375.  Through the "Cascader" MBean, which
      I'll define below, you can see what command each process id
      corresponds to.  29375 is the command
      <code>com.sun.enterprise.server.PELaunch</code>, which is the
      Sun App Server.  I launched that because it has a non-trivial
      number of MBeans, as you can divine from the MBean domains on
      the left.</p>

    <p>The processes you see are your own processes.  In other words
      they are the ones that you are able to manipulate if you are
      logged in to the machine.  On Unix machines, this means they are
      processes that are running with the same user id as the Master
      Agent.  On Windows machines, it means processes that you have the
      necessary privileges to open and interact with.</p>

    <h4>The details</h4>

    <p>I'll use the Cascading implementation from <a
	href="https://opendmk.dev.java.net/">Open DMK</a>, the Open Source
      version of the <a
	href="http://java.sun.com/products/jdmk/index.jsp">Java
	Dynamic Management Kit</a> (Java DMK) product.  (When I wrote
      my earlier <a
	href="http://weblogs.java.net/blog/emcmanus/archive/2007/02/cascading_its_a_1.html">blog
	entry</a> about cascading, Open DMK hadn't yet been released.)</p>

    <p>So to try this out, you'll need to <a
	href="https://opendmk.dev.java.net/download/">download</a> the
      Open DMK binaries.  You'll need to compile and run with
      <code>OpenDMK-bin/lib/jdmkrt.jar</code> from the Binary Zip.
      The Binary Zip also includes API documentation if you want to
      see the details of the API I'm using.</p>

    <p>You'll also need to compile and run with <code>tools.jar</code>
      from the JDK to get the Attach API.  It's in the
      <code>lib</code> directory of your JDK 6 installation.</p>

    <p>The program creates a "Cascader" MBean, which has one operation
      and one attribute.  The <code>refresh</code> operation gets the
      current list of Java processes and sets up cascading to import
      from each one.  I don't attempt to detect when new processes are
      created, though it would be straightforward to call
      <code>refresh</code> periodically in a loop.  When a process
      exits, the Master Agent's connection to it will break, and
      Cascading will automatically remove the MBeans that were
      imported from that process.</p>

    <p>The <code>CascadeResults</code> attribute shows the result of
      attaching to each Java process - either an exception message, or
      a success message including the process's command-line
      parameters.  In the latter case you can use this to figure out
      what the process is.  That's how I knew that 29375 was the App
      Server, above.</p>

    <p>(A <a
	href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6176346">bug</a>
      in JConsole makes it hard to see the command-line when it is
      long.  If you let the mouse hover over the value, you can see a
      longer string.)</p>

    <p>Since the full code is fairly involved, here's a sketch of how
      I discover the Java processes and set up cascading for them.  It
      omits exception handling and the like.</p>

    <pre>
List&lt;VirtualMachineDescriptor> vmds = VirtualMachine.list();
for (VirtualMachineDescriptor vmd : vmds) {

    String id = vmd.id();
    // This is the id that we will prefix to MBean names.  In practice
    // it is a numeric process id, as we have seen.

    VirtualMachine vm = VirtualMachine.attach(vmd);

    Properties agentProps = vm.getAgentProperties();

    String connectorAddressProperty =
    	"com.sun.management.jmxremote.localConnectorAddress";
    if (!agentProps.containsKey(connectorAddressProperty)) {
    	// The above property will be present if the process was launched
    	// with -Dcom.sun.management.jmxremote or if this program or
    	// JConsole previously attached to it.  Otherwise we need to start
    	// the management agent within the process:

    	String javaHome = vm.getSystemProperties().getProperty("java.home");
    	String agent = javaHome + "/lib/management-agent.jar";

    	vm.loadAgent(agent, "com.sun.management.jmxremote");
    	// This has the same effect as running with -Dcom.sun.management.jmxremote

    	agentProps = vm.getAgentProperties();
    }

    String connectorAddress = agentProps.getProperty(connectorAddressProperty);
    JMXServiceURL url = new JMXServiceURL(connectorAddress);

    CascadingService cascade = ...;
    cascade.mount(url, connectOptions, objectNamePattern, id);

    vm.detach();
}
</pre>

    <p>The complete code is <a href="#code">below</a>.  You'll
      probably want to customize it, for example so it only cascades
      from certain of your processes rather than all of them.</p>

    <h4>Cascade loops</h4>

    <p>One detail I omitted from the sketch is that we have to be
      careful that the Master Agent doesn't try to import its own
      MBeans.  Say the Master Agent is process 12345.  It will show up
      in the list of Java processes from the Attach API, along with
      all the others.  If we handled it the same way as the others,
      then the MBean <code>java.lang:type=Runtime</code>, for example,
      would be imported as <code>12345/java.lang:type=Runtime</code>.
      Cascading detects when new MBeans are created, and imports them.
      So it would detect the new
      <code>12345/java.lang:type=Runtime</code> and import it as
      <code>12345/12345/java.lang:type=Runtime</code>.  And so on.</p>

    <p>The way I prevent this is by checking the
      <code>MBeanServerId</code> property of the <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/MBeanServerDelegate.html">MBean
	Server Delegate</a> in each subagent.  If it is the same as
      the <code>MBeanServerId</code> of the Master Agent, then we
      know that the supposed subagent is actually the Master Agent.</p>

    <p>A more efficient technique would be to compare the VM id
      against the RuntimeMXBean's <a
	href="http://java.sun.com/javase/6/docs/api/java/lang/management/RuntimeMXBean.html#getName()"><code>Name</code></a>
      attribute in the Master Agent.  But that would require making
      assumptions that go beyond what is strictly specified.</p>

    <h4 id="jdk5">Stuck on JDK 5?</h4>

    <p>If you're currently on JDK 5, the Attach API is one of the many
      goodies that may encourage you to migrate to JDK 6.  But what if
      you can't?</p>

    <p>In that case, I think your best bet is to look at the JConsole
      code from the <a
      href="http://javashoplm.sun.com/ECom/docs/Welcome.jsp?StoreId=5&PartDetailId=J2SDK-1.5.0-G-CS&TransactionId=try">JDK
      5 sources</a>, and try to do the same thing it does.  The
      relevant code is in the method getManagedVirtualMachines()
      within the class sun.tools.jconsole.ConnectDialog.  This
      solution is fragile, because nothing prevents an update of JDK 5
      from changing how this works and breaking your code.  But if
      you're prepared to live with that, this is a possible
      approach.</p>

    <p>Since JDK 5 doesn't have Attach On Demand, you will only be
      able to cascade processes that were explicitly run with the
      <code>-Dcom.sun.management.jmxremote</code> option.  I don't see
      any way around that.</p>

    <h4 id="code">The code</h4>

    <pre>
package net.mcmanus.eamonn.cascadelocalvms;

import com.sun.jdmk.remote.cascading.CascadingService;
import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.JMX;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerDelegate;
import javax.management.MBeanServerDelegateMBean;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

public class Cascade {
    private static final String localConnectorAddressProperty =
            "com.sun.management.jmxremote.localConnectorAddress";
    private static final Logger logger = Logger.getLogger(Cascade.class.getName());

    public static void main(String[] args) throws Exception {
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

        CascadingService cascade = new CascadingService(mbs);

        CascaderImpl cascader = new CascaderImpl(cascade);
        cascader.refresh();
        mbs.registerMBean(cascader, new ObjectName(":type=Cascader"));

        System.out.println("Ready");

        Thread.sleep(Long.MAX_VALUE);
        // If this thread exits then the app will exit, so don't let it.
    }

    public static interface CascaderMXBean {
        public void refresh();
        public SortedMap&lt;String, String> getCascadeResults();
        // key in map is VM id (typically a pid)
        // value is result of trying to cascade from that VM
    }

    public static class CascaderImpl implements CascaderMXBean {
        private final CascadingService cascade;
        private SortedMap&lt;String, String> cascadeResults;

        CascaderImpl(CascadingService cascade) {
            this.cascade = cascade;
        }

        public void refresh() {
            uncascadeJVMs(cascade);
            cascadeResults = cascadeJVMs(cascade);
        }

        public SortedMap&lt;String, String> getCascadeResults() {
            return cascadeResults;
        }
    }

    private static SortedMap&lt;String, String> cascadeJVMs(CascadingService cascade) {
        logger.fine("Cascading JVMs...");

        SortedMap&lt;String, String> results = new TreeMap&lt;String, String>();

        List&lt;VirtualMachineDescriptor> vmds = VirtualMachine.list();
        for (VirtualMachineDescriptor vmd : vmds) {
            logger.fine("Attaching to " + vmd);
            String id = vmd.id();
            VirtualMachine vm;
            try {
                vm = VirtualMachine.attach(vmd);
            } catch (Exception e) {
                logger.log(Level.FINE, "...exception attaching", e);
                results.put(id, "Exception attaching: " + e);
                continue;
            }

            // From this point on we must detach, so we need a 'finally' block
            try {
                Properties agentProps = vm.getAgentProperties();
                if (!agentProps.containsKey(localConnectorAddressProperty)) {
                    logger.fine("...loading management agent into JVM");
                    try {
                        loadManagementAgent(vm);
                    } catch (Exception e) {
                        logger.log(Level.FINE, "...exception loading agent", e);
                        results.put(id, "Exception loading agent: " + e);
                        continue;
                    }
                    agentProps = vm.getAgentProperties();
                }

                String addr = agentProps.getProperty(localConnectorAddressProperty);
                if (addr == null) {
                    logger.fine("...still don't have connector address??");
                    results.put(id, "No connector address even after loading agent");
                    continue;
                }

                JMXServiceURL url = new JMXServiceURL(addr);
                logger.finer("...connector address is " + url);

                if (isThisJVM(url, cascade.getTargetMBeanServer())) {
                    logger.fine("...is local JVM");
                    results.put(id, "Local JVM");
                    continue;
                }

                Map&lt;String, ?> connectOptions = null;
                ObjectName pattern = new ObjectName("*:*");
                String mountTo = id;

                try {
                    String mountId =
                            cascade.mount(url, connectOptions, pattern, mountTo);
                    logger.log(Level.FINE, "...mounted with id " + mountId);
                    results.put(id, "Success: " + vmd.displayName());
                } catch (Exception e) {
                    logger.log(Level.FINE, "...exception mounting JVM", e);
                    results.put(id, "Exception mounting JVM: " + e);
                }

            } catch (Exception e) {
                logger.log(Level.FINE, "...unexpected exception", e);
                results.put(id, "Unexpected exception: " + e);
            } finally {
                try {
                    vm.detach();
                } catch (IOException e) {
                    logger.log(Level.INFO, "Could not detach vm " + id, e);
                }
            }
        }

        return results;
    }

    private static void uncascadeJVMs(CascadingService cascade) {
        String[] ids = cascade.getMountPointIDs();
        for (String id : ids) {
            try {
                boolean unmounted = cascade.unmount(id);
                if (!unmounted)
                    logger.info("Was not mounted: " + id);
            } catch (IOException e) {
                logger.log(Level.FINE, "Exception unmounting " + id, e);
            }
        }
    }

    private static void loadManagementAgent(VirtualMachine vm)
    throws AgentLoadException, AgentInitializationException, IOException {
        String javaHome = vm.getSystemProperties().getProperty("java.home");
        String agent = javaHome + File.separator +
                "lib" + File.separator + "management-agent.jar";
        File f = new File(agent);
        if (!f.exists())
            throw new IOException("Management agent not found: " + agent);
        agent = f.getCanonicalPath();
        logger.fine("...load management agent from " + agent);
        vm.loadAgent(agent, "com.sun.management.jmxremote");
    }

    private static boolean isThisJVM(JMXServiceURL url, MBeanServer mbs) {
        try {
            JMXConnector jmxc = JMXConnectorFactory.connect(url);
            MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
            MBeanServerDelegateMBean myDelegate =
                JMX.newMBeanProxy(mbs, MBeanServerDelegate.DELEGATE_NAME,
                    MBeanServerDelegateMBean.class);
            MBeanServerDelegateMBean remoteDelegate =
                JMX.newMBeanProxy(mbsc, MBeanServerDelegate.DELEGATE_NAME,
                    MBeanServerDelegateMBean.class);
            boolean same = myDelegate.getMBeanServerId().equals(
                    remoteDelegate.getMBeanServerId());
            jmxc.close();
            return same;
        } catch (Exception e) {
            logger.log(Level.FINE, "Cannot determine if same JVM", e);
            return true;  // if it really IS the same JVM, then we might
                          // get an infinite cascading loop
        }
    }
}
// END OF CODE
</pre>

    <p>[Tags: <a href="http://java.sun.com/jmx" rel="tag">jmx</a>,
      <a href="http://java.sun.com/products/jdmk" rel="jdmk">jdmk</a>,
      <a href="http://technorati.com/tag/opendmk" rel="tag">opendmk</a>.]</p>]]>

</content>
</entry>
<entry>
<title>Comparing objects that might be arrays</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/archive/2007/07/comparing_objec.html" />
<modified>2007-07-20T15:50:54Z</modified>
<issued>2007-07-20T15:50:00Z</issued>
<id>tag:weblogs.java.net,2007:/blog/emcmanus/254.7891</id>
<created>2007-07-20T15:50:00Z</created>
<summary type="text/plain">I was using this Java idiom today, not for the first time, and thought I&apos;d blog it for people not aware of it.  You probably know that if you compare two objects x and y using x.equals(y), the result will be false if they are distinct arrays, even if their contents are the same.  There is an easy way to get the right result for arrays.</summary>
<author>
<name>emcmanus</name>

<email>eamonn.mcmanus@sun.com</email>
</author>
<dc:subject>Programming</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/emcmanus/">
<![CDATA[<p>I was using this Java idiom today, not for the first time, and thought I'd blog it for people not aware of it.  You probably know that if you compare two objects x and y using <code>x.equals(y)</code>, the result will be false if they are distinct arrays, even if their contents are the same.  There is an easy way to get the right result for arrays.  It is<br>
<code>Arrays.deepEquals(new Object[] {x}, new Object[] {y})</code>.  This works if x and y are plain objects, or null, or primitive arrays, or reference arrays.  The only case where you might like it to work but it doesn't is for collections containing arrays, for example <code>Set&lt;int[]&gt;</code>.</p>

<p>Of course the idiom is a bit clunky and it's worth considering whether a new method<br>
<code>Something.deepEquals(Object x, Object y)</code> might not be a useful addition.  But where might it go?  <code>Arrays</code>?</p>]]>

</content>
</entry>
<entry>
<title>&quot;Top threads&quot; plugin for JConsole</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/archive/2007/06/top_threads_plu.html" />
<modified>2007-06-21T16:15:00Z</modified>
<issued>2007-06-21T16:14:49Z</issued>
<id>tag:weblogs.java.net,2007:/blog/emcmanus/254.7703</id>
<created>2007-06-21T16:14:49Z</created>
<summary type="text/plain">Peter Doornbosch has created a much improved version of the JTop sample plugin for JConsole.</summary>
<author>
<name>emcmanus</name>

<email>eamonn.mcmanus@sun.com</email>
</author>
<dc:subject>Community: JDK</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/emcmanus/">
<![CDATA[<p>Peter Doornbosch has created a <a href="http://blog.luminis.nl/luminis/entry/top_threads_plugin_for_jconsole">much improved version</a> of the <a href="http://weblogs.java.net/blog/mandychung/archive/2006/05/mustang_jconsol_1.html">JTop sample plugin</a> for JConsole.  JTop only shows thread name, cumulative CPU time, and thread state.  The "top threads" plugin also shows, per thread, current CPU percentage, average CPU percentage, and the evolution of CPU percentage over time.  Very nice!</p>

<p>There does seem to be a bug whereby the TextArea that shows the stack trace of the selected thread is editable.  Furthermore this TextArea is "always on top" so it can obscure part of the "new connection" dialogue.  I found that I could shrink the TextArea down to nothing by grabbing the control at its top, so this problem isn't very severe.</p>

<p>Thanks to <a href="http://blogs.sun.com/jmxetc/">Daniel Fuchs</a> for the pointer.</p>

<p>[Tags: <a href="http://java.sun.com/jmx" rel="tag">jmx</a> <a href="http://technorati.com/tag/jconsole">jconsole</a> <a href="http://technorati.com/tag/jtop">jtop</a>.]</p>]]>

</content>
</entry>
<entry>
<title>Disassembling serialized Java objects</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/archive/2007/06/disassembling_s.html" />
<modified>2007-06-12T15:12:20Z</modified>
<issued>2007-06-12T14:51:03Z</issued>
<id>tag:weblogs.java.net,2007:/blog/emcmanus/254.7612</id>
<created>2007-06-12T14:51:03Z</created>
<summary type="text/plain">Presenting Serialysis, a library that allows you to disassemble
      the serial form of Java objects.  This can allow you to retrieve
      information about an object that is not available through its
      public API.  It is also a useful tool when testing the
      serialization of your classes.</summary>
<author>
<name>emcmanus</name>

<email>eamonn.mcmanus@sun.com</email>
</author>
<dc:subject>Community: JDK</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/emcmanus/">
<![CDATA[    <p>Presenting Serialysis, a library that allows you to disassemble
      the serial form of Java objects.  This can allow you to retrieve
      information about an object that is not available through its
      public API.  It is also a useful tool when testing the
      serialization of your classes.</p>

    <h4>When the public API is not enough</h4>

    <p>My reason for writing this library is that I encountered a
      couple of problems where I found that I needed information from
      an object that was not available through its public API, but
      that <em>was</em> available through its serial form.</p>

    <p>One example is if you have a stub for a remote RMI object, and
      you want to know what address it will connect to, or what port, or
      using what <a
	href="http://java.sun.com/javase/6/docs/api/java/rmi/server/RMIClientSocketFactory.html">socket
	factory</a>.  The standard RMI API doesn't give you any way to
      extract this information from the stub.  But the information is
      there, and it must be included when the stub is serialized so
      that the stub is usable when it is later deserialized.  So if we
      could somehow parse the serialized stub we could get the
      information we want.</p>

    <p>A second example comes from the <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/package-frame.html">JMX
	API</a>.  Queries to the MBean Server are represented by the
      interface <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/QueryExp.html">QueryExp</a>.
	QueryExp instances are constructed using the methods of the <a
	href="http://java.sun.com/javase/6/docs/api/javax/management/Query.html">Query</a>
      class.  If you have an object implementing QueryExp, how can you
      know what query it executes?  The JMX API doesn't include any
      method to find out.  The information must be present in the
      serial form, so that when a client sends a query to a remote
      server it can be reconstituted on the server.  If we could look
      at the serial form, we could find out what the query was.</p>

    <p>This second example is what prompted me to write this library.
      The existing standard JMX connectors are based on Java
      serialization, so they don't need to do anything special for
      QueryExps.  But the new <a
	href="https://ws-jmx-connector.dev.java.net/">Web Services
	Connector</a> being defined by <a
	href="http://jcp.org/en/jsr/detail?id=262">JSR 262</a> uses XML
      for serialization.  How can it analyze a QueryExp in order to
      convert it into XML?  The answer is that the WS Connector uses a
      version of this library to look at the Java-serialized
      QueryExp.</p>

    <p>What these examples have in common is that they illustrate gaps
      in the relevant APIs.  There <em>ought</em> to be methods that
      allow you to extract the information contained in an RMI stub.
      There <em>ought</em> to be methods that convert back from a
      QueryExp object to the original Query methods that constructed
      it.  (Even a standardized parseable toString() would be enough.)
      But those methods aren't there today, and if we want code that
      works with those APIs as they are now, we need another
      approach.</p>

    <h4>Grabbing the private fields of objects</h4>

    <p>If you have the source code of the classes you're interested
      in, it's tempting just to barrel in and grab the information you
      need.  In the RMI stub example, we can find out by experiment that
      the stub's <a
	href="http://java.sun.com/javase/6/docs/api/java/rmi/server/RemoteObject.html#getRef()">getRef()</a>
      method returns a <code>sun.rmi.server.UnicastRef</code>, and by
      studying the JDK source we might be able to figure out that this
      class contains a field <code>ref</code> of type
      <code>sun.rmi.transport.LiveRef</code> with the information we
      need.  So we might end up with code like this:</p>

    <pre>
// <b>This is NOT a good idea!!!</b>

<b>import sun.rmi.server.*;
import sun.rmi.transport.*;</b>
import java.rmi.*;
import java.rmi.server.*;

public class StubDigger {
    public static getPort(RemoteStub stub) throws Exception {
        RemoteRef ref = stub.getRef();
    	<b>UnicastRef uref = (UnicastRef) ref;
    	Field refField = UnicastRef.class.getDeclaredField("ref");
    	refField.setAccessible(true);
    	LiveRef lref = (LiveRef) refField.get(uref);</b>
    	return lref.getPort();
    }
}
</pre>

    <p>You might be satisfied with this, but you shouldn't be.  The
      code in bold is full of horrors.  First of all, you should
      <em>never</em> depend on <code>sun.*</code> classes, because
      there's no guarantee they won't change unrecognizably in any JDK
      update, plus of course your code probably won't be portable to
      platforms other than the JDK.  Secondly, it's a huge red flag
      when you see <a
      href="http://java.sun.com/javase/6/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible(java.lang.reflect.AccessibleObject{},%20boolean)">Field.setAccessible</a>
      being called.  That means the code is depending on undocumented
      fields, which again could change between releases, or, worse,
      which might continue to exist but with subtly different
      semantics.</p>

    <p>(The above code was written for JDK 5.  It turns out that in
      JDK 6, LiveRef acquires a public getPort() method, so you no
      longer need Field.setAccessible.  But you still need to depend
      on <code>sun.*</code> classes.)</p>

    <p>Well, sometimes you can't do any better than this.  But if the
      class you're interested in is serializable, often you can.  The
      reason is that the serial form of a class is part of its public
      interface.  If the API is any good at all then its public
      interfaces will evolve compatibly in every update.  This is a
      very strong requirement on the JDK platform in particular.</p>
    
    <p>So if the information you need isn't available through a
      class's public methods, but <em>is</em> part of the documented
      serial form, then you can rely on it remaining in the serial
      form in the future.</p>

    <p>The serial form is included in the Javadoc output as part of
      the <b>See Also</b> for each serializable class.  You can see
      the serial form of all public JDK classes in <a
	href="http://java.sun.com/javase/6/docs/api/serialized-form.html">a
	single giant page</a>.</p>

    <h4>Enter Serialysis</h4>

    <p>My library to parse serialized objects is called
      <em>Serialysis</em>, the result of cramming the words "serial
      analysis" too close together.</p>

    <p>Here's a simple example of what it looks like in action.  This
      code...</p>

    <pre>
    	SEntity sint = SerialScan.examine(new Integer(5));
	System.out.println(sint);
</pre>

    <p>...produces this output...</p>

    <pre>
SObject(java.lang.Integer){
  value = Prim(int){5}
}
</pre>

    <p>This tells us that the <code>java.lang.Integer</code> that we
      gave to <code>SerialScan.examine</code> serializes as an object
      with a single field <code>value</code> of type <code>int</code>.
      If we check out the <a
      href="http://java.sun.com/javase/6/docs/api/serialized-form.html#java.lang.Integer">documented
      serialized form of <code>java.lang.Integer</code></a> we can see
      that this is indeed what is expected.</p>

    <p>If you check out the source code of
      <code>java.lang.Integer</code>, you'll see that the class itself
      also has a single field <code>value</code> of type
      <code>int</code>:</p>

    <pre>
    /**
     * The value of the &lt;code>Integer&lt;/code>.
     *
     * @serial
     */
    private final int value;
</pre>

    <p>But private fields are an implementation detail.  An update
      could rename this field, or replace it with a new field
      inherited from the parent class <a
	href="http://java.sun.com/javase/6/docs/api/java/lang/Number.html"><code>java.lang.Number</code></a>,
      or whatever.  There's no guarantee that that won't happen, but
      there <em>is</em> a guarantee that the serial form will remain
      the same.  Serialization provides <a
	href="http://java.sun.com/javase/6/docs/platform/serialization/spec/serial-arch.html#6250">mechanisms</a>
      to keep the serial form the same even when the class's fields
      change.</p>

    <p>Here's a more complicated example.  Suppose that, for some
      reason, we want to know how big the array in an <a
	href="http://java.sun.com/javase/6/docs/api/java/util/ArrayList.html">ArrayList</a>
      is.  The API doesn't allow us to find out, though it does allow
      us to <a
	href="http://java.sun.com/javase/6/docs/api/java/util/ArrayList.html#ensureCapacity(int)">force</a>
      the array to be at least a certain size.</p>

    <p>If we check the <a
	href="http://java.sun.com/javase/6/docs/api/serialized-form.html#java.util.ArrayList">serial
	form of ArrayList</a>, we see that it does contain the information
      we're looking for.  There's a serialized field
      <code>size</code>, which is the number of elements in the list.
      That's not what we want.  But the <b>Serial Data</b> in the
      <code>writeObject</code> method does have what we want:</p>

    <blockquote>
      <dd><dl>
	  <dt><b>Serial Data:</b></dt>
	  <dd>The length of the array backing the
	    <code>ArrayList</code> instance is emitted (int), followed
	    by all of its elements (each an <code>Object</code>) in
	    the proper order.</dd>
	</dl></dd>
    </blockquote>

    <p>If we execute this code...</p>

    <pre>
	List&lt;Integer> list = new ArrayList&lt;Integer>();
	list.add(5);
	SObject slist = (SObject) SerialScan.examine(list);
	System.out.println(slist);
</pre>

    <p>...we get this output...</p>

    <pre>
SObject(java.util.ArrayList){
  size = SPrim(int){1}
  -- data written by class's writeObject:
  SBlockData(blockdata){4 bytes of binary data}
  SObject(java.lang.Integer){
    value = SPrim(int){5}
  }
}</pre>

    <p>This is where we get into the gory details of serialization.
      In addition to, or instead of, serializing an object's fields, its
      class can declare a method
      <code>writeObject(ObjectOutputStream)</code> that writes arbitrary
      data to the serial stream using methods like <a
	href="http://java.sun.com/javase/6/docs/api/java/io/ObjectOutputStream.html#writeInt(int)">ObjectOutputStream.writeInt</a>.
      It must declare a corresponding <code>readObject</code> that reads
      the same data, and it should document via a <a
	href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/solaris/javadoc.html#@serialData">@serialData</a>
      tag what the <code>writeObject</code> method writes, as
      ArrayList does.</p>

    <p>The <code>writeObject</code> data is accessible in Serialysis
      through the method <code>SObject.getAnnotations()</code>, which
      returns a <code>List&lt;SEntity&gt;</code>.  Each Object that
      was written via the method <a
	href="http://java.sun.com/javase/6/docs/api/java/io/ObjectOutputStream.html#writeObject(java.lang.Object)">ObjectOutputStream.writeObject(Object)</a>
      appears as an <code>SObject</code> in this list.  Each chunk of
      data written by one or more consecutive calls to the methods
      that ObjectOutputStream gets from <a
	href="http://java.sun.com/javase/6/docs/api/java/io/DataOutput.html">DataOutput</a>
      (<a
	href="http://java.sun.com/javase/6/docs/api/java/io/ObjectOutputStream.html#writeInt(int)">writeInt</a>,
      <a
	href="http://java.sun.com/javase/6/docs/api/java/io/ObjectOutputStream.html#writeUTF(java.lang.String)">writeUTF</a>,
      etc) appears as an <code>SBlockData</code>.  The serial stream
      doesn't include enough information to separate out individual
      items within the chunk; that information is an agreement between
      writer and reader that is documented by the
      <code>@serialData</code> tag.</p>

    <p>Based on the ArrayList documentation, we can find the size of
      the array like this:</p>

    <pre>
	SObject slist = (SObject) SerialScan.examine(list);
	List&lt;SEntity> writeObjectData = slist.getAnnotations();
	SBlockData data = (SBlockData) writeObjectData.get(0);
	DataInputStream din = data.getDataInputStream();
	int alen = din.readInt();
	System.out.println("Array length: " + alen);
</pre>


    <h4>How Serialysis solves my example problems</h4>

    <p>Without showing all the details of the code, here's the outline
      of the solution to the <b>QueryExp problem</b> I mentioned.
      Suppose I have a QueryExp constructed like this:</p>

    <pre>
QueryExp query =
    Query.or(Query.gt(Query.attr("Version"), Query.value(5)),
	     Query.eq(Query.attr("SupportsSpume"), Query.value(true)));
</pre>

    <p>This means, "MBeans where the <code>Version</code> attribute is
      greater than 5 or the <code>SupportsSpume</code> attribute is
      true.  The toString() of this query in the JDK looks like
      this:</p>

    <pre>
((Version) &gt; (5)) or ((SupportsSpume) = (true))
</pre>

    <p>The result of SerialScan.examine looks like this:</p>

    <pre>
SObject(javax.management.OrQueryExp){
  exp1 = SObject(javax.management.BinaryRelQueryExp){
    relOp = SPrim(int){0}
    exp1 = SObject(javax.management.AttributeValueExp){
      attr = SString(String){"version"}
    }
    exp2 = SObject(javax.management.NumericValueExp){
      val = SObject(java.lang.Long){
        value = SPrim(long){5}
      }
    }
  }
  exp2 = SObject(javax.management.BinaryRelQueryExp){
    relOp = SPrim(int){4}
    exp1 = SObject(javax.management.AttributeValueExp){
      attr = SString(String){"supportsSpume"}
    }
    exp2 = SObject(javax.management.BooleanValueExp){
      val = SPrim(boolean){true}
    }
  }
}
</pre>

    <p>You can imagine code that descends into this structure
      producing an XML equivalent.  Every conformant implementation of
      the JMX API is required to produce this same serial form, so the
      code that parses it is guaranteed to work everywhere.</p>

    <p>Now here's the code that solves the <b>RMI stub port number
	problem</b>:</p>

    <pre>
    public static int getPort(RemoteStub stub) throws IOException {
	SObject sstub = (SObject) SerialScan.examine(stub);
	List&lt;SEntity> writeObjectData = sstub.getAnnotations();
	SBlockData sdata = (SBlockData) writeObjectData.get(0);
	DataInputStream din = sdata.getDataInputStream();
	String type = din.readUTF();
	if (type.equals("UnicastRef"))
	    return getPortUnicastRef(din);
	else if (type.equals("UnicastRef2"))
	    return getPortUnicastRef2(din);
	else
	    throw new IOException("Can't handle ref type " + type);
    }

    private static int getPortUnicastRef(DataInputStream din) throws IOException {
	String host = din.readUTF();
	return din.readInt();
    }

    private static int getPortUnicastRef2(DataInputStream din) throws IOException {
	byte hasCSF = din.readByte();
	String host = din.readUTF();
	return din.readInt();
    }
</pre>

    <p>To understand this, you need to see the <a
	href="http://java.sun.com/javase/6/docs/api/serialized-form.html#java.rmi.server.RemoteObject">serial
	form for <code>RemoteObject</code></a>.  This code is
      admittedly difficult, but it is portable and futureproof.  It
      should be fairly clear how to extract the other information I
      mentioned from RMI stubs using the same approach.</p>

    <h4>Conclusions</h4>

    <p>You really don't want to get into disassembling serial forms
      unless you have to.  But if you <em>do</em> have to, then
      Serialysis should make your task a little less painful.</p>

    <p>It's also a good way to check that your own classes serialize
      the way you expect them to.</p>

    <h4>Download</h4>

    <p>You can download the Serialysis library at <a
	href="http://weblogs.java.net/blog/emcmanus/serialysis.zip">http://weblogs.java.net/blog/emcmanus/serialysis.zip</a>.</p>


    <p>[Tags: <a href="http://java.sun.com/jmx" rel="tag">jmx</a>,
      <a href="http://java.sun.com/rmi" rel="tag">rmi</a>,
      <a href="http://technorati.com/tag/serialization" rel="tag">
	serialization</a>.]</p>]]>

</content>
</entry>
<entry>
<title>Custom types for MXBeans</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/emcmanus/archive/2007/05/custom_types_fo.html" />
<modified>2007-05-30T15:00:24Z</modified>
<issued>2007-05-30T15:00:14Z</issued>
<id>tag:weblogs.java.net,2007:/blog/emcmanus/254.7518</id>
<created>2007-05-30T15:00:14Z</created>
<summary type="text/plain">MXBeans map between arbitrary Java types and a fixed set of
      types in javax.management.openmbean called the Open Types.  Up
      until now the mapping rules were fixed.  In the Java 7 platform,
      we&apos;re planning to allow customization of the rules.</summary>
<author>
<name>emcmanus</name>

<email>eamonn.mcmanus@sun.com</email>
</author>
<dc:subject>Community: JDK</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/emcmanus/">
<![CDATA[    <p><a
	href="http://java.sun.com/developer/technicalArticles/J2SE/mxbeans/">MXBeans</a>
      map between arbitrary Java types and a fixed set of types in <a
      href="http://java.sun.com/javase/6/docs/api/javax/management/openmbean/package-summary.html">javax.management.openmbean</a>
      called the Open Types.  This allows clients to interact with
      MXBeans, without needing to know the original Java types (which
      might require putting extra jars in their classpath and so
      on).</p>

    <p>Up until now the mapping rules were fixed.  Certain types can
      not be mapped by these rules, for example self-referential types
      or types such as Object or Number.  In the Java 7 platform,
      we're planning to allow customization of the rules, as part of
      <a href="http://jcp.org/en/jsr/detail?id=255">JSR 255</a> which
      is defining version 2.0 of the JMX API.  This is a summary of
      the proposed changes.</p>

    <h4>What problem are we solving?</h4>

    <p>There are three sorts of use cases here:</p>

    <ol>
      <li id="usecase1">You have some types that you control and that
	are used in your MXBean interfaces. For example, <a
	  href="http://java.sun.com/javase/6/docs/api/java/lang/management/MemoryUsage.html">java.lang.management.MemoryUsage</a>
	which is referenced by <a
	  href="http://java.sun.com/javase/6/docs/api/java/lang/management/MemoryMXBean.html">java.lang.management.MemoryMXBean</a>. An
	update to java.lang.management could update MemoryUsage, for
	example to add an annotation to it.</li>

      <li id="usecase2">You have some types that you do not control
	that are used in MXBean interfaces that you do control. For
	example, you are an end-user and you define an MXBean
	interface MyMemoryMXBean that references
	java.lang.management.MemoryUsage. You can't change MemoryUsage
	but you can change MyMemoryMXBean.</li>

      <li id="usecase3">You have some types that you do not control
	that are used in MXBean interfaces that you do not control
	either. For example, you want to define an MXBean-ified
	version of some legacy MBeans defined by somebody else.</li>
    </ol>

    <p>The proposal is to add one class, one interface, and two
      annotations to address these cases. The existing class
      javax.management.StandardMBean acquires two new constructors and
      the existing class javax.management.JMX acquires two new
      overloads of existing methods.</p>


    <h4>MXBeanMapping and @MXBeanMappingClass</h4>

    <p>The most important change is the new class
      javax.management.openmbean.MXBeanMapping:</p>

    <p id="MXBeanMapping">public abstract class <b>MXBeanMapping</b> {<br>
&nbsp;&nbsp;&nbsp; protected <b>MXBeanMapping</b>(<a href="http://java.sun.com/javase/6/docs/api/java/lang/reflect/Type.html">Type</a> javaType, <a href="http://java.sun.com/javase/6/docs/api/javax/management/openmbean/OpenType.html">OpenType</a>&lt;?&gt;
openType);<br>
&nbsp;&nbsp;&nbsp; public final Type <b>getJavaType</b>();<br>
&nbsp;&nbsp;&nbsp; public final OpenType&lt;?&gt; <b>getOpenType</b>();<br>
&nbsp;&nbsp;&nbsp; public final Class&lt;?&gt; <b>getOpenClass</b>();<br>

&nbsp;&nbsp;&nbsp; public abstract Object <b id="fromOpenValue">fromOpenValue</b>(Object openValue)
throws InvalidObjectException;<br>
&nbsp;&nbsp;&nbsp; public abstract Object <b id="toOpenValue">toOpenValue</b>(Object javaValue) throws
OpenDataException;<br>
&nbsp;&nbsp;&nbsp; public void <b>checkReconstructible</b>() throws
InvalidObjectException;<br>
}</p>

    <p>Suppose we want to define a mapping for the class MyLinkedList,
      which looks like this:</p>

    <p><p>public class <b>MyLinkedList</b> {<br>
&nbsp;&nbsp;&nbsp; public <b>MyLinkedList</b>(String name, MyLinkedList next) {...}<br>
&nbsp;&nbsp;&nbsp; public String <b>getName</b>() {...}<br>
&nbsp;&nbsp;&nbsp; public MyLinkedList <b>getNext</b>() {...}<br>
}</p>

    <p>This is not a valid type for MXBeans, because it contains a
      self-referential property "next" defined by the getNext()
      method. (This example comes from <a
      href="http://bordet.blogspot.com/">Simone Bordet</a>.) So we
      would like to specify a mapping for it explicitly. When an
      MXBean interface contains MyLinkedList, that will be mapped into
      a String[], which is a valid Open Type.</p>

    <p>To define this mapping, we first subclass MXBeanMapping:</p>

    <p>public class <b>MyLinkedListMapping</b> extends MXBeanMapping {<br>

&nbsp;&nbsp;&nbsp; public <b>MyLinkedListMapping</b>(Type type) throws
OpenDataException {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super(MyLinkedList.class,
ArrayType.getArrayType(SimpleType.STRING));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (type != MyLinkedList.class)<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new OpenDataException("Mapping only valid for
MyLinkedList");<br>
&nbsp;&nbsp;&nbsp; }<br>
</p>

<p>&nbsp;&nbsp;&nbsp; @Override<br>
&nbsp;&nbsp;&nbsp; public Object <b>fromOpenValue</b>(Object openValue) throws
InvalidObjectException {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String[] array = (String[]) openValue;<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MyLinkedList list = null;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = array.length - 1; i &gt;= 0; i--)<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list = new MyLinkedList(array[i], list);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return list;<br>

&nbsp;&nbsp;&nbsp; }<br>
</p>
<p>&nbsp;&nbsp;&nbsp; @Override<br>
&nbsp;&nbsp;&nbsp; public Object <b>toOpenValue</b>(Object javaValue) throws
OpenDataException {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ArrayList&lt;String&gt; array = new ArrayList&lt;String&gt;();<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (MyLinkedList list = (MyLinkedList) javaValue; list !=
null; list = list.getNext())<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; array.add(list.getName());<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return array.toArray(new String[0]);<br>
&nbsp;&nbsp;&nbsp; }<br>
}</p>

    <p>The call to the superclass constructor specifies what the
      original Java type is (MyLinkedList.class) and what Open Type it
      is mapped to (<a
      href="http://java.sun.com/javase/6/docs/api/javax/management/openmbean/ArrayType.html#getArrayType(javax.management.openmbean.OpenType)">ArrayType.getArrayType</a>(SimpleType.STRING)). The
      fromOpenValue method says how we go from the Java type to the
      Open Type, and the toOpenValue method says how we go from the
      Open Type to the Java type.</p>

    <p id="MXBeanMappingClass">With this mapping defined, we can
      annotate MyLinkedList with the new annotation
      @javax.management.openmbean.MXBeanMappingClass:</p>

    <p>@<b>MXBeanMappingClass</b>(MyLinkedListMapping.class)<br>
public class <b>MyLinkedList</b> {...}</p>

    <p>Now we can use MyLinkedList in an MXBean interface and it will
      work. This satisfies <a href="#usecase1">use case 1</a>
      above.</p>

    <h4>MXBeanMappingFactory and @MXBeanMappingFactoryClass</h4>

    <p>If we are unable to annotate individual classes, then we can define
      a <em>mapping factory</em> that is consulted every time a type
      needs to be mapped. This is also useful if we would like to
      apply the same set of rules across a whole set of classes (for
      example, any class that implements <a
	href="http://java.sun.com/javase/6/docs/api/java/util/List.html">List&lt;E&gt;</a>
      is mapped in the same way as List&lt;E&gt;).</p>

    <p>A mapping factory is a subclass of
      javax.management.openmbean.MXBeanMappingFactory:</p>

    <p id="MXBeanMF">public abstract class <b>MXBeanMappingFactory</b> {<br>
&nbsp;&nbsp;&nbsp; public static final MXBeanMappingFactory <b>DEFAULT</b>;<br>
&nbsp;&nbsp;&nbsp; protected <b>MXBeanMappingFactory</b>();<br>
&nbsp;&nbsp;&nbsp; public abstract MXBeanMapping <b>mappingForType</b>(Type t, MXBeanMappingFactory f)<br>
&nbsp;&nbsp;&nbsp; throws OpenDataException;<br>
      }</p>

    <p>For example, suppose we can't change MyLinkedList, so we can't
      add the @MXBeanMappingClass annotation to it. We can achieve the
      same effect by defining a mapping factory as follows:</p>

<p id="MyLinkedListMF">public class <b>MyLinkedListMappingFactory</b> extends
MXBeanMappingFactory {<br>
&nbsp;&nbsp;&nbsp; public <b>MyLinkedListMappingFactory</b>() {}<br>
<br>
&nbsp;&nbsp;&nbsp; @Override<br>
&nbsp;&nbsp;&nbsp; public MXBeanMapping <b>mappingForType</b>(Type t,
MXBeanMappingFactory f)<br>
&nbsp;&nbsp;&nbsp; throws OpenDataException {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (t == MyLinkedList.class)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new MyLinkedListMapping(t);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return MXBeanMappingFactory.DEFAULT.mappingForType(t, f);<br>
&nbsp;&nbsp;&nbsp; }<br>