Skip to main content

skip to main content

developerWorks  >  Autonomic computing | SOA and Web services  >

Keep your WSDM endpoints trim with Apache Muse

How to represent a large number of resources without an overwhelming increase in footprint

developerWorks
Document options

Document options requiring JavaScript are not displayed

Sample code


Rate this page

Help us improve this content


Level: Intermediate

Dan Jemiolo (danjemiolo@us.ibm.com), Advisory Software Engineer, IBM

12 Dec 2006

Learn how to use Apache Muse 2.0 to create WS-DistributedManagement (WSDM) interfaces for resource types that have hundreds or thousands of instances. First, this article shows how to create a WSDM interface to represent Java™ Platform, Enterprise Edition (Java EE) application resources (which can be quite numerous in any given application server). Second, it shows how to create a "factory" resource that in turn creates the Web application resources as they are installed on the server. Finally, you'll see how to minimize the footprint needed to support a large number of resources so the WSDM endpoint doesn't burden its host.

In many IT environments, the manageable resources that you want to expose using WSDM are quite numerous, to the point where creating a set of Java objects for every one of them will hinder the host machine's performance. If your WSDM interfaces are not efficient in the way they store addressing and resource data, they could quickly become heavyweights, as heavy as the resources they are representing.

A situation that presents an example of both of these issues is when you want to create WSDM interfaces for the components in a Java EE application server; such a product will host Web applications, Enterprise Java Beans (EJBs), JDBC™ data sources, and many other components. In the interest of simplicity, in this article I focus on just one of these components -- the Java EE Web application -- and then explain how to duplicate the work done here for the other resource types while keeping in-memory footprint low.

This article is written for Java programmers whose skills and experience are at an intermediate level. You should also have a solid understanding of the concepts and XML schemas that are defined in the WS-ResourceFramework (WSRF) and WSDM standards. And you should have tried the introductory tutorial that is included with the Apache Muse 2.0 distribution and have successfully run the sample applications.

Designing the solution

To meet the performance goals, I need to make two assumptions when designing the WSDM interface for Java EE Web applications:

  1. The implementation of the Web application resource properties and operations are stateless; that is, the code will not hold any data that is related to a specific instance of a Web application.
  2. All of the data needed to route a request to a specific instance of a Web application will be found in the request's WS-Addressing headers.

If you agree to these design decisions, it is possible to write implementation code that handles a large number of resources with a relatively small number of objects. Because the code is stateless, the instantiation of it (an object) is always the same; this means that you can reuse one object for every single Web application resource. The trick is completed by mapping multiple endpoint references (EPRs) to the one object so that it can handle all requests. I demonstrate how to create a separate resource whose sole job is to create these EPR-to-object mappings whenever a new Web application is installed on the server.

Creating the solution with Apache Muse

The Apache Muse project provides you with an implementation of WSDM and code generation tools that make it easier to develop WSDM interfaces. After designing the WSDM interface for Web applications and encoding it in a WSDL document, you can run Muse's WSDL2Java tool to create a skeleton implementation. Then I'll provide some sample implementation code that you can use to test the WSDM interface. Finally, you will use some of Muse's lower-level APIs to map multiple EPRs to a single org.apache.muse.core.Resource object, avoiding the need to have one org.apache.muse.core.Resource object per resource instance.

Code generation

Let's starting by generating code with WSDL2Java. In the interest of time, I've created two WSDL documents -- one for the Java EE Web application resource and one for the "factory" resource. I've also provided the Muse deployment descriptor, muse.xml, which lets you generate code for two resource types at the same time. You can download all of these files, extract them to a directory of your choice, and then run Muse's WSDL2Java tool as follows: wsdl2java -descriptor muse.xml.

The implementation code for the Java EE application resources is under the JavaSource directory, in the package named com.ibm.management.j2ee.application; the factory resource code is in the package named com.ibm.management.j2ee.factory. The WSDL and XML artifacts in the WebContent directory do not need to be modified.

Implementation code

The Java EE application resource code is filled in with code that looks up a JMX MBean representing the application and manipulating it as necessary. The application server creates MBeans for all of the components installed inside it and the lookup process is fairly straightforward. The MBean lets you get or set properties and invoke operations on the application. Thus, all of the state for the individual applications is stored in the application server that's hosting the WSDM interface and not the code; this gives you the stateless implementation you were looking for.

The code in Listing 1 can be copied and pasted into the implementation file com.ibm.management.j2ee.application.ApplicationCapability. Notice that each method -- the getters, setters, and operations -- uses the getObjectNameFromRequest() method to get the name of the MBean representing the proper application. This name can be used to look up the right MBean object and manipulate it. The implementation does not contain any state that pertains to a specific application -- all of that is handled by the MBean API.


Listing 1. Implementation code

public class ApplicationCapability 
    extends AbstractWsResourceCapability implements IApplicationCapability
{
    private static final QName OBJECT_NAME_PARAM = 
        new QName("http://ibm.com/management/j2ee", "ObjectName", "j2ee");
        
    private static final QName[] _PROPERTIES = new QName[]{
        new QName(NAMESPACE_URI, "StartTime", PREFIX)
    };

    public QName[] getPropertyNames()
    {
        return _PROPERTIES;
    }
        
    //
    // The J2EE management system provides an EJB that we can use to 
    // lookup the MBeans for each component in the server
    //
    private Management managementEJB = null;
            
    //
    // Utility method for getting the MBean name by reading the
    // WS-Addressing reference parameters
    //
    protected ObjectName getObjectNameFromRequest()
    {
        MessageHeaders wsa = getEnvironment().getAddressingContext();
        EndpointReference epr = wsa.getToAddress();
        String param = epr.getPropertyString(OBJECT_NAME_PARAM);
        return new ObjectName(param);
    }
    
    //
    // Muse's standard initialization method for Capability classes
    //
    public void initialize()
        throws SoapFault
    {
        super.initialize();
        
        //
        // find the EJB that is used to invoke MBeans by name
        //
        try
        {
            Context context = new InitialContext();
            Object ejb = context.lookup("java:comp/env/ejb/mgmt/MEJB");

            ManagementHome home = 
                (ManagementHome)PortableRemoteObject.narrow(ejb, ManagementHome.class);

            managementEJB = home.create();
        }

        catch (Throwable error)
        {
            throw new RuntimeException(error.getMessage(), error);
        }
    }
    
    //
    // The remaining code contains the generated methods with their 
    // complete implementations
    //
    
    public Date getStartTime()
    {
        ObjectName objName = getObjectNameFromRequest();
        Long timeInMS = (Long)managementEJB.getAttribute(objName, "startTime");
        return new Date(timeInMS.longValue());
    }
    
    public void start()
    {
        ObjectName objectName = getObjectNameFromRequest();
        managementEJB.invoke(objectName, "start", null, null);
    }
    
    public void stop()
    {
        ObjectName objectName = getObjectNameFromRequest();
        managementEJB.invoke(objectName, "stop", null, null);
    }
}

The factory resource will be in charge of handling the creation of new Web applications; its Web services interface is very limited because it is not expected to do anything other than create new EPR-to-Resource mappings. The implementation code for this resource is limited to its initialization routines, where you perform two tasks:

  • Create a single Resource object to represent Java EE applications.
  • Look for all of the MBeans on the server that represent applications and then create an EPR-to-Resource mapping for each of them.

The code in Listing 2 can be copied and pasted into the implementation file com.ibm.management.j2ee.factory.FactoryCapability. This code makes one instance of the Java EE application resource and then, for each MBean it finds, creates a unique EPR and maps it to the Resource object. This allows the Muse request router to confirm the validity of incoming requests before dispatching to the implementation code. Creating one EPR object per actual resource instance adds minimally to the overall footprint; the real bulk of the potential footprint is in the Resource objects (and the capabilities they contain).


Listing 2. Code makes one instance and creates and maps a unique EPR

public class FactoryCapability 
    extends AbstractCapability implements IFactoryCapability
{
    private static final QName OBJECT_NAME_PARAM = 
        new QName("http://ibm.com/management/j2ee", "ObjectName", "j2ee");
        
    public void initialize()
        throws SoapFault
    {
        super.initialize();
        
        //
        // find the context path for the J2EE application resource type
        //
        ResourceManager manager = getEnvironment().getResourceManager();
        String contextPath = manager.getResourceContextPath(ApplicationCapability.class);
        
        //
        // create one instance of the application ws-resource
        //
        Resource singletonResource = manager.createResource(contextPath);
        singletonResource.initialize();
        
        EndpointReference singletonEPR = singletonResource.getEndpointReference();
        
        //
        // find all of the MBeans for J2EE applications installed on our server
        //        
        Set applications = null;
        
        try
        {
            ObjectName pattern = new ObjectName("*:j2eeType=J2EEDeployedObject,*");
            applications = getManagementEJB().queryNames(pattern, null);
        }
        
        catch (Throwable error)
        {
            throw new RuntimeException(error.getMessage(), error);
        }
        
        //
	// for every MBean we find for a J2EE application, create an EPR 
        // with the J2EE object name as the reference parameter; then, 
        // map that EPR to the Resource object above
        //
        Iterator i = applications.iterator();
	
	while (i.hasNext())
        {
            ObjectName objectName = (ObjectName)i.next();
            
            EndpointReference epr = new EndpointReference(singletonEPR);
            epr.addParameter(OBJECT_NAME_PARAM, objectName);
	    
            manager.addResource(epr, singletonResource);
        }
    }
}

This code creates all of the EPR-to-Resource mappings at initialization, meaning that it will only catch those applications that are installed when the server starts. It can be modified to create (and destroy) the mappings more dynamically by listening to Java EE's MBeanServer API to find out when applications are installed (and uninstalled) on the server. However, the main idea of the code is always the same -- map multiple EPRs to one instance of a stateless Resource object and delegate state maintenance to the server's MBeans.

Extending the implementation

This implementation code could easily be extended to deal with other Java EE components in the application server; all you would need to do is

  • Add a new WSDL with the desired interface
  • Run WSDL2Java again
  • Use the same implementation ideas to fill in the Java source files

If you want to modify the factory resource to create other types of resources, all you have to do is modify the string literal in the following line of code:

ObjectName pattern = new ObjectName("*:j2eeType=J2EEDeployedObject,*");

The bold string is a simple pattern that lets you search for multiple MBeans at a time; if you change J2EEDeployedObject to J2EEServer, you will get all of the server instances that are currently running. A list of all of the valid Java EE type names can be found in this Java EE inheritance diagram.

By using this pattern, you only create one Resource object for every resource type defined in muse.xml and one EPR object per resource instance. Because EPR objects are rather small, you are still saving a lot in terms of footprint. You can afford to add many other Java EE components to this Muse-based WSDM interface without it becoming a burden to the actual resources it is managing.

Conclusion

Share this...

digg Digg this story
del.icio.us Post to del.icio.us
Slashdot Slashdot it!

In this article I've shown you how to use the Apache Muse APIs to represent large numbers of Web services resources with a smaller in-memory footprint than is normally required by a Muse-based application. The example is specific to Java EE management, but the concepts can be reused for other IT resources; the factory resource and EPR mapping strategy are generic and the use of the MBean API can be replaced by other manageability APIs for other products. You can reuse this design pattern when building WSDM interfaces with Apache Muse so that the addition of a new management layer does not adversely affect the system you are managing. A small footprint is not essential in all scenarios, but when it is, the Muse APIs are flexible enough to help.




Back to top


Download

DescriptionNameSizeDownload method
Sample WSDL files for this articleapache-muse-factory-xml.zip17KBHTTP
Information about download methods


Resources

Learn

Get products and technologies

Discuss


About the author

Photo of Dan Jemiolo

Dan Jemiolo is an Advisory Software Engineer on IBM's Autonomic Computing team in Research Triangle Park, NC. He led the design and development of Apache Muse 2.0 and continues to work on the project today. Dan also participates in the WS-RF TC as editor of the WS-ResourceMetadataDescriptor specification and is involved in IBM's strategy for increasing adoption of Web services standards. He came to IBM just over two years ago after earning his Master of Science degree in Computer Science from Rensselaer Polytechnic Institute.




Rate this page


Please take a moment to complete this form to help us better serve you.



YesNoDon't know
 


 


12345
Not
useful
Extremely
useful
 


Back to top