
=pod

=head1 NAME 

JMX::Jmx4Perl::Manual - Documentation for B<jmx4perl>

=head1 DESCRIPTION

JMX (Java Management Extensions) is the standard management solution in the
Java world. Since JDK 1.5 it is available in every Java Virtual Machine and
especially JEE application servers use this technology intensively for exposing
managable entities. In fact, the popular JEE Server JBoss 4 is based on a JMX
kernel.

For the Perl world, it's not that easy to access JMX MBeans. I<MBean> is the
Java term for JMX managed entities. The existing solutions are mostly based on
the Java standard JSR-160 (L<http://jcp.org/en/jsr/detail?id=160>), which
defines how JMX can be accessed remotely. The problem of JSR-160 with respect
to Perl is, that the default communication protocols rely on exchanging
serialized Java objects. Hence they require to start a Java Virtual Machine in
the one way or other. This has quite some implications concerning installation
requirements (you need a Java virtual machine with the proper version
installed) and performance (firing up a JVM is not something you get for free)

The ultimate goal of B<jmx4perl> is to bridge both worlds in the most simplest
way. This is done with the I<agent> and I<proxy> based approaches described
below. In short, the building blocks of this bridge are based on standards well
known and used in both worlds: HTTP and JSON.

Another goal is to provide an abstraction for accessing certain, commonly known
MBeans for various supported JEE application server, which differ in naming
from brand to brand. For now, the JEE servers supported are JBoss 4 & 5, Oracle
WebLogic 9 & 10, Websphere 6 & 7, Glassfish 2 & 3, Jonas 4 and Geronimo 2 as
well as the pure servlet containers Jetty 5 and 6, Tomcat 4, 5 & 6. Other
platforms might work as well, however they are not yet tested. Please let me
know, whether jmx4perl works for you on other servers as well (which is highly
likely due to the simplistic nature of the agent).  B<jmx4perl> is not an
academic exercise. In fact it originates from the need to let Nagios (a well
known open source monitoring solution, see L<http://www.nagios.org>) access JEE
appliation servers in a painless way. You can find a nagios check in the
scripts directory, which is a prefactored check directly usable for a Nagios
setup.

Additionally, there is a command line tool called (incidentally ;-) L<jmx4perl>
which allows for simple access to JMX MBeans and much more. 

=head1 MBean Features

JMX is a complex specification, which can not be completely revealed in this
short documentation. Refer to
L<http://java.sun.com/docs/books/tutorial/jmx/index.html> for an introduction
to JMX. But in short, one can distinguish three kinds of operational modes:

=over

=item Attribute reading and writing

An MBean can have one or more attributes, which can be read and/or
written. jmx4perl knows how to read and write MBean attributes.

=item Execution of operations

A MBean can expose certain operations, which can be executed via JMX
calls. With jmx4perl, JMX operations can be executed.

=item Notifications

Listeners can register to get notified for certain notifications by the
MBeans. This is not yet supported by jmx4perl and it is technically quite
challenging, since HTTP, our transport protocol, is a typical request-response
based protocol which is unidirectional by nature. However there are already
ideas how to overcome this limitation, but please don't hold your breath. This
is on the roadmap, but with very low priority only. Tell me your use case if
you want to push it up.

=back

=head1 AGENT BASED APPROACH

An agent based approach requires you to install a small Java Webapplication
within your JEE application server. It registers itself locally to the JMX
MBeanServer, and listens to HTTP requests whose results are translated into a
JSON representation. This reponse can be easily picked up by a Perl module,
L<JMX::Jmx4Perl> in our case. This kind of approach differs from the canonical
approach as suggested by the JMX specification itself. 

This approach works for the following environments:

=over 4

=item * 

JEE Servers where a webapplication in the standard WAR format can be deployed. 

=item *

For the Mule ESB as dedicated Mule agent can be used for exposing JMX to the
outside. 

=item *

Not actually ready, but definitively scheduled for the next release is
packaging as an OSGi bundle for operation in an OSGi environment (along with an
OSGi HttpService). Stay tuned ...

=back 

Beside this restriction concerning the runtime environment, this approach has
also quite some advantages:

=head2 Advantages

=over 4 

=item * 

No special startup options for the JEE server are required for exposing JMX
informations as it would be the case for exporting JMX via JSR-160 connectors. 

=item * 

No Java installation required on the client for using the agent

=item * 

No overhead with regard to startup times of a JVM

=item *

Since the agent is a standard Java Webapplication it can be secured by
standard JEE means like any other Webapplication. 

=item *

Firewall friendly since all HTTP communication goes over a single port. 

=back 

=head2 Disadvantages

=over 4

=item * 

The agent can be deployed only to certain Java runtime container (Servlet
container, Mule Agent, OSGi container). But please read on, even when your
runtime environment doesn't fit in here. With the I<proxy> approach arbitrary
Java applications can be connected to.

=back 

=head1 PROXY MODE

Although the I<agent based> is the most simplest way to access JMX, there are
circumstances which prevent the deployment of a dedicated agent servlet. This
kind of restrictions are mostly politically motivated. For these situations,
jmx4perl provides an operational mode known as the I<proxy mode> with which the
target platform can be monitored without installing the j4p agent servlet on
it. This works by using j4p.war as a JMX Proxy, which translates our
JSON/HTTP protocol on the frontside to JSR-160 JMX remote requests on the
backend and vice versa.

A dedicated proxy serlvet server is needed for hosting C<j4p.war>, which supports
the I<agent mode> as well as the I<proxy mode>. A lightweight container like
Tomcat or Jetty are a perfect choice for this mode. The setup is straight
forward: 

=over

=item * 

Install Jetty (L<http://www.mortbay.org/jetty/>) or Tomcat
(L<http://tomcat.apache.org/>) 

=item * 

Deploy C<j4p.war> from the jmx4perl distribution by copying it into the
F<webapp> directory.

=item * 

Enable remote JMX commonicutaion on the target plattform. Please consult the
documentation of your Appserver for further details.

=item * 

Use the C<--target> option for C<jmx4perl> or C<check_jmx4perl> with a JMX
service URL (like C<service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi>) in
order to specify the target server. Use the proxy server's URL as the agent
URL:

 jmx4perl http://localhost:8080/j4p  \
      --target service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi list


=back

Said all this, the proxy mode has some limitations:

=over 4

=item * 

There is no automatic merging of JMX MBeanServers as in the case of the direct
mode. Most application servers uses an own MBeanServer in addition to the
PlatformMBeanServer (which is always present). Each MBean is registered only in
one MBeanServer. The choice, which C<MBeanServer> to use has to be given
upfront, usually as a part of the JMX Service URL. But even then (as it is the
case for JBoss 5.1) you might run into problem when selecting the proper
MBeanServer.

=item * 

Proxying adds an additional remote layer which causes additional
problems. I.e. the complex operations like C<list> might fail in the proxy mode
because of serialization issues. E.g. for JBoss it happens that certain
MBeanInfo objects requested for the list operation are not serializable. This
is a bug of JBoss, but I expect similar limitations for other application
servers as well.

=item * 

Certain workarounds (like the JBoss I<"can not find MXBeans before MBeanInfo has
been fetched"> bug) works only in agent mode.

=item * 

It is astonishingly hard to set up an application server for JSR-160
export. And there are even cases (combinations of JDK and AppServer Version)
which don't work at all properly (e.g. JDK 1.5 and JBoss 5). For certain
application servers, detailed setup instructions are published at
http://labs.consol.de/tags/jsr-160/

=back

To summarize, the proxy mode should be used only when required. The agent
servlet on its own is more powerful than the proxy mode since it eliminates an
additional layer, which adds to the overall complexity and performance. Also,
minor additional features like merging of MBeanServers are not available in the
proxy mode.

=head1 INSTALLATION 

The Perl part installs as any other module via Module::Build, which
you need to have installed. Using

  perl Build.PL
  ./Build
  ./Build test
  ./Build install

will install the modules. If you have Java and "ant" (a Java build
tool) installed, the Java agent will be compiled and packaged as
well. However, this is not required. A precompiled F<j4p.war>
can be found in the F<agent> directory.

For the module to work, you need to deploy F<j4p.war> to the JEE Server
to monitor. The concrete steps depend on the specific way for deploying on the
target server, which in most cases is as simple as copying the agent into a
specific directory. Please consult the documentation of your Java application
server for the details (look for "deployment" and "web application" (or "war))) 

To test it, you can use L<jmx4perl> with the URL of the deployed
agent:

  jmx4perl http://<jeeserver>:<port>/j4p
      
Consult L<jmx4perl> for further details. 

=head2 Mule agent

The mule agent is not yet distributed as binary and not included in the default
build. You can easily build it on your by using C<mvn install> within the
F<agent/> subdirectory. You need maven (L<http://maven.apache.org>) as build
tool installed. The agent can be found afterwards at
F<agent/modules/j4p-mule/target/j4p-mule-0.50-agent.jar> (note the C<-agent>
classifier, replace the version number with the current jmx4perl version).

Alternatively, the mule agent can be downloaded from our maven repository at
L<http://labs.consol.de/maven/repository/org/jmx4perl/j4p-mule/> or you can use
C<./Build get_mule_agent> to download the current mule agent
automatically. (BTW, C<./Build get_war> downloads the current jmx4perl standard
agent from labs.consol.de repository).

The agent jar needs to be stored within the Mule installation in
F<lib/opt/>. Additionally, the Mule configuration needs to be adapted to
contain the following section:

 <management:custom-agent name="j4p-agent" class="org.jmx4perl.mule.J4pAgent">
   <spring:property name="port" value="8899"/>
 </management:custom-agent>
 <management:jmx-server/>

Starting up mule should yield a startup message like 

 *********************************************************
 * Mule ESB and Integration Platform                     *
 * Version: 2.2.1 Build: 14422                           *
 * MuleSource, Inc.                                      *
 * For more information go to http://mule.mulesource.org *
 *                                                       *
 * Server started: 12/9/09 3:36 PM                       *
 * Server ID: myMule                                     *
 * JDK: 1.6.0_15 (mixed mode)                            *
 * OS encoding: MacRoman, Mule encoding: UTF-8           *
 * OS: Mac OS X (10.6.2, x86_64)                         *
 * Host: localhost (127.0.0.1)                           * 
 *                                                       *
 * Agents Running:                                       *
 *   Wrapper Manager: Mule PID #0, Wrapper PID #861      *
 *   j4p Agent: http://localhost:8899/j4p                *
 *   JMX Agent                                           *
 *********************************************************

Note the URL for the j4p agent which can be used with C<jmx4perl> or
C<check_jmx4perl> like

 jmx4perl http://localhost:8899/j4p list

which will result in an output similar to

 Mule.myMule:
    Mule.myMule:name=AllStatistics,type=org.mule.Statistics
        Attributes:
            Enabled                             boolean
        Operations:
            void logSummary()                   
            java.lang.String printXmlSummary()  
            java.lang.String printHtmlSummary() 
            void clear()                        
            java.lang.String printCSVSummary()  
 
 ....
 java.lang:
    java.lang:type=Memory
        Attributes:
            NonHeapMemoryUsage                  CompositeData [ro] 
            ObjectPendingFinalizationCount      int [ro]
            Verbose                             boolean
            HeapMemoryUsage                     CompositeData [ro]
        Operations:
            void gc()

Note that Mule was started here with a server id myMule (startup option:
C<-M-Dmule.serverId=myMule>). As you can see you have access to the Mule specific
MBeans and the Java platform MXBeans (which BTW is not easy achievable using
Mules JSR-160 agents directly).

For enabling basic security the properties user and password can be set:

 <management:custom-agent name="j4p-agent" class="org.jmx4perl.mule.J4pAgent">
   <spring:property name="user" value="roland"/>
   <spring:property name="password" value="wtf"/>
 </management:custom-agent>
 <management:jmx-server/>

On the client side the options C<--user> and C<--password> can be used with
C<jmx4perl> and C<check_jmx4perl> for specifying the credentials.

Finally, all other options as specified as init parameters in C<j4p.war>s web.xml
can be used as properties here as well.

=head1 FEATURES

=head2 Reading and Writing Attributes

Jmx4Perl knows how to read any attribute and how to write to certain attributes
for whose types are string-to-object conversions are known. Currently, writing
of attributes of type String, int, long and boolean is supported. As a special
features, Jmx4Perl has the notion of an I<inner path> which is a XPath like
expression for pointing into the object returned by a read or write
operation. 

=head2 Execution of JMX operations

It is easy to execute JMX operations, even with arguments. However, they same
restrictions for the argument types apply as for writing attributes: There must
be an easy way to deserialize an argument from a string representation. The
same types as for writing attributes are supported.

=head2 Autodetection and Product Support

Jmx4Perl is able to autodectect various application servers. This is done by
querying a certain MBean attribute which is unique for this specific
product. The following application servers can be autodetected:

=over

=item * 

JBoss 4 and 5 (L<http://www.jboss.org/jbossas/>)

=item *

Oracle WebLogic 9 & 10 (L<http://www.oracle.com/appserver/>)

=item *

IBM Websphere 6 & 7 (L<http://www.ibm.com/websphere>)

=item *

Glassfish 2 and 3 (L<https://glassfish.dev.java.net/>)

=item *

Apache Geronimo 2 (L<http://geronimo.apache.org/>)

=item * 

Jonas 4 (L<http://jonas.ow2.org/>)

=item * 

Tomcat 4, 5 and 6 (L<http://tomcat.apache.org/>)

=item * 

Jetty 5 and 6 (http://www.mortbay.org/jetty/)

=back 

All these application servers has been tested to work with jmx4perl. The
testing environment is a 64bit Ubuntu 9.04 installation, running in a virtual
machine. However, this should not make any difference for another platform, so
I'm pretty confident that the application servers from the list above will work
with jmx4perl on any OS. Please open a bug at
L<http://rt.cpan.org/Public/Bug/Report.html?Queue=jmx4perl> if you encounter
any problems.

Please note, that autodetection is not for free with respect to performance. It
takes some considerable time to probe various servers. So, if you have the
chance to provide the application server type in advance, you should do
this. Said this, please note this is only relevant if you are going to use the
aliasing feature described below.

=head2 Aliasing

L<JMX::Jmx4Perl::Alias> provides a thin abstraction layer about over the JMX
naming scheme so that you can use a single alias value to access the
combination (MBean name,attribute) or (MBean name,operation). It also maps the
differing naming schemes of different application server to unique names, as
far as this is possible. E.g. the alias C<SERVER_VERSION> maps on JBoss to the
attribute C<VersionNumber> of MBean C<jboss.system:type=Server>, whereas for
Jetty it's mapped to MBean C<org.mortbay:jetty=default>, Attribute C<version>. 

Remember, you can always use the the native JMX naming to access your MBeans
without worrying about aliasing at all.  

=head2 History Tracking

The agent C<j4p> can be switched into a history tracking mode, where it records
the values for C<read>, C<write> and C<exec> operations. You have to call a
certain, jmx4perl specific, MBean to turn it on. If switched on each request
contains an additional history entry containing the list of historical values
along with their timestamps. The history is stored in a list with fixed length
so that the oldest value gets removed from the list in case of an overflow.

=head2 Full featured Nagios plugin C<check_jmx4perl> 

A full functional Nagios plugin called C<check_jmx4perl> is provided in the
scripts directory. It can be used to monitor any JMX Mbean's attribute with a
numeric value. Thresholds for warning and critical values can be provided in
the formats as defined by L<Nagios::Plugin>. You can use autodetection and
aliasing here as well. C<check_jmx4perl> can use relative critical and warning
thresholds which refer to some base value taken from another MBean's
attribute. An incremental mode can be used to measure the growth rate of
certain value (like number of threads). Finally, it can monitor the return
value of some JMX operations as well. Please refer to L<check_jmx4perl> for a
detailed documentation.

=head1 WHAT'S NEXT ?

There are several entry points for jmx4perl. The easiest is to start to play
around with L<jmx4perl>. This is a complete command lines for exploring the
MBeans on your JEE Server. 

If you want to use the Nagios Plugin L<check_jmx4perl> start reading its
documentation. A Nagios cookbook is on the roadmap. If you want to restrict
access to your JMX MBeanServer read the next chapter in this manual which
describes a way to build a custom agent containing a policy file.

Next, L<JMX::Jmx4Perl> is the entry module. Use this, if you need programmatical
access to JMX. Don't forget to have a look into the F<examples> directory which
contains some usage examples for L<JMX::Jmx4Perl>

Of course, you are free to access the agent servlet directly without the usage
of the provided module. Even in Java ;-) A description of the request and
response format can be found in the protocol description
L<JMX::Jmx4Perl::Agent::Protocol>.

Another resource is the jmx4perl Blog located at L<http://labs.consol.de>. It
contains various post about different jmx4perl use case and best practices.
Don't forget to add L<http://labs.consol.de/tags/jmx4perl/feed/rss/> to your
RSS Feedreader if you want to keep in touch with the latest jmx4perl evolution
(there is quite something in the pipeline).

=head1 ACCESS POLICY

The deployed agent servlet is quite mighty in the default distribution as you
can perform any operation exposed by a MBean via JMX. Of course, you should
secure the agent via standard mechanism (e.g via Basic Authentication) to allow
only access to certain users. But even then, you might not want your
monitoring guys to access the heart of the JEE Server. Therefore, you can
restrict access to certain MBeans only by using a so called I<policy> file. You
have to rebuild the agent if you want to use this feature, though. To do this,
here's the recipe:

=over

=item 1.

Change into the directory F<agent>. There you will find a template policy file
called F<j4p-access.xml.template>

=item 2. 

Copy this template to F<j4p-access.xml> (all within the agent directory). 

=item 3. 

Edit F<j4p-access.xml> to your needs. In the section C<commands> you can
restrict the request types, only those present here are allowed to be
called. If the complete C<commands> section is missing, no restriction on a
request type is in effect. In the C<mbeans> part you can provide MBeans by name
and the allowed attributes and operations. If this section is present, only the
MBeans listed can be accessed with the attributes and operations listed. Access
to an attribute can be restricted further by giving a C<mode="read"> attribute
to the C<attribute> tag in which case the attribute can be accessed
read-only. Via the C<remote> section access to certain IP adresses and subnets
can be restricted.

=item 4.

Call C<ant>. Ah, yes, you need C<ant> installed (L<http://ant.apache.org>). To
be on the save side do an C<ant clean> before calling C<ant> without argument.

=item 5.

Deploy the F<j4p.war> which was created in Step 4.   

=back

A typical workflow looks like

 $ cd agent/
 $ cp j4p-access.xml.template j4p-access.xml
 $ vi j4p-access.xml
 $ ant clean
 $ ant
 $ jar tvf j4p.war
      0 Thu Jul 30 10:42:24 CEST 2009 META-INF/
     95 Thu Jul 30 10:42:22 CEST 2009 META-INF/MANIFEST.MF
      0 Thu Jul 30 10:42:24 CEST 2009 WEB-INF/
   1872 Tue Jul 28 09:09:32 CEST 2009 WEB-INF/web.xml
      0 Thu Jul 30 10:42:24 CEST 2009 WEB-INF/lib/
  16046 Wed Jul 01 22:26:42 CEST 2009 WEB-INF/lib/json_simple-1.1.jar
  85124 Thu Jul 30 10:42:22 CEST 2009 WEB-INF/lib/j4p-agent.jar
      0 Thu Jul 30 10:42:24 CEST 2009 WEB-INF/classes/j4p-access.xml
 $ cp j4p.war $DEPLOYMENT_DIR/

=head1 LICENSE

Copyright (C) 2009 Roland Huss

Jmx4perl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

jmx4perl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with jmx4perl.  If not, see L<http://www.gnu.org/licenses/>.

A commercial license is available as well. You can either apply the GPL or
obtain a commercial license for closed source development. Please contact
roland@cpan.org for further information.

=head1 PROFESSIONAL SERVICES

Just in case you need professional support for jmx4perl (or Nagios or JMX in
general), you might want to have a look at
L<http://www.consol.com/opensource/nagios/>. Contact roland.huss@consol.de for
further information (or use the contact form at L<http://www.consol.com/contact/>)

=head1 AUTHOR

roland@cpan.org

=cut
