Table of Contents
JMX monitoring and management is built into Metro-based services and clients. Monitoring allows one to view the state of parts of Metro runtime system while it is in operation. Management allows one to change values dynamically. The rest of this document will refer to Metro monitoring and management as simply "monitoring".
Metro monitoring should not be confused with Metro's Web Service Configuration Management (Metro CM). Monitoring enables one to view the state of the Metro runtime, whereas Metro CM is for (re)configuring a web service.
Metro-based services have monitoring turned on by default.
Metro-based clients have monitoring turned off by default.
Clients are off by default because there is no standard way to
dispose of a client and release its resources. Metro does include a
proprietary method for disposing a proxy. Assuming you have an
AddNumbers
service:
Example 19.1.
AddNumbersPortType port = new AddNumbersService().getAddNumbersPort(); ... ((java.io.Closeable)port).close();
If you enable client monitoring it is recommended you
close
client proxies when they are no longer used.
Metro has two system properties for controlling monitoring scoped to the JVM:
Setting either to false
will disable all
monitoring for Metro-based endpoints (i.e., web services) or
clients, respectively, in a JVM.
Metro includes a policy assertion for enabling and disabling
monitoring for specific services and endpoints. For an endpoint
(using an AddNumbersService
as an example):
Example 19.3.
<service name="AddNumbersService"> <port name="AddNumbersPort" binding="tns:AddNumbersPortBinding"> <wsp:Policy> <sunman:ManagedService xmlns:sunman="http://java.sun.com/xml/ns/metro/management" management="false" monitoring="true"> </sunman:ManagedService> </wsp:Policy> ... </port> </service>
The ManagedService
assertion is placed inside
(or referenced from) the port
element in the
endpoint's WSDL (if creating a service from WSDL) or in the
endpoint's configuration file (if creating a service from
Java).
This assertion is used by both Metro CM and monitoring. See
Metro CM for the meaning and operation of the
management
attribute.
Metro monitoring is turned off for the specific endpoint if
the monitoring
attribute is set to
false
. If the policy assertion or the
monitoring
attribute is not present, or the
monitoring
attribute is set to true
then
monitoring is turned on for that endpoint (unless endpoint
monitoring is turned off for the JVM).
For a client the ManagedClient
assertion is
used:
Example 19.4.
<sunman:ManagedClient xmlns:sunman="http://java.sun.com/xml/ns/metro/management" management="false" monitoring="true" > </sunman:ManagedClient>
This is placed inside the
<service>/<port>
element of the
*.xml
file corresponding to the service referenced
from the src/java/META-INF/wsit-client.xml
configuration file. (Note: the example path to the
wsit-client.xml
file is where the file is located
when building using NetBeans.)
When the monitoring
attribute of
ManagedClient
is set to true
then
monitoring will be turned on for that specific client (unless the
client JVM property is set to false
).
Each endpoint is given a unique monitoring identifier (also call "root name"). That identifier is made up of (in order):
The context path (if it is available).
The local part of the service name.
The local part of the port name.
For example, suppose one creates a web application with
a context path of /AddNumbersService
and a Metro
web service is deployed under that context path with an
AddNumbersService
service name and a
AddNumbersPort
port name. Then the identifier
will be:
When deploying in GlassFish an INFO
log
message is output to GlassFish's server.log
file
when the monitoring root is created. In this example the
message would be:
Example 19.6.
Metro monitoring rootname successfully set to: amx:pp=/mon/server-mon[server],type=WSEndpoint,name=/AddNumbersService-AddNumbersService-AddNumbersPort
The name
part is the identifier. The
amx:pp=...
part reflects that this Metro endpoint
is federated under GlassFish's AMX tree. Note: when deploying
in non-GlassFish containers then Metro monitoring will be
under a top-level node: com.sun.metro
.
It is possible to give user-assigned identifiers to
monitoring endpoints. Include an id
attribute in
the ManagedService
policy assertion. For
example:
Example 19.7.
<sunman:ManagedService xmlns:sunman="http://java.sun.com/xml/ns/metro/management" management="false" monitoring="true" id="ExampleService" > </sunman:ManagedService>
In this case, the INFO
log will say:
Example 19.8.
Metro monitoring rootname successfully set to: amx:pp=/mon/server-mon[server],type=WSEndpoint,name=ExampleService
Each client stub is given a unique monitoring
identifier. That identifier is the endpoint address of the
service it will communicate with. For example, for a client of
the AddNumbersService
above the identifier, as
shown in GlassFish's log, will be:
Example 19.9.
Metro monitoring rootname successfully set to: amx:pp=/mon/server-mon[server],type=WSClient,name=http-//localhost-8080/AddNumbersService/AddNumbersService
(Note that ':' characters have been replaced with '-'. See below for more info.)
Some characters in a root name are converted to the '-' character. This is to avoid the need to quote characters that are not legal in JMX. The regular expression used to find and replace those characters is:
It is possible that two root names can be the same. This can happen when deploying web services with the same service name and port name under different context paths in non-GlassFish containers because the context path is not available to the naming mechanism when in other containers. This can also happen when two different proxies are communicating with the same service.
When root names clash, then the rootname has
-<N>
appended, where N
is a unique
integer.
To show what monitoring information is available we will use two tools:
Neither of these tools is officially supported by GlassFish nor Metro. However, they are useful for browsing the mbeans in a JVM.
The following screenshot shows one client and two services running inside the same instance of GlassFish.
Metro has five mbean types:
WSClient
General information for a client.
WSEndpoint
General information for an endpoint.
WSNonceManager
Nonce manager used by endpoints to prevent replay attacks.
This only exists on the endpoint side, scoped per-endpoint.
WSRMSCSessionManager
Manages Reliable Messaging (RM) and/or Secure Conversation (SC) sessions.
This only exists on the endpoint side, scoped per-endpoint.
WSRMSequenceManager
Manages Reliable Messaging sequences.
This exists on both client and endpoints sides, scoped per-stub and per-endpoint respectively.
In the screenshot there is
one client that is connected to the
AddNumbersService
two endpoints: a /s17...
service and an
ExampleService
one WSNonceManager
associated with the
/s17...
service
two WSRMSCSessionManager
s, one for each of
the two services
two WSRMSequenceManager
s, one associated
with the client, the other with
ExampleService
.
Using Jmxterm you can find these same mbeans (note: the output
of beans
show a lot of beans, this has been edited to
only show Metro's mbeans):
Example 19.11.
java -jar <Jmxterm-jar> Welcome to JMX terminal. Type "help" for available commands. $>open localhost:8686 #Connection to localhost:8686 is opened $>beans ... #domain = amx: amx:name=/s17-PingService-PingPort,pp=/mon/server-mon[server],type=WSEndpoint amx:name=ExampleService,pp=/mon/server-mon[server],type=WSEndpoint amx:name=NonceManager,pp=/mon/server-mon[server]/WSEndpoint[/s17-PingService-PingPort],type=WSNonceManager amx:name=RMSequenceManager,pp=/mon/server-mon[server]/WSClient[http-//localhost-8080/AddNumbersService/AddNumbersService],type=WSRMSequenceManager amx:name=RMSequenceManager,pp=/mon/server-mon[server]/WSEndpoint[ExampleService],type=WSRMSequenceManager amx:name=RM_SC_SessionManager,pp=/mon/server-mon[server]/WSEndpoint[/s17-PingService-PingPort],type=WSRMSCSessionManager amx:name=RM_SC_SessionManager,pp=/mon/server-mon[server]/WSEndpoint[ExampleService],type=WSRMSCSessionManager amx:name=http-//localhost-8080/AddNumbersService/AddNumbersService,pp=/mon/server-mon[server],type=WSClient ...
The following screenshot shows the top-level information available for each client:
Children: the WSRMSequenceManager
that
is used by this client.
Container: the container in which the client is deployed---in this case: GlassFish. Note that the actual container object has not been instrumented with monitoring so it Java class@address is printed.
Name: the root name given for this client.
Parent: show the WSClient
under the AMX
mbean.
qnameToPortInfoMap: an internal map used by the runtime system.
serviceClass: The SEI (service endpoint interface).
serviceName: From the WSDL.
wsdlDocumentLocation: Where the WSDL used to create
the client lives. (Note: when a service is created using
NetBeans it makes a local copy of the WSDL, therefore the
example shows a file
instead of an
http
location.)
wsdlService: an internal data structure that is not instrumented.
To see these attributes in jmxterm:
Example 19.12.
$>bean amx:name=http-//localhost-8080/AddNumbersService/AddNumbersService,pp=/mon/server-mon[server],type=WSClient $>info #class name = WSClient # attributes %0 - Children ([Ljavax.management.ObjectName;, r) %1 - Container (java.lang.String, r) %2 - Name (java.lang.String, r) %3 - Parent (javax.management.ObjectName, r) %4 - qnameToPortInfoMap (javax.management.openmbean.TabularData, r) %5 - serviceClass (java.lang.String, r) %6 - serviceName (java.lang.String, r) %7 - wsdlDocumentLocation (java.lang.String, r) %8 - wsdlService (java.lang.String, r) $>get Name Name = http-//localhost-8080/AddNumbersService/AddNumbersService;
Children: in this example there are two other mbeans associated with the example service.
addressingVersion: generally this will be
W3C
unless explicitly using a different
version of addressing.
bindingID: the namespace for the type of binding used for the service.
dumpHTTPMessages: when set to true
then
HTTP messages received and sent by this service are
"dumped" into the log file. It is possible to dynamically
set this value. Just click on the value, type in the value
and hit return using JConsole. In jmxterm:
Example 19.13.
$>bean amx:name=ExampleService,pp=/mon/server-mon[server],type=WSEndpoint $>set dumpHTTPMessages true
features: the "features" (see the JAX-WS specification) used in this endpoint. Using jmxterm (assuming the bean has been set as in dump above:
Example 19.14.
$>get features features = [ { enabled = true; iD = http://www.w3.org/2005/08/addressing/module; }, { enabled = true; iD = com.sun.xml.ws.rm.ReliableMessagingFeature; } ];
jaxwsRuntimeVersion: the version of the JAX-WS specification which is implemented by Metro.
policy: A representation of the policy used by the
endpoint. The entire policy is more easily viewed using
jmxterm: $>get policy
. Note: the format of
the policy output can and will
change.
portName: The WSDL port name.
seiModelWSDLLocation: not currently supported.
serviceDefinitionImports: a list of any of files imported by the main WSDL file for this service.
serviceDefinitionURL: the service's WSDL.
serviceName: The WSDL service name.
soapVersionHttpBindingId: The namespace of the HTTP binding.
wsdlEndpointAddress: this generally will not contain the real address since it depends on a client calling the service to exist and the value is taken before that happens.
wsdlPortTypeName: The WSDL port type.
This allows one to examine the contents of a nonce manager of a specific service. Using jmxterm:
Example 19.15.
$>bean amx:name=NonceManager,pp=/mon/server-mon[server]/WSEndpoint[/s17-PingService-PingPort],type=WSNonceManager $>get NonceCache NonceCache = { maxNonceAge = 900000; nonceCache = { ( F2jz9MkcI9Gcshk1K0snDPhC ) = { key = F2jz9MkcI9Gcshk1K0snDPhC; value = 2009-12-03T22:21:39Z; }; }; oldNonceCache = { }; scheduled = true; wasCanceled = false; };
Examine reliable messaging and secure conversation keys and sessions for a specific service. Using jmxterm:
Example 19.16.
$>bean amx:name=RM_SC_SessionManager,pp=/mon/server-mon[server]/WSEndpoint[ExampleService],type=WSRMSCSessionManager $>get keys keys = [ uuid:8593cea6-9328-41fe-986a-abf0745c4470, uuid:0987fa78-cd7d-4c1c-9ec2-e849b7f68881 ]; $>get sessions sessions = [ { creationTime = 1259879310907; lastAccessedTime = 1259879310907; securityInfo = { creationTime = null; expirationTime = null; externalId = null; identifier = null; issuedTokenContext = null; secret = null; }; sessionKey = uuid:8593cea6-9328-41fe-986a-abf0745c4470; }, { creationTime = 1259866808000; lastAccessedTime = 1259866808000; securityInfo = { creationTime = null; expirationTime = null; externalId = null; identifier = null; issuedTokenContext = null; secret = null; }; sessionKey = uuid:0987fa78-cd7d-4c1c-9ec2-e849b7f68881; } ];
boundSequences: generally an inbound sequence will be bound to an outbound sequence so that requests and replies are reliable. This table gives the sequence identifiers for those pairs.
concurrentlyOpenedInbound: the number of inbound sequences opened.
persistent: true if using Metro's persistent reliable messaging.
sequences: a map from a sequence identifier to information on that sequence. In jmxterm:
Example 19.17.
$>bean amx:name=RMSequenceManager,pp=/mon/server-mon[server]/WSEndpoint[ExampleService],type=WSRMSequenceManager $>get sequences sequences = { ( uuid:5145de4e-618b-4da3-9004-c715770934d2 ) = { key = uuid:5145de4e-618b-4da3-9004-c715770934d2; value = { ackRequested = false; boundSecurityTokenReferenceId = null; closed = false; expired = false; hasUnacknowledgedMessages = true; id = uuid:5145de4e-618b-4da3-9004-c715770934d2; lastActivityTime = 1259880084724; lastMessageNumber = 1; state = CREATED; }; }; ( uuid:d16b0fb9-7e80-4598-a3e2-789c9bac9474 ) = { key = uuid:d16b0fb9-7e80-4598-a3e2-789c9bac9474; value = { ackRequested = false; boundSecurityTokenReferenceId = null; closed = false; expired = false; hasUnacknowledgedMessages = false; id = uuid:d16b0fb9-7e80-4598-a3e2-789c9bac9474; lastActivityTime = 1259880084724; lastMessageNumber = 1; state = CREATED; }; }; };
uniqueEndpointId: An identifier used by the reliable messaging implementation. Note: this is not related to client and endpoint root name identifiers
The AMX mbean is created lazily. Therefore, if one deploys an
endpoint in GlassFish and then looks for the Metro
WSEndpoint
mbeans using JConsole there are times where
the AMX mbean does not appear. To activate it start up the asadmin GUI
or CLI. Or use jmxterm and issue its domains
command.
In some cases Metro endpoint mbeans will not appear until the endpoint receives its first client invocation.
WSClient
mbeans can appear and disappear quickly if
the stub is just used for one call then closed immediately. A stub
that uses reliable messaging or secure conversation generally stays
active longer since it will most likely be used for multiple
calls.
Metro supports a feature we will be calling Metro Web Services Runtime Configuration Management (Metro CM) from here on. It allows to reconfigure a running web service instance without losing any messages. The web service does not have to be redeployed or restarted. All configuration changes are persisted across application redeployments and server restarts.
Metro provides an easy to use management interface based on JMX to reconfigure web service instances. Any WS-Policy expression that is supported by Metro may be used through that interface. This chapter explains how to deploy reconfigurable web services, how to author new policy expressions and how to implement management clients that can reconfigure manageable web services.
The configuration management is configured through a policy assertion that the service is looking up from its initial configuration. The initial configuration are the Metro configuration files. In the case of a web service with bundled WSDL, the bundled WSDL is the configuration file. Otherwise Metro will look for a file in WEB-INF or META-INF named wsit-<endpoint implementation class>.xml. The configuration file is in (slightly simplified) WSDL 1.1 format. Here is how a configuration file might look like:
Example 19.18.
<?xml version='1.0' encoding='UTF-8'?> <definitions xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/ oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://test.ws.xml.sun.com/" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://test.ws.xml.sun.com/" name="NewWebServiceService"> <message name="echo"> <part name="parameters" element="tns:echo"/> </message> <message name="echoResponse"> <part name="parameters" element="tns:echoResponse"/> </message> <portType name="NewWebService"> <operation name="echo"> <input message="tns:echo"/> <output message="tns:echoResponse"/> </operation> </portType> <binding name="NewWebServicePortBinding" type="tns:NewWebService"> <wsp:PolicyReference URI="#NewWebServicePortBindingPolicy"/> <operation name="echo"/> </binding> <service name="NewWebServiceService"> <port name="NewWebServicePort" binding="tns:NewWebServicePortBinding"> <wsp:Policy> <sunman:ManagedService xmlns:sunman="http://java.sun.com/xml/ns/metro/management" id="WebApplicationSunJAXWSFromWSDL"> </sunman:ManagedService> </wsp:Policy> </port> </service> </definitions>
The part that enables the configuration management is the policy expression under the WSDL port element. Note that this policy must be a child element of the WSDL port element. You could also use a PolicyReference instead of inlining the policy.
The id attribute of the ManagedService policy assertion is mandatory and can be anything that is convenient for the configuration management client. The ID must be unique for each web services that is managed by a management client:
Note that the default implementation will write this ID to a database, i.e. it might be subject to the length restrictions of the database column. The default implementation itself does not enforce any length restrictions.
The start attribute of the ManagedService policy
assertion controls the behavior of the managed web service
when it is instantiated. The web service may, depending on the
container implementation, already be instantiated during
deployment or once it has received an init-cm
request from a management client or a SOAP request from a web
service client.
By default, when this attribute is omitted or contains an unknown value, the web service will configure itself immediately without waiting for configuration from a management client. Otherwise, if you want the web service instance to wait until it has received configuration, the start attribute needs to be set to notify:
Even when start is set to notify, the web service will still come up without any signal from a management client if it finds any persistent configuration in the Metro durable storage. This is to allow endpoints to recover from system failures and allows to operate in clusters where only one web service instance can receive a configuration signal.
You can pass some configuration parameters into the default JMX communication implementation as well as specify your own communication implementations. The generic syntax is this:
Example 19.21.
<sunman:ManagedService id="user defined"> <sunman:CommunicationServerImplementations> <sunman:CommunicationServerImplementation className="fully qualified class name"> <ParameterName>value</ParameterName> </sunman:CommunicationServerImplementation> <sunman:CommunicationServerImplementation className="fully qualified class name"> <ParameterName>value</ParameterName> </sunman:CommunicationServerImplementation> </sunman:CommunicationServerImplementations> </sunman:ManagedService>
The CommuncationServerImplementation className attribute
allows you to plug in one or more of your own implementations. The
implementation must implement the
com.sun.xml.ws.api.config.management.CommunicationServer
interface. You can specify arbitrarily named parameters that your
code will be able to read through
com.sun.xml.ws.api.config.management.policy.ManagedServiceAssertion
.
If you just want to set some configuration parameters for the default JMX implementation, do not specify the className attribute:
Example 19.22.
<sunman:ManagedService id="user defined"> <sunman:CommunicationServerImplementations> <sunman:CommunicationServerImplementation> <sunman:JmxServiceUrl>value</sunman:JmxServiceUrl> <sunman:JmxConnectorServerEnvironment> <ParameterName>value</ParameterName> </sunman:JmxConnectorServerEnvironment> <sunman:JmxConnectorServerCreator> fully qualified class name </sunman:JmxConnectorServerCreator> </sunman:CommunicationServerImplementation> </sunman:CommunicationServerImplementations> </sunman:ManagedService>
JMXServiceUrl allows you to specify what transport protocol
and address the default JMX agent should be listening to. By
default the following URL will be used:
service:jmx:rmi:///jndi/rmi://localhost:8686/metro/ID
,
where ID is what was specified in the ManagedService id
attribute.
JmxConnectorServiceEnvironment allows to pass parameters
into the connector of the default JMX agent. This can be used to
set security settings for example. There are some cases however
where you need to pass objects other than Strings into the JMX
connector service environment. Therefore it is possible to specify
a custom class with JmxConnectorServerCreator
that is
expected to return an already initialized JMXConnectorServer. The
JmxConnectorServerCreator must implement the interface
com.sun.xml.ws.api.config.management.jmx.JmxConnectorServerCreator
.
This allows you to plug in a custom
com.sun.xml.ws.api.config.management.Configurator
implementation:
Example 19.23.
<sunman:ManagedService id="user defined"> <sunman:ConfiguratorImplementation className="fully qualified class name"> <ParameterName>value</ParameterName> </sunman:ConfiguratorImplementation> </sunman:ManagedService>
The default Configurator implementation does not take any parameters, i.e. there is no need to provide this configuration statement if you don't want to plug in a custom implementation.
The persistence API consists of two interfaces,
com.sun.xml.ws.api.config.management.ConfigSaver
and
com.sun.xml.ws.api.config.management.ConfigReader
.
ConfigSaver is meant to write the new service configuration to
durable storage. ConfigReader is designed to run asynchronously
(it can also be implemented to run synchronously however) and can
e.g. poll the durable storage for configuration changes and kick
off a service reconfiguration. You can specify your implementation
classes like this:
Example 19.24.
<sunman:ManagedService id="user defined"> <sunman:ConfigSaverImplementation className="fully qualified class name"> <ParameterName>value</ParameterName> </sunman:ConfigSaverImplementation> <sunman:ConfigReaderImplementation className="fully qualified class name"> <ParameterName>value</ParameterName> </sunman:ConfigReaderImplementation> </sunman:ManagedService>
Again, if you want to configure the default implementations, leave away the className attribute:
Example 19.25.
<sunman:ManagedService id="user defined"> <sunman:ConfigSaverImplementation className="fully qualified class name"> <sunman:JdbcDataSourceName>value</sunman:JdbcDataSourceName> <sunman:JdbcTableName>value</sunman:JdbcTableName> <sunman:JdbcIdColumnName>value</sunman:JdbcIdColumnName> <sunman:JdbcVersionColumnName>value</sunman:JdbcVersionColumnName> <sunman:JdbcConfigColumnName>value</sunman:JdbcConfigColumnName> </sunman:ConfigSaverImplementation> <sunman:ConfigReaderImplementation className="fully qualified class name"> <sunman:JdbcDataSourceName>value</sunman:JdbcDataSourceName> <sunman:JdbcTableName>value</sunman:JdbcTableName> <sunman:JdbcIdColumnName>value</sunman:JdbcIdColumnName> <sunman:JdbcVersionColumnName>value</sunman:JdbcVersionColumnName> <sunman:JdbcConfigColumnName>value</sunman:JdbcConfigColumnName> </sunman:ConfigReaderImplementation> </sunman:ManagedService>
JdbcDataSourceName
lets you customize the name
of the JDBC DataSource. The name defaults to
jdbc/metro/management
.
JdbcTableName
is the name of the database table
that contains the configuration data. It defaults to
METRO
.
JdbcIdColumnName
is the name of the column that
holds the managed web service ID. It defaults to id
and is expected to be of a type that can hold a JDBC String value.
This column should be declared as a primary key. The default
implementation does not impose any restrictions on the length of
the web service ID.
JdbcVersionColumnName
is the name of a column
that provides a running counter and defaults to
version
. The counter is increased strictly
monotonously when new configuration data is written to the table.
This allows the implementation to efficiently establish if new
data was written. The column type needs to map to a JDBC Long
type.
JdbcConfigColumnName
is the name of the column
that holds the current configuration data and defaults to
config
. The data is read and written as a character
BLOB. The column type must be suitable for use with a JDBC
character stream.
If you change one of these settings for the
ConfigSaverImplementation
or the
ConfigReaderImplementation
, make sure that you are
configuring the same setting for both implementations.
The previous sections detailed all configuration options but it might be easier to follow some simple step by step instructions to set up and deploy a managed web service from scratch:
Create a database
Register the data source (GlassFish in this example)
In the admin console under Resources/JDBC create a connection pool (or use an existing one).
Create a JDBC Resource with the name jdbc/metro/management.
Instead of the GlassFish admin console, you can use the GlassFish asadmin tool from the command line like this:
Example 19.27.
$ asadmin create-jdbc-connection-pool --datasourceclassname org.apache.derby.jdbc.ClientDataSource --restype javax.sql.DataSource \\ --property user=APP:password=APP:portNumber=1527:serverName=localhost:databaseName=metroConfig metro_config_pool $ asadmin create-jdbc-resource --connectionpoolid metro_config_pool jdbc/metro/management
Create a web application with a web service
The following shows a Servlet based web service. JSR 109 web services are configured similarly. See here for detailed instructions on how to configure a JAX-WS servlet.
Attach a ManagedService policy assertion to the web service port (see next step how this looks like).
Add this to the web.xml:
Example 19.28.
<resource-ref> <description>Metro Web Services Config Management DB Connection </description> <res-ref-name>jdbc/metro/management</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>
The Metro configuration for a managed web service would look like this (including the surrounding WSDL service/port elements):
Example 19.29.
<service name="NewWebServiceService"> <port name="NewWebServicePort" binding="tns:NewWebServicePortBinding"> <wsp:Policy> <sunman:ManagedService xmlns:sunman="http://java.sun.com/xml/ns/metro/management" id="any unique id"> </sunman:ManagedService> </wsp:Policy> </port> </service>
This chapter discusses the implementation of JMX management clients for managed web services. It focuses on RMI as the JMX transport protocol because RMI is ubiquitously supported by the Java SDKs. But it is possible to plug in any JMX transport protocols and the configuration settings listed in section Metro CM Configuration allow to configure the server side extensively.
This client requires that an RMI registry is running that holds the RMI stub object. This is the default setting for a managed Metro web service and will work out of the box with GlassFish.
Example 19.30.
import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import javax.management.Attribute; import javax.management.MBeanServerConnection; import javax.management.JMException; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; public class Client { public static void main(String[] args) throws MalformedURLException, IOException, JMException { final String serviceId = "service-1"; // Force the service to deploy final URL initUrl = new URL ("http://localhost:8080/webapp/port" + "?init-cm"); final URLConnection initConnection = initUrl.openConnection(); Thread.sleep(5000L); // The RMI registry is running on the local host in this case. JMXServiceURL url = new JMXServiceURL ("service:jmx:rmi:///jndi/rmi://localhost:8686/metro" + "/" + serviceId); JMXConnector connector = JMXConnectorFactory.connect(url); MBeanServerConnection connection = connector .getMBeanServerConnection(); connection.setAttribute(new ObjectName("com.sun.xml.ws.config" + ".management:className=" + serviceId), new Attribute("policies", "<sunman:Policies>...</sunman:Policies>")); connector.close(); } }
The package
com.sun.xml.ws.api.config.management.jmx
contains
some helper code with the names of the commonly used JMX
attributes. The client from the previous section would look like
this:
Example 19.31.
import com.sun.xml.ws.api.config.management.jmx.JmxConstants; import com.sun.xml.ws.api.config.management.jmx.JmxUtil; import java.io.IOException; import java.net.MalformedURLException; import javax.management.Attribute; import javax.management.MBeanServerConnection; import javax.management.JMException; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; public class Client { public static void main(String[] args) throws MalformedURLException, IOException, JMException { final String serviceId = "service-1"; // The RMI registry is running on the local host in this case. JMXServiceURL url = new JMXServiceURL(JmxConstants .JMX_SERVICE_URL_DEFAULT_PREFIX + serviceId); JMXConnector connector = JMXConnectorFactory.connect(url); MBeanServerConnection connection = connector .getMBeanServerConnection(); connection.setAttribute(JmxUtil.getObjectName(serviceId), new Attribute(JmxConstants .SERVICE_POLICIES_ATTRIBUTE_NAME, "<sunman:Policies>...</sunman:Policies>")); connector.close(); } }
JMX clients can be required to authenticate and their actions can be limited. The Sun JDK JMX implementation provides several methods, including JAAS, to take care of authentication and authorization. They are extensively discussed in this blog entry. Here we only cover the simplest use case that is discussed in that blog, where JMX connector environment properties point to one password file and one access file.
Create one file named e.g. jmx.password
with
this content:
This defines two users monitorRole and controlRole and their
passwords. Next create a file jmx.access
with this
content:
This allows user monitorRole to only read data, while controlRole may also write. The Metro management MBean only provides one attribute and that attribute is write-only, i.e. the only case where a read-only user makes sense would be for listening to notifications.
Now you can configure the service management interface with these settings:
Example 19.34.
<sunman:ManagedService id="service-id"> <sunman:CommunicationServerImplementations> <sunman:CommunicationServerImplementation> <sunman:JmxConnectorServerEnvironment> <jmx.remote.x.password.file> /path/to/jmx.password </jmx.remote.x.password.file> <jmx.remote.x.access.file> /path/to/jmx.access </jmx.remote.x.access.file> </sunman:JmxConnectorServerEnvironment> </sunman:CommunicationServerImplementation> </sunman:CommunicationServerImplementations> </sunman:ManagedService>
Finally, the client code needs to explicitly set the password before it connects to the JMX agent:
Example 19.35.
import com.sun.xml.ws.api.config.management.jmx.JmxConstants; import com.sun.xml.ws.api.config.management.jmx.JmxUtil; import java.io.IOException; import java.net.MalformedURLException; import javax.management.Attribute; import javax.management.MBeanServerConnection; import javax.management.JMException; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; public class Client { public static void main(String[] args) throws MalformedURLException, IOException, JMException { final String serviceId = "service-1"; // The RMI registry is running on the local host in this case. JMXServiceURL url = new JMXServiceURL( JmxConstants.JMX_SERVICE_URL_DEFAULT_PREFIX + serviceId); // Set client credentials HashMap<String, Object> env = new HashMap<String, Object>(); String[] creds = {"controlRole", "crpasswd"}; env.put(JMXConnector.CREDENTIALS, creds); JMXConnector connector = JMXConnectorFactory.connect(url, env); MBeanServerConnection connection = connector.getMBeanServerConnection(); connection.setAttribute( JmxUtil.getObjectName(serviceId), new Attribute(JmxConstants.SERVICE_POLICIES_ATTRIBUTE_NAME, "<sunman:Policies>...</sunman:Policies>")); connector.close(); } }
While the section Metro CM Management Clients on management clients showed how to implement a JMX client, it does not detail the format of the policies input attribute. We will first explain the basic format.
WS-PolicyAttachment defines a format for external policy attachments that fulfills our requirements without adding any superfluous information. It allows to communicate multiple policies at once. It identifies the policy subject to which a policy is attached. Here is an example:
Example 19.36.
<wsp:PolicyAttachment> <wsp:AppliesTo> <wsp:URI> http://test.ws.xml.sun.com/NewWebServiceService? \ wsdl#wsdl11.binding(NewWebServicePortBinding) </wsp:URI> </wsp:AppliesTo> <wsp:PolicyReference URI="#NewWebServicePortBindingPolicy"/> </wsp:PolicyAttachment> <wsp:PolicyAttachment> <wsp:AppliesTo> <wsp:URI> http://test.ws.xml.sun.com/NewWebServiceService? \ wsdl#wsdl11.bindingOperation.input(NewWebServicePortBinding/echo) </wsp:URI> </wsp:AppliesTo> <wsp:PolicyReference URI="#NewWebServicePortBinding_echo_Input_Policy"/> </wsp:PolicyAttachment> <wsp:PolicyAttachment> <wsp:AppliesTo> <wsp:URI> http://test.ws.xml.sun.com/NewWebServiceService? \ wsdl#wsdl11.bindingOperation.output(NewWebServicePortBinding/echo) </wsp:URI> </wsp:AppliesTo> <wsp:PolicyReference URI="#NewWebServicePortBinding_echo_Output_Policy"/> </wsp:PolicyAttachment>
The above still allows for references to external policies.
It is possible to directly include a policy by using the
<wsp:Policy>
element instead of
<wsp:PolicyReference>
.
The external attachments in section External Policy Attachments contain URIs that point to the attachment element. The format for these URIs that is used are WSDL 1.1 element identifiers.
Here is an example input document with inlined policies:
Example 19.37.
<Policies> <wsp:PolicyAttachment> <wsp:AppliesTo> <wsp:URI> http://test.ws.xml.sun.com/NewWebServiceService? \ wsdl#wsdl11.binding(NewWebServicePortBinding) </wsp:URI> </wsp:AppliesTo> <wsp:Policy>...</wsp:Policy> </wsp:PolicyAttachment> <wsp:PolicyAttachment> <wsp:AppliesTo> <wsp:URI> http://test.ws.xml.sun.com/NewWebServiceService? \ wsdl#wsdl11.bindingOperation.input(NewWebServicePortBinding/echo) </wsp:URI> </wsp:AppliesTo> <wsp:Policy>...</wsp:Policy> </wsp:PolicyAttachment> <wsp:PolicyAttachment> <wsp:AppliesTo> <wsp:URI> http://test.ws.xml.sun.com/NewWebServiceService? \ wsdl#wsdl11.bindingOperation.output(NewWebServicePortBinding/echo) </wsp:URI> </wsp:AppliesTo> <wsp:Policy>...</wsp:Policy> </wsp:PolicyAttachment> <wsp:PolicyAttachment> <wsp:AppliesTo> <wsp:URI> http://test.ws.xml.sun.com/NewWebServiceService? \ wsdl#wsdl11.bindingOperation.fault(NewWebServicePortBinding/fault) </wsp:URI> </wsp:AppliesTo> <wsp:Policy>...</wsp:Policy> </wsp:PolicyAttachment> </Policies>
In practice, management applications may not know the exact WSDL element names. Therefore, we are using synthetic URNs to identify WSDL attachment points without having to know their WSDL element names. We need to identify the following five WSDL elements:
binding
binding/operation
binding/operation/input
binding/operation/output
binding/operation/fault
We always use the same five URNs to denote the five allowed attachment points. The URNs are constructed from UUIDs. We are using the following URNs:
urn:uuid:c9bef600-0d7a-11de-abc1-0002a5d5c51b
urn:uuid:62e66b60-0d7b-11de-a1a2-0002a5d5c51b
urn:uuid:730d8d20-0d7b-11de-84e9-0002a5d5c51b
urn:uuid:85b0f980-0d7b-11de-8e9d-0002a5d5c51b
urn:uuid:917cb060-0d7b-11de-9e80-0002a5d5c51b
The document that is used as input needs to have a valid XML
root element because WS-PolicyAttachment does not provide any. The
namespace is the same we use for the Metro configuration file with
the term management appended:
http://java.sun.com/xml/ns/metro/management
.
The fully qualified root element is: <Policies
xmlns:sunman="http://java.sun.com/xml/ns/metro/management">
.
Example 19.38.
<?xml version="1.0" encoding="UTF-8"?> <sunman:Policies xmlns:sunman="http://java.sun.com/xml/ns/metro/management" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/ oasis-200401-wss-wssecurity-utility-1.0.xsd"> <wsp:PolicyAttachment> <wsp:AppliesTo> <wsp:URI>urn:uuid:c9bef600-0d7a-11de-abc1-0002a5d5c51b </wsp:URI> </wsp:AppliesTo> <wsp:Policy wsu:Id="binding-policy">...</wsp:Policy> </wsp:PolicyAttachment> <wsp:PolicyAttachment> <wsp:AppliesTo> <wsp:URI>urn:uuid:62e66b60-0d7b-11de-a1a2-0002a5d5c51b </wsp:URI> </wsp:AppliesTo> <wsp:Policy wsu:Id="operation-policy">...</wsp:Policy> </wsp:PolicyAttachment> <wsp:PolicyAttachment> <wsp:AppliesTo> <wsp:URI>urn:uuid:730d8d20-0d7b-11de-84e9-0002a5d5c51b </wsp:URI> </wsp:AppliesTo> <wsp:Policy wsu:Id="input-policy">...</wsp:Policy> </wsp:PolicyAttachment> <wsp:PolicyAttachment> <wsp:AppliesTo> <wsp:URI>urn:uuid:85b0f980-0d7b-11de-8e9d-0002a5d5c51b </wsp:URI> </wsp:AppliesTo> <wsp:Policy wsu:Id="output-policy">...</wsp:Policy> </wsp:PolicyAttachment> <wsp:PolicyAttachment> <wsp:AppliesTo> <wsp:URI>urn:uuid:917cb060-0d7b-11de-9e80-0002a5d5c51b </wsp:URI> </wsp:AppliesTo> <wsp:Policy wsu:Id="fault-policy">...</wsp:Policy> </wsp:PolicyAttachment> </sunman:Policies>
The wsu:Id of the wsp:Policy element is optional but should be defined whenever possible so that policies can easily be identified. If it is not omitted, it must be a unique ID within the document.