Create a WSDM interface for an HTTP server using Apache Muse

Exposing the manageability of a common product with Web services standards

Learn how you can use Apache Muse to create a WS-DistributedManagement (WSDM)-compliant interface for a manageable resource. In this tutorial, you'll see how to design the Web service interface for the resource, generate code for the implementation, and deploy the code as a Web application. The manageable resource focus of this tutorial is the ubiquitous Apache HTTP Server, commonly-referred to as "httpd." After completing this tutorial, you should have a Muse-based application that lets any WSDM-compliant management client manipulate the httpd resource.

Dan Jemiolo, Advisory Software Engineer, IBM

Photo of Dan JemioloDan 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.



21 November 2006

Also available in Japanese

Before you start

Learn what to expect from this tutorial, and how to get the most out of it.

About this tutorial

This tutorial goes beyond simple examples and illustrates how to build a WS-DistributedManagement (WSDM) interface for a software product that is very common in today's IT systems. It uses the tools and framework from the Apache Muse project to design, implement, and deploy a WSDM interface for the Apache HTTP Server, commonly-referred to as "httpd." If you have not used Muse before you are not expected to fully understand this tutorial until you have completed the introductory tutorial (see Resources) that is part of the project's documentation.

Objectives

In this tutorial, you learn some of the finer points of designing a Web services interface for an existing manageable resource; along the way, you create a Service Definition Language (WSDL) document that defines a Web services interface for httpd. You'll then use the tools that ship with Muse to generate code and artifacts that adhere to the interface and which can be deployed as a Java™ Platform, Enterprise Edition (Java EE) Web application. Finishing the application so that it allows WSDM-compatible management clients to manipulate httpd will teach you how to map the concepts in WSDM to a product's existing management API.

Prerequisites

This tutorial 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. Finally, it is expected that you have tried the introductory tutorial (see Resources for a link) that is included with the Muse 2.0 distribution and have successfully run the sample applications.

System requirements

To run the application that you build in this tutorial, you need to have Apache Tomcat installed on your system. Keep in mind that Tomcat 5.5 requires Java Platform, Standard Edition (Java SE) 1.5, so if you are using Java SE 1.4, you'll want Tomcat 4.1 or 5.0. The work is shown using a Microsoft Windows console, but the tutorial can be completed by UNIX® and Linux® users as well.


Installing and understanding the Apache HTTP Server

If you're already familiar with httpd and have it installed on your system, you can skip this section. For everyone else, I will provide instructions for installing httpd, confirm that it works, and review the files that are pertinent to the tutorial.

The first step to building a Web services manageability interface for httpd is making sure you have the product on your system! You can get the latest version from the Apache Web site; Microsoft® Windows® users will find the MSI installer the easiest to use.

After you have extracted the contents of the distribution, you can start it by running the /bin/httpd application in the installation directory. After the server is started, you can verify that it's working by using any Web browser. Go to http://localhost and you should see a simple message: It works! All you need to do now is to look at some of the files in the installation and understand their purpose.

Another way to start httpd

Windows users have another way of starting the server. In the Start Menu, select Apache HTTP Server > Control Apache Server > Start Apache in Console. The console will be blank when the server has started.

The /bin directory of the httpd installation contains the httpd application itself as well as a number of scripts that offer, among other things, performance testing, log maintenance, and cache management. All of these scripts have a number of options or tasks associated with them that you may want to expose to a management client. In this tutorial, I focus on the httpd application itself, but the manipulation of this executable should illustrate how you would access the other executables to add more features to the application.

The /conf directory contains the configuration files for httpd. The most important file is httpd.conf, which contains all of the basic TCP/IP, threading, and permissions settings, plus a whole lot more; the settings are simple name-value pairs much like a Java properties file. At the top of this file you see a comment warning you to be judicious in changing the values in the file; in that spirit, I will not be modifying any of values in httpd.conf that have an effect on server behavior. I'll be reading values from this file as part of the implementation of WS-ResourceProperties for httpd.


Designing a WSDL, Part 1: The resource properties

Now that you understand the basics of httpd, take a look at how you can translate httpd concepts into those in the WSRF and WSDM specifications. The first part of any WSRF-based WSDL is its state model or resource properties document.

Different types of properties

All Web services that are based on WSRF must have a resource properties document as defined by the WS-ResourceProperties specification. WSRF and WSDM both define a number of standard properties (many of which are optional) that are useful to managed resource developers; there are also many pieces of information in the httpd installation that could be useful to a management client, things that are specific to HTTP servers. I'll discuss some of the standard properties at your disposal first, then cover the httpd-specific ones.

WS-* properties

This section cannot possibly cover all of the properties that are defined by WSRF and WSDM (you can find that information in the OASIS standards link in Resources). Instead, I highlight a few of the most important ones and how I intend to use them for the httpd interface.

  • ResourceId. Part of the WSDM Management Using Web Services (MUWS) Identity capability, this is a unique identifier for each instance of a resource type. For example, you may have three instances of an httpd resource, but each would have a different ResourceId value to differentiate it.
  • ManageabilityCapability. Part of the WSDM MUWS ManageabilityCharacteristics capability, this collection of URIs communicates to remote clients which management features the Web service supports. In other words, it tells management clients "here's what I can do."
  • Caption, Description, and Version. Part of the WSDM MUWS Description capability, these values provide human-readable text that help management clients sort and present the resources more clearly.
  • OperationalStatus. Part of the WSDM MUWS OperationalStatus capability, this is a simple enumeration that gives a high-level report on the resource's ability to service requests. The valid values are Available, PartiallyAvailable, Unavailable, and Unknown.

These properties all revolve around the common themes of identification and description. While their values may be httpd-specific in this application, their definitions and semantics adhere to the standards. The first two properties are URIs, the last two are simple strings. You can assign proper values to them as you get into the code implementation stage.

HTTP properties

The Apache HTTP Server has a lot of configuration data that would be useful to a management client and it is all found in the httpd.conf file; of course, this file also contains a lot of information that you wouldn't want exposed through Web services, so I won't just say that every property in the httpd.conf file should be a resource property. Instead, I will pick a few simple values from this file and I'll show you how they can be modeled as resource properties with WSRP, which should give you insight into how other management-related values could be exposed.

Open the httpd.conf file and look through the file. You should see the following properties:

  • ThreadsPerChild. The number of request-handling threads in each httpd process. The default is 250.
  • Listen. The port number that the server is listening on. The default is 80.
  • ServerName. The full host name and port that the server uses to identify itself. This is optional, but is useful for descriptive purposes. You can uncomment this line (delete the #) and provide the right value. http://localhost is sufficient for this tutorial.

There are many other properties as well, but I'll focus on these three for this tutorial. One excellent quality that these properties share is that they are generic to HTTP servers; that is, there is nothing httpd-specific about them or their values. This is key to getting the most out of WSRF and WSDM because product-specific management APIs were one of the main complexities that these specifications were designed to eliminate. This Web service interface could be reused by another HTTP server product and management clients would not have to change their logic to support it.

I will add a namespace to these properties later in order to create an XML schema for them. The types of the ThreadsPerChild, Listen, and ServerName properties are integer, integer, and URI, respectively. That's all you need to know to craft a WSDL that can be used to generate the proper Muse-based code and artifacts.


Designing a WSDL, Part 2: The resource operations

Selecting which operations your Web services interface should have requires understanding the WSRF and WSDM specifications as well as the executables in httpd's /bin directory. Let's look at WSRF and WSDM first to make sure to reuse as much as possible from those standards.

WS-* operations

Because you're creating a WSRF-based resource, you not only need a resource properties document but the WSRP operations to manipulate that document. The minimal set of operations required by WSRF has just one operation: GetResourceProperty. The resource properties that you selected from WSDM belong to capabilities that do not define any operations, so GetResourceProperty may be all you need. The other parts of WSRF -- WS-ResourceLifetime, WS-ServiceGroup, and so on -- are not applicable to this example.

There are actually three "get" operations defined by WSRP and they differ only in how much information can be requested at a time. Because they are so similar, Muse 2.0 implements all three operations -- GetResourceProperty, GetResourcePropertyDocument, and GetMultipleResourceProperties as one component or capability. This is discussed further in the introductory tutorial that is part of the Muse documentation. I mention it here only as justification for adding the other two "get" operations to the WSDL -- if you are going to include the code to execute these operations and they provide no extra burden on your application, you might as well expose them to remote clients as an added convenience.

Another very useful operation that is used in all of the Muse sample applications is GetMetadata from WS-MetadataExchange (WSX). This operation provides a very robust way for clients to resolve a resource's WSDL document. Because the ?wsdl convention that is used by Web browsers is not based on SOAP and does not take into account virtual paths, it's good to support this operation whenever possible to ensure that clients can resolve all parts of your WSDL.

So, the final list of WS-* operations that you are including in your WSDL is: GetResourceProperty, GetResourcePropertyDocument, GetMultipleResourceProperties, and GetMetadata.

HTTP operations

Securing httpd operations

Security should obviously be a concern when opening up such critical operations as starting and stopping a server. The authentication and authorization of these actions is beyond the scope of this tutorial, but you can learn about Web services security in the Resources section.

Earlier I said that there were multiple executables and tasks that could be found /bin, but that I would focus on the httpd application when defining new operations that could be invoked by management clients. As with the resource properties, I will try to focus on things that are generic to HTTP servers rather than httpd itself. Two obvious candidates are Start and Stop -- a management client would definitely need to control the availability of the server if it were in charge of maintaining and optimizing it. You can map the Start and Stop operations to the execution of the httpd application and termination of the same process, respectively.

In this simple scenario, neither the Start nor Stop operations will have a parameter list. You create the schema for the WSDL messages in the same namespace as the resource properties document. The operations are combined with the WSRP operations and the resource properties document to form the resource's port type. The port type will serve as the cohesive interface that clients use to reason about and manipulate the HTTP server resource.


Designing a WSDL, Part 3: Creating the XML

In this section, you will start executing on the design decisions of the last two sections by creating an actual WSDL document for your httpd resource. You'll modify the template WSDL provided by the Muse SDK so that it includes the WS-* definitions you need.

The Muse SDK includes a template WSDL that includes all of the properties and operations defined by the WSRF and WSDM specifications; all you have to do to modify the template is add comment markers around definitions you don't want and add your custom properties and operations. This is the same WSDL you started from when you completed the introductory tutorial. You can find the template in the /docs/2.0.0/tutorial/artifacts directory of the Muse SDK or you can download it here.

Create a directory named http-management and put a copy of the template file there. As with the introductory tutorial, you should also copy in all of the WS-* WSDL and XSD files that are referenced by the template. You can then take the following steps to customize it:

  1. Give the WSDL file a meaningful name, such as "http-server.wsdl".
  2. Use your text editor to perform a search-and-replace on the current target namespace (http://ws.apache.org/muse/test/wsrf). Change the namespace to http://www.example.com/http-server.
  3. Use your text editor to perform a search-and-replace on the current WSDL name (WsResource). Change the name to HttpServer.
  4. At the bottom of the WSDL, change the location attribute on the <wsdl-soap:address/> element to be http://localhost:8080/http-management/services/http-server.
  5. Delete all of the resource properties that are not being used by your httpd resource. These include CurrentTime, TerminationTime, QueryExpressionDialect, and the four topic-related properties.
  6. Delete all of the <wsdl:message/> and <wsdl:operation/> elements that are not being used by your httpd resource. These include QueryResourceProperties, SetResourceProperties, Subscribe, and GetCurrentMessage.

The template WSDL is now customized for your httpd resource. It has five properties defined by WSDM and four operations: GetResourceProperty, GetResourcePropertyDocument, GetMultipleResourceProperties, and GetMetadata. All that remains is to add the properties and operations that are specific to HTTP servers.


Designing a WSDL, Part 4: Adding the HTTP definitions

In this final section on WSDL creation, you will add the httpd-specific resource properties and operations to the customized WSDL file. You'll then move on to code generation, using Muse command-line tools to create an application from this WSDL.

The HTTP resource properties

To add the httpd-specific resource properties you must create an XML schema definition for them and then insert references to them in the resource properties document. The three resource properties are ThreadsPerChild, Listen, and ServerName. In the interest of clarity, you will rename Listen to PortNumber so that Web services clients don't have to know about httpd-specific configuration data.

The resource properties document is defined in the <wsdl:types/> section under an <xsd:schema/> element bound to the http://www.example.com/http-server namespace. It looks like the code shown in Listing 1:

Listing 1. Resource properties document definition
<xsd:schema elementFormDefault="qualified" 
      targetNamespace="http://www.example.com/http-server">

   <xsd:element name="HttpServerProperties">
       <xsd:complexType>
        
            ...
            
</xsd:schema>

You need to add the three property definitions shown in Listing 2 to the schema. They can go above or below the HttpServerProperties element.

Listing 2. Three property definitions
<xsd:element name="ServerName" type="xsd:anyURI"/>
<xsd:element name="PortNumber" type="xsd:integer"/>
<xsd:element name="ThreadsPerChild" type="xsd:integer"/>

These three lines define the property types, but they do not add the property instances to the resource properties document. To do that you must add to the HttpServerProperties element, like shown in Listing 3.

Listing 3. Adding to the HttpServerProperties element
<xsd:element name="HttpServerProperties">
    <xsd:complexType>
        <xsd:sequence>
            <xsd:element ref="tns:ServerName"/>
            <xsd:element ref="tns:PortNumber"/>
            <xsd:element ref="tns:ThreadsPerChild"/>
            
            ...
            
        </xsd:sequence>
    </xsd:complexType>
</xsd:element>

Notice the use of the ref attribute -- this is the most common way to reference other schema types in the resource properties document. Here you are saying that there should be one instance of each of the three types in each instance of the resource property document; in other words, every call of GetResourceProperty for one of these properties must return exactly one value.

The HTTP resource operations

In the same <xsd:schema/> element where you added the resource property definitions, you will now add the message types for the Start and Stop operations. This is fairly straightforward because these operations do not have parameters:

Listing 4. Adding message types
<xsd:element name="Start"/>
<xsd:element name="StartResponse"/>

<xsd:element name="Stop"/>
<xsd:element name="StopResponse"/>

<xsd:element name="StartFailedFault">
    <xsd:complexType>
        <xsd:complexContent>
            <xsd:extension base="wsrf-bf:BaseFaultType" />
        </xsd:complexContent>
    </xsd:complexType>
</xsd:element>

<xsd:element name="StopFailedFault">
    <xsd:complexType>
        <xsd:complexContent>
            <xsd:extension base="wsrf-bf:BaseFaultType" />
        </xsd:complexContent>
    </xsd:complexType>
</xsd:element>

No type versus open content

Don't confuse having no type ("void" in Java) with allowing open content. The latter requires a type of xsd:anyType. Muse's code generation tool maps parameters of xsd:anyType to the org.w3c.dom.Element type from the JDK, giving you the raw XML content to work with in your Java method. In this example, you don't want any parameters, so leave the type blank.

The message elements do not have a type attribute because they are empty ("void"). You have also added two fault types, one for each operation, so that you can report errors that are specific to the life cycle of the HTTP server. The faults extend from WSRF's BaseFault and use that type's fields to communicate the fault's timestamp, message, origin, and more.

You now need to provide the <wsdl:message/> and <wsdl:operation/> elements for these operations so that they can be included in your port type. Most WSDL editors add the <wsdl:operation/> elements automatically after you add the <wsdl:message/> elements, but for everyone using a regular text editor, the XML is shown in Listing 5. The <wsdl:message/> elements can be added to the end of the current list of <wsdl:message/> elements; the same is true for the <wsdl:operation/> elements under the WSDL's port type.

Listing 5. XML sample
<wsdl:message name="StartRequest">
    <wsdl:part name="StartRequest" element="tns:Start" />
</wsdl:message>
<wsdl:message name="StartResponse">
    <wsdl:part name="StartResponse"/>
</wsdl:message>
<wsdl:message name="StartFailedFault">
    <wsdl:part name="StartFailedFault" element="tns:StartFailedFault" />
</wsdl:message>
<wsdl:message name="StopRequest">
    <wsdl:part name="StopRequest" element="tns:Stop" />
</wsdl:message>
<wsdl:message name="StopResponse">
    <wsdl:part name="StopResponse" />
</wsdl:message>
<wsdl:message name="StopFailedFault">
    <wsdl:part name="StopFailedFault" element="tns:StopFailedFault" />
</wsdl:message>

<wsdl:portType name="HttpServerPortType" 
               wsrf-rp:ResourceProperties="tns:HttpServerProperties">
               
    ...
    
    <wsdl:operation name="Start">
      <wsdl:input  wsa:Action="http://www.example.com/http-server/Start" 
                   name="StartRequest" message="tns:StartRequest" />
      <wsdl:output wsa:Action="http://www.example.com/http-server/StartResponse" 
                   name="StartResponse" message="tns:StartResponse" />
      <wsdl:fault name="StartFailedFault" message="tns:StartFailedFault"/>
      <wsdl:fault name="ResourceUnknownFault" message="tns:ResourceUnknownFault"/>
      <wsdl:fault name="ResourceUnavailableFault" 
                   message="tns:ResourceUnavailableFault"/>
  </wsdl:operation>
  <wsdl:operation name="Stop">
      <wsdl:input  wsa:Action="http://www.example.com/http-server/Stop" 
                   name="StopRequest" message="tns:StopRequest" />
      <wsdl:output wsa:Action="http://www.example.com/http-server/StopResponse" 
                   name="StopResponse" message="tns:StopResponse" />
      <wsdl:fault name="StopFailedFault" message="tns:StopFailedFault"/>
      <wsdl:fault name="ResourceUnknownFault" message="tns:ResourceUnknownFault"/>
      <wsdl:fault name="ResourceUnavailableFault" 
                   message="tns:ResourceUnavailableFault"/>
    </wsdl:operation>
               
</wsdl:portType>

Your WSDL is now complete. You have a WSDM interface for an HTTP server that includes properties and operations from WSRF, WSDM, WSX, and your own custom definitions. You map this interface to httpd-specific commands and settings with the help of Muse's code generation tool, WSDL2Java.


Code generation with WSDL2Java

You will now use the WSDL2Java tool to generate the skeleton Java code and XML artifacts for a Muse-based application. After the code is generated, I'll start describing how you map properties and operations to the httpd installation.

At this point you should have your http-server.wsdl file (as well as the WS-* files it depends on) in a directory named http-management. From the command line, switch to the http-management directory and invoke the following:

wsdl2java -proxy -wsdl http-server.wsdl

Custom capabilities are defined by namespaces

As a reminder, all custom capability definitions are separated by their XML namespaces. When WSDL2Java analyzes your WSDL, it creates a new custom capability (package, interface, and implementation class) for each new schema that is referenced in your port type. For larger projects with port types that tie together more than one schema, this means that there will be multiple implementation classes to complete; it also means you won't have a giant, monolithic Java class to sort through when debugging a particular capability's behavior.

The tool generates three directories -- JavaSource, WebContent, and src -- and an Apache Ant build file. The JavaSource directory contains the skeleton source code for the httpd-specific capabilities. The WebContent directory contains the Apache Axis2 SOAP engine, Muse libraries, WSDL files, and the Muse deployment descriptor; you should not need to modify anything in the WebContent directory, but its contents should look familiar to those in the Muse SDK's sample projects. The src directory contains the complete source code for a remote client; you can use this code to communicate with the WSDM interface without writing a lot of XML plumbing code.

Drill down through the package directories in JavaSource until you find the Java source files -- they should be named IMyCapability.java and MyCapability.java. By default, WSDL2Java configures the generated application to use Muse's implementations of the WS-* capabilities and then creates Java code for all custom capabilities, such as your HTTP server definitions. Thus, there is no generated code for WSRF, WSDM, or WSX constructs -- these are handled by the Muse libraries that you can find in WebContent/WEB-INF/lib. The source code you see here will be compiled into a JAR file and added to WebContent/WEB-INF/lib by the build file before a Java EE WAR file is created.

If you open the IMyCapability.java file, you see a Java interface that contains getter and setter methods for all three httpd properties, as well as start and stop methods. It also has a constant for the capability's XML namespace. Finally, notice that it extends Muse's org.apache.muse.ws.resource.WsrfCapability interface that provides the foundation for all WSRF-based capabilities. The code should look exactly like Listing 6.

Listing 6. Java interface code
package com.example.www.http_server;

import javax.xml.namespace.QName;

public interface IMyCapability
{
    String PREFIX = "tns";

    String NAMESPACE_URI = "http://www.example.com/http-server";

    public int getThreadsPerChild();

    public void setThreadsPerChild(int param0);

    public String getServerName();

    public void setServerName(String param0);

    public int getPortNumber();

    public void setPortNumber(int param0);

    public void start() throws StartFault;

    public void stop() throws StopFault;
}

When you look in MyCapability.java, you see an implementation class that has method stubs for all of the interface's methods. In the next section, you'll start filling in these methods so that the WSDM interface actually works!


Implementing the HTTP Server operations

In this section you will use the httpd application to implement the start and stop methods. The implementation of stop is Windows-specific, but I'll discuss the simplicity in making it work for UNIX-based systems.

Both the start and stop methods require the use of Java's java.lang.Runtime class to execute shell commands. The start and stop methods just execute the httpd application with the proper command-line flag -- it's as simple as that. The code in Listing 7 assumes that you have httpd installed in at /apache-2.2 (C:\apache-2.2, for Windows users). You should copy and paste it into your MyCapability.java file.

Listing 7. Copy and paste into your MyCapability.java file
 public void start() 
  throws StartFailedFault
 {
  try
  {
   Runtime.getRuntime().exec("/apache-2.2/bin/httpd -k start");
   getLog().info("The httpd process was started successfully.");
  }
  
  catch (IOException error)
  {
   throw new StartFailedFault("The httpd process failed to start.");   
  }
 }

 public void stop() 
  throws StopFailedFault
 {
  try
  {
   // Unix users: use ps and kill to do the same task
   Runtime.getRuntime().exec("/apache-2.2/bin/httpd -k stop");
   getLog().info("The httpd process was stopped successfully.");
  }
  
  catch (IOException error)
  {
   throw new StopFailedFault("The httpd process failed to stop.");   
  }
 }

After each call to Runtime.exec(), you print a message to the Muse log file to confirm that the operation was a success. You will find this log file in the deployed WAR file under the WEB-INF/services/muse/log directory.

At this point you should see how you have taken generic Web services operations and mapped them down to a real IT resource (httpd). It should be easy to imagine how you would change this implementation for another HTTP server product without changing the interface or behavior from a client's point-of-view.


Implementing the HTTP Server operations

In this section you'll use the httpd.conf file to fill in the values of the resource property fields. The implementation defines the three properties as read-only to remote clients so that you don't have to introduce WS-Security authentication; keeping the properties read-only also allows you to avoid the checks that would be needed to prevent changes while the httpd process is running.

Because your properties won't change after startup, you can read them in from httpd.conf once during initialization and keep them in the fields that WSDL2Java created in the MyCapability class. You should copy and paste the implementation code into your MyCapability.java file.

Listing 8. Implementation code
    public void initialize()
        throws SoapFault
    {
        super.initialize();
        
        Map configParams = null;
	        
	try
	{
	    configParams = readConfigFile("/apache-2.2/conf/httpd.conf");
	}

	catch (IOException error)
	{
	    throw new SoapFault("Error while reading httpd.conf.", error);
	}

	_ServerName = (String)configParams.get("ServerName");
	
	String portString = (String)configParams.get("Listen");
	String threadsString = (String)configParams.get("ThreadsPerChild");
	
	_PortNumber = Integer.valueOf(portString);
        _ThreadsPerChild = Integer.valueOf(threadsString);
    }
    
    protected Map readConfigFile(String filePath)
        throws IOException
    {
        BufferedReader reader = new BufferedReader(new FileReader(filePath));
        String nextLine = null;
        
        Map configParams = new HashMap();
        
        while ((nextLine = reader.readLine()) != null)
        {
            nextLine = nextLine.trim();
            
            // ignore comments and blank lines
            if (nextLine.length() == 0 || 
                nextLine.charAt(0) == '#' || 
                nextLine.charAt(0) == '<')
                continue;
            
            int space = nextLine.indexOf(' ');
            String name = nextLine.substring(0, space);
            String value = nextLine.substring(space + 1);
            configParams.put(name, value);
        }
        
        return configParams;
    }

Allowing for mutable resource properties

If your properties were dynamic, you would remove the fields and instead read the property values from httpd.conf in each getter method. If you end up extending this application to make the properties mutable, both the getter and setter methods will be implemented using the java.io package to read in the httpd.conf file at the time of the request.

The first method overrides the base class's initialize method, which is where capabilities can perform all of their self-contained startup tasks; this method simply reads the name-value pairs in the httpd.conf file into a java.util.Map and then sets the class's fields using the values it finds. The initialize method is called before any SOAP requests are serviced by the Muse application.

The second method performs the actual task of parsing the file into java.util.Map, taking care to remove comments and blank lines from the input. Finally, the getter methods should remain exactly as they are -- they simply return the values that were read in from httpd.conf when called by Muse's GetResourceProperty implementation.


Making the implementation more configurable

The implementation is just about done -- there's just one issue that I should address before you build and deploy the application -- the hard-coded installation path of httpd.

In the start, stop, and initialize methods, you refer to the /apache-2.2 directory when referencing files in the httpd installation. This is a hack and it will prevent you from reusing the WSDM manageability interface on other machines for other instances of httpd. You can avoid having to recompile and rebuild the application for each new machine by making the installation directory an initialization parameter for the Muse application.

In the Muse deployment descriptor, you have the option to specify initialization parameters or simple name-value pairs for each capability in a resource type. Open the file named WebContent/WEB-INF/services/muse/muse.xml and look for the fragment of XML shown in Listing 9.

Listing 9. XML fragment
<capability>
  <capability-uri>http://www.example.com/http-server</capability-uri>
  <java-capability-class>com.example.www.http_server.MyCapability</java-capability-class>
</capability>

This fragment describes the HTTP server capability to the Muse run time. It is here that you can add the initialization parameter that will store the httpd install path. When you move this application to a different machine (with a different httpd installation at a different path), all you have to do is change the muse.xml file to have the new path rather than recompiling and rebuilding. Listing 10 shows the syntax for the addition to muse.xml.

Listing 10. Syntax for addition to muse.xml
<capability>
  <capability-uri>http://www.example.com/http-server</capability-uri>
  <java-capability-class>com.example.www.http_server.MyCapability</java-capability-class>
  <init-param>
      <param-name>httpd-install-dir</param-name>
      <param-value>C:\apache-2.2</param-value>
  </init-param>
</capability>

Now you must change your Java code to read in this value and use it rather than the hard-coded path. Fortunately, the Muse run time does all the hard work for you and all you have to do is call the getInitializationParameter() method. You should modify your current code to include the lines in bold in Listing 11.

Listing 11. Calling the getInitializationParameter() method
 public void initialize()
  throws SoapFault
 {
  super.initialize();
  
  String installDir = getInitializationParameter("httpd-install-dir");
  
  Map configParams = null;
	  
	try
	{
	 configParams = readConfigFile(installDir + "/conf/httpd.conf");
	}

	catch (IOException error)
	{
	 throw new SoapFault("Error while reading httpd.conf.", error);
	}

	_ServerName = (String)configParams.get("ServerName");
	
	String portString = (String)configParams.get("Listen");
	String threadsString = (String)configParams.get("ThreadsPerChild");
	
	_PortNumber = Integer.valueOf(portString);
  _ThreadsPerChild = Integer.valueOf(threadsString);
 }
 
 ...
 
 public void start() 
  throws StartFailedFault
 {
  try
  {
   String installDir = getInitializationParameter("httpd-install-dir");
  
   Runtime.getRuntime().exec(installDir + "/bin/httpd -k start");
   getLog().info("The httpd process was started successfully.");
  }

  catch (IOException error)
  {
   throw new StartFailedFault("The httpd process failed to start.");   
  }
 }
 
 public void stop() 
  throws StopFailedFault
 {
  try
  {
   String installDir = getInitializationParameter("httpd-install-dir");
  
   Runtime.getRuntime().exec(installDir + "/bin/httpd -k stop");
   getLog().info("The httpd process was stopped successfully.");
  }

  catch (IOException error)
  {
   throw new StartFailedFault("The httpd process failed to start.");   
  }
 }

You're now ready to compile, build, and deploy your WSDM endpoint for httpd!


Building and deploying the WSDM endpoint

From the same command line where you ran WSDL2Java, you will now use Ant to build the Java EE WAR file that will be deployed onto Apache Tomcat. All you have to do is run ant from the command line and it will execute the instructions in the build.xml file. The end result will be a file named http-management.war.

After the WAR file has been created, you should copy it into the /webapps directory of your Apache Tomcat installation. When you start the Tomcat server, it will expand and deploy the WAR file. You can then go the next and final section, where you will run a test client against the WSDM endpoint to make sure that it's working.


Testing the WSDM endpoint

Now that the WSDM endpoint for httpd is built and deployed and the Tomcat server started, you can run a test client against it to see if it actually works! Remember that remote client that was generated by WSDL2Java? It has getter and setter methods for all of your resource properties, as well as methods for all of your operations. The code in Listing 12 uses that client to invoke the Start and Stop operations and read all of the resource property values (GetResourceProperty). You should copy and paste this code into the HttpProxy.java file, compile, and run it.

Listing 12. Invoking the Start and Stop operations
    public static void main(String[] args)
    {
        //
        // create EPR for test resource
        //
        URI address = URI.create("http://localhost:8080/http-management/services/http");
        EndpointReference epr = new EndpointReference(address);

        //
        // create proxy - uncomment setTrace() to see SOAP messages
        //
        HttpProxy http = new HttpProxy(epr);
        // http.setTrace(true);

        try
        {

            //
            // start server
            //
            http.start();

            //
            // read/print some property values
            //
            System.out.println("Name: " + http.getServerName());
            System.out.println("Port: " + http.getPortNumber());
            System.out.println("Threads: " + http.getThreadsPerChild());
        }

        catch (Throwable error)
        {
            error.printStackTrace();
        }

        try
        {
            //
            // stop server
            //
            http.stop();
        }

        catch (Throwable error)
        {
            error.printStackTrace();
        }
    }

The output of this test client should be:

Name: http://localhost
Port: 80
Threads: 250

If you uncomment the call to http.setTrace(true);, you will see all of the SOAP messages that are sent and received by the test client. This is very valuable when debugging new WSDM endpoints. Uncommenting the line now will let you see one call to Start, three calls to GetResourceProperty, and one call to Stop.

Finally, if you look in the Tomcat console or the Muse log file (WEB-INF/services/muse/log/muse.log), you will see the messages that you printed in the start and stop methods. Another way to confirm that the operations are working is to remove the call to stop in the test client and then use your Web browser to look up http://localhost; if you see the It works! message again, you know the httpd process really is active.


Conclusion

This tutorial showed you how to move beyond simple tutorials and start integrating Apache Muse with real IT products. You built a working WSDM interface for Apache's HTTP Server and validated it with your own test client and a Web browser. More importantly, you learned how abstract concepts in the WSRF and WSDM concepts can be mapped down to concrete concepts in software products using the Muse programming model; these ideas should serve as a basis for enabling other products with WSDM.

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Tivoli (service management) on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Tivoli (service management), Tivoli, SOA and web services
ArticleID=175541
ArticleTitle=Create a WSDM interface for an HTTP server using Apache Muse
publish-date=11212006