Innovative uses for WebSphere sMash, Part 2: Automate enterprise operations through a cloud by wrapping management tools for external systems

This series of articles describes actual examples of where IBM® WebSphere® sMash was selected and used to perform innovative and valuable tasks to aid in the operations of IBM's Green Innovation Data Center (GIDC) in Southbury, CT, USA. Part 1 looked at how WebSphere sMash was used to build a flexible framework for constructing data center dashboards. In this second article, you will see how WebSphere sMash can be used to wrap external systems management tools with easy-to-use APIs to facilitate the automation of costly manual tasks that used to add to the overhead of running the GIDC. This content is part of the IBM WebSphere Developer Technical Journal.

Share:

Aaron Kasman (akasman@us.ibm.com), Advisory Software Engineer, IBM

Aaron Kasman is an advisory software engineer in the Innovation Engineering team in the IBM CIO Office where he focuses on internal Platform-as-a-Service (PaaS) offerings, with an interest toward supporting innovators and situational application development. Prior to this role, he was part of the IBM Software Services for WebSphere team developing IBM.com’s e-commerce presence. His interests include WebSphere sMash, Platform and Software-as-a-Service technologies, content and community management with Drupal and CiviCRM, and visual design.



Andrew J. F. Bravery (abravery@us.ibm.com), Senior Technical Staff Member, Executive IT Architect, IBM

Andy Bravery is a Senior Technical Staff Member, Executive IT Architect and Manager of the Innovation Engineering team in the IBM CIO Office. Mr Bravery has a rich background of experience working in the emerging technology field. His recent work has been around exploiting cloud technologies to support situational applications in the enterprise. Mr. Bravery is a member of the British Computer Society & an Open Group Certified Master IT Architect and holds an honours degree in Physics from the University of Birmingham, UK.



14 July 2010

Also available in Chinese

Introduction

Running a data center is not just about keeping the lights on across the racks of servers. There is an ever increasing number of processes and procedures that need to be executed in order to meet the necessary standards of security, data protection, and asset management that today’s enterprise demands. Finding new ways to automate these tasks and building them into flexible workflows is one of the principle focuses of the Innovation Engineering team.

This article highlights an example of where we were able to use the features of WebSphere sMash to easily wrap an external system’s API so that a set of steps that used to have to be performed by an operator using a user interface could now be automatically driven from a controlling component of our cloud management infrastructure.

You will also learn some tips for taking advantage of WebSphere sMash’s powerful features for making the development and configuration of common components of Web applications easier.


An enterprise scenario

In our environment, all computers on the network -- real and virtual -- need to be registered in a database, which we will refer to as our Address database. Traditionally, users add, remove, and update entries for each of the systems they own in the Address database through a Web application with a typical user interface. However, when introducing a cloud environment, we want to simplify the process by registering instances on behalf of the users as they request them. Similarly, when the user no longer needs the instance, we want to make sure the registration is removed for the instance.

Fortunately, our Address database application already has a Java™ API for performing these operations. Each cloud management system in the enterprise could include a Java program that uses this API to manage entries in the Address database.

Imagine, though, that multiple cloud systems want to take advantage of this service. To avoid having to distribute and update the Java API libraries in multiple places, we could instead set up a service that wraps the Java API so that it can be accessed by other systems over HTTP via RESTful endpoints. We would have one common service for use across the enterprise. The steps behind developing that service are the focus of this article.

Figure 1 illustrates an overview of the architecture. Generally, systems -- rather than human users -- will connect to the service we will be offering, although operators can still use the user interface to access the Address database directly if they wish.

Figure 1. Architecture of the Address database wrapper
Figure 1. Architecture of the Address database wrapper

You will see how WebSphere sMash makes this process easy by eliminating tricky configuration and letting you focus on the logic of the application.

This article assumes that you are familiar with the basics of setting up a WebSphere sMash environment and creating a “hello world” application, and that you have already read Part 1 of this series, which introduces some of the concepts that will be expanded upon here. In this example, the sample application will be coded in Groovy, but WebSphere sMash provides you with the option to use PHP as an alternative, if that is your preference.


Creating the basics

The actions on the Address database that you need to support include creating, deleting, listing, retrieving, and updating records.

Part 1 looked at how WebSphere sMash easily maps these basic operations to methods in a Groovy file, as well as to HTTP paths and operations. However, that article only looked at getting data (retrieving and listing) from the service. Here, things get a bit more interesting as the callers of your service want to perform a wider variety of operations. Since the Java API to the Address database provides the required operations, your task is to bridge the Java methods in the API to URI endpoints.

Let’s start by creating a Groovy handler called system.groovy in the /resources directory with the methods listed in Listing 1. Remember that the /resources directory is a good place to include REST handlers for managing collections. In this case, the collection is a set of systems that you are registering and managing in the Address database.

Listing 1. Stub methods for system.groovy
def onList() { 

	print("This function will list systems in the database.")

}

def onCreate() { 
	print ("This function will create a new system in the database")

}

def onRetrieve() { 
	print ("This function will retrieve a particular system from the database")

} 

def onUpdate() { 
	print ("this function will update an existing system in the database")

}  

def onDelete() { 
	print ("this function will delete an existing system from the database")

}

Each method will be triggered by a different HTTP operation, as listed in Table 1, which shows the mapping of the HTTP operations, URIs, and methods. This is our RESTful API in a nutshell.

Table 1. Mapping of HTTP operations, URIs, and methods
HTTP methodURIDescriptionMaps to method
GET/systemReturns a list of systems.onList
POST/systemCreates a new system.onCreate
GET/system/3Retrieves details of system 3onRetrieve
PUT/system/4Updates existing system 4.onUpdate
DELETE/system/7Deletes existing system 7.onDelete

For example, performing an HTTP GET on /resources/system will map to the onList function in system.groovy. Performing an HTTP POST on /resource/system, with appropriate data provided as the payload, will trigger the function to create a new system record. That’s all there is to it; there is no configuration required to get started.

If, however, you wanted to use non-default mappings, you could accomplish this too by writing custom handler configurations in your zero.config configuration file and map those to your Groovy, PHP, or Java code.

Are you looking to test various HTTP operations against your system? The Firefox plug-in Poster is helpful for performing quick tests using operations like GET, POST, PUT, and DELETE against a URL that you specify.

At this point, you can test what you’ve done so far. Before starting your application for the first time, it’s useful to run zero resolve from the command line in the root directory of your application to make sure that your application’s dependencies have been resolved. Then, run zero start to start it up. Assuming your application is running locally and on the default port 8080, you can access your application at the default URL from a browser: http://localhost:8080/resources/system.

Using Table 1, you see that this URL maps to a list operation, onList. Your onList method is just a stub with some output to the browser. At this point, you should see the text This function will list systems in the database appear in the browser window.

Try performing a POST against your handler to see the response from the stub, as if you were trying to create a new entry in the database. At this point, you don’t need to worry about putting any payload into the HTTP request, as you haven’t yet included code to parse it.


Connecting to the back end

You now have the stubs for each of the operations in system.groovy, and you know how to invoke the various methods based on the URL and HTTP method you choose. The next task is to hook into the Address database’s legacy Java API from our Groovy handler. Let’s see how to tie this together.

First, put your Address database Java library JAR file into your WebSphere sMash application’s /lib directory so that you can access the classes from your code. Java JARs in the /lib directory are loaded automatically when the application starts up, so there is no need to adjust any classpaths manually.

For the purpose of this example, assume that the JAR file is called addressdb.jar, and that it contains a Java interface com.ibm.addressdb.Manager.class for connecting to and performing operations against the Address Database. The Manager interface is detailed in Listing 2 and the implementation (not shown) is contained in ManagerImpl.class. The JAR also defines a class com.ibm.addressdb.SystemDetails.class, which represents a system in the Address database application.

Listing 2. Manager interface
package com.ibm.addressdb;

import java.util.List;

public interface Manager {

	public abstract void logon(String username, String password) throws Exception;

	public abstract List<SystemDetails> listSystems();

	public abstract SystemDetails getSystem(int systemId) throws Exception;

	public abstract SystemDetails addSystem(SystemDetails newSystem) throws Exception;

	public abstract SystemDetails updateSystem(int sysId,
			SystemDetails system) throws Exception;

	public abstract int deleteSystem(int sysId) throws Exception;

}

To use these Java artifacts from your Groovy handler, include the corresponding Java import statements. Then you can use them seamlessly from your Groovy methods (Listing 3).

Listing 3. Building on system.groovy
import com.ibm.addressdb.Manager;
import com.ibm.addressdb.ManagerImpl;
import com.ibm.addressdb.SystemDetails;


def onList() { 
	
	Manager m = ManagerImpl.getInstance ()
	m.logon ('addressdbid@myorg.org','systempassword') 
	List list = m.listSystems ()  
	request.view='JSON'
	request.json.output=list
	render()
	
}

The onList method takes care of connecting to Address database through the Java API and returning a list of systems in JSON form. Be aware that the WebSphere sMash request handler framework automatically converts the List object that contains zero or more SystemDetails into a JSON array using the syntax shown. Make sure that your List type’s getters and setters follow JavaBean conventions in order to support this conversion. Listing 4 shows a sample response. Later, you'll see how to encode the password so that it doesn't appear in plain text in your code.

Listing 4. Response to listing request
[
{
"creatorId":"cloud1@myorg,com",
"ipAddress":"9.45.15.40",
"ownerId":"user1@myorg.com",
"systemId":"0",
"systemName":"financeServer"
}
{
"creatorId":"cloud1@myorg,com",
"ipAddress":"9.45.15.41",
"ownerId":"user2@myorg.com",
"systemId":"1",
"systemName":"hrServer"
}
]

Next, let’s look at how you would code the onCreate method for creating a new system record in your database. Here, you need to digest the contents of the POST that contains the system details and then populate them into the Java API. This is done by taking the contents of the HTTP POST and converting them into a JSON object. It’s then easy to reference the specific attributes that were passed in. Listing 5 shows some system parameters in the format they would appear in the POST request.

Listing 5. Sample of POST parameters for creation of system record
{
		"systemName":"auditServer", 
"ownerId":"user4@myorg.com", 
          	"ipAddress":“9.45.15.43" 
}

Listing 6 shows how you can easily pull the parameters out of the request and feed them into the Java API. Notice that you get the IP address, system name, and system’s owner name from the JSON object passed to your service.

For audit purposes, however, you also will want to identify the ID associated with making the request against your service. Remember that this is likely to be a service ID used by the system calling your service. To do this, you need to get the username of the authenticated user by retrieving the value from the global context. See the Global Context Reference to learn what is stored in it by default. Consulting the reference, you will see that the username of the logged-in user is found at /request/subject/remoteUser. You can retrieve a member from the global context by either executing the zget method with the path of the request as an argument:

zget (“/request/subject/remoteUser”)

or by calling an alternate syntax:

request.subject.remoteUser []

which will return the authenticated username. Going forward, the second syntax will be used for its simplicity.

Because there is no authentication currently set in your application, performing a retrieving the remoteUser at this point will return null. In the next section, you will see how to set up authentication and authorization rules using LDAP.

At the end of the onCreate method, you return an appropriate HTTP code following REST convention. If the creation is successful, you pass back an HTTP status code of 201, indicating success and that something was created. You also return the location of the new resource in the HTTP response header. For example, a new system might be located at this URI: http://localhost:8080/resources/system/3.

You can use this location to retrieve the ID of the newly created system, determine its ID and view its data. You will need to keep track of the system IDs locally so that you can perform future operations (retrieve, update, delete) on them, but for the purpose of this article, we’ll leave out management of that local database. The created element could be optionally returned, but it is not necessary and you chose not to include it.

Listing 7 shows code to retrieve a system, Listing 8 to delete a system and Listing 9 to create a system.

A few notes on the techniques used:

  • To convert a JSON string from the body of a POST or PUT into a JSON object, use the syntax:

    def systemInputs = zero.json.Json.decode(request.input[]);

    Then you can easily access the JSON object's members. See examples of this in onUpdate and onCreate.

  • As mentioned earlier, you can convert simple Java objects and collections (Lists, Maps, and so on) into JSON responses by using the WebSphere sMash request/response framework. This technique is illustrated at the end of the onRetrieve and onList methods. You don't need to manually convert the Java object into a JSON object.
  • For the methods that pull the system ID as URL parameters (onCreate, onRetrieve, onDelete and onUpdate), use the syntax:

    request.params.systemId[]

    to reference the URL parameter, then cast the parameter into an integer. The "systemId" portion is formed by the following convention: join the collection resource name that appears in your URL (in this case, "system") with the word "Id" to create "systemId."

  • Notice the HTTP return codes returned at the end of each of the methods, both in success and failure cases. They provide for a clean and succinct representation of the success of operations that have taken place in the API.
Listing 6. onCreate method for system.groovy
def onCreate() { 
		
	//Convert request entity to JSON object
	//then we can easily pull out the objects from it
	def systemInputs = zero.json.Json.decode(request.input[])
	
	SystemDetails newSystem = new SystemDetails ()
	
	newSystem.setIpAddress (systemInputs.ipAddress)
	newSystem.setSystemName (systemInputs.systemName)
	newSystem.setOwnerId (systemInputs.ownerId)
	
	String remoteUser = request.subject.remoteUser[]
	
	if (remoteUser == null) {
		
		remoteUser = 'none'
		//handle error...
	}
	
	newSystem.setCreatorId (remoteUser)
	
	
	
	Manager m =   ManagerImpl.getInstance ()
	m.logon ('addressdbid@myorg.org','systempassword')
	
	SystemDetails confirmedSystem = m.addSystem (newSystem)
	
	
	if (confirmedSystem !=null ) {
		// Set a Location header with URI to the new record
	    locationUri = getRequestedUri(false) + '/' + newSystem.getSystemId()
		request.status = HttpURLConnection.HTTP_CREATED

		
	}  else {
		
		//handle error
		request.status = HttpURLConnection.HTTP_INTERNAL_ERROR
		request.error.message = "system $requestSystemId not found."
        request.view = 'error'
        render()

	}

	
}
Listing 7. onRetrieve method for system.groovy
def onRetrieve() { 
	
	
	// Getting the system id of the system from the REST URL
	// Follows the convention of "collection item name" + "Id"

	def requestSystemId = Integer.parseInt(request.params.systemId[])
	
	Manager m = ManagerImpl.getInstance ()
	m.logon ('addressdbid@myorg.org','systempassword') 
	SystemDetails system = m.getSystem (requestSystemId)  
	
	String response = null
	
	if (system !=null ) {
		response = zero.json.Json.encode(system)
		request.json.output=response
		request.view='JSON'
		
		render()

		
	}  else {
		 // Error handling
        request.status = HttpURLConnection.HTTP_NOT_FOUND
        request.error.message = "system $requestSystemId not found."
        request.view = 'error'
        render()

		
	
	}	
	
}
Listing 8. onDelete method for system.groovy
def onDelete() { 
	
	def requestSystemId = Integer.parseInt(request.params.systemId[])
	
	Manager m = ManagerImpl.getInstance ()
	
	m.logon ('addressdbid@myorg.org','systempassword') 
	
	int deletedSystem = m.deleteSystem (requestSystemId)  
	
	if (deletedSystem >= 0  ) {
		request.status = HttpURLConnection.HTTP_NO_CONTENT

		
	}  else {
		
		 // Error handling
        request.status = HttpURLConnection.HTTP_NOT_FOUND
        request.error.message = "system $requestSystemId not found."
        request.view = 'error'
        render()

	}
	
}
Listing 9. onUpdate method for system.groovy
def onUpdate() { 
	
	

	def requestSystemId = Integer.parseInt(request.params.systemId[])
	
	
	Manager m = ManagerImpl.getInstance ()
	m.logon ('addressdbid@myorg.org','systempassword') 
	SystemDetails existingSystem = m.getSystem (requestSystemId)  
	SystemDetails confirmedSystem = null
	
	if (existingSystem!=null){ 
	
	
		//	Convert POSTED data to JSON object
		//then we can easily pull out the objects from it
		def systemInputs = zero.json.Json.decode(request.input[])
		
		
		existingSystem.setIpAddress (systemInputs.ipAddress)
		existingSystem.setSystemName (systemInputs.systemName)
		existingSystem.setOwnerId (systemInputs.ownerId)
		
		String remoteUser = request.subject.remoteUser[]
		
		if (remoteUser == null) {
			
			remoteUser = 'none'
			//handle error...
		}
		
		existingSystem.setCreatorId (remoteUser)
		
		
		confirmedSystem = m.updateSystem (requestSystemId, existingSystem)
	}       

	if (confirmedSystem !=null ) {

		request.status = HttpURLConnection.HTTP_NO_CONTENT

	}  else {
		
		 // Error handling
        request.status = HttpURLConnection.HTTP_NOT_FOUND
        request.error.message = "system $requestSystemId not found or could not be 
	updated."
        request.view = 'error'
        render()
	}
	

	
}

Securing your service

You now have the basics of your service complete, but it’s essential that you secure access to it. Not only do you need to know and register who is accessing the service, but you also want to make sure that only authorized systems or users can access it. Fortunately, WebSphere sMash is designed to make securing resources straightforward. Best of all, you can accomplish securing your application with a few lines of configuration.

Listing 10 illustrates the configuration that you would include in zero.config.

Listing 10. Security configuration
# Enable Security
@include "security/enableSecurity.config"

# Secret Key  - run "zero secretkey" CLI command to generate secret key
# Required whenever security is enabled in sMash
/config/security/secretKey = "xMgwl+sUzcsRBLb4tBkn5w=="

 

# Using the LDAP for authentication
/config/security/userservice/registryType="ldap"
 

### Inbound authorization to this wrapper
              
# LDAP related configuration 
/config/security/userservice/ldap += {
"jndiProviderUrl" : "ldaps://<serviceURL> /",
"jndiSecurityAuthentication" : "simple",
"ldapSearchScope" : 2,
"ldapUserIdSearchFilterPattern" : "(&(mail={0})(objectclass=person))",
"ldapUserIdBaseDn" : "ou=bluepages,o=<domain name>.com",
"ldapGroupBaseDn" : "ou=memberlist, ou=<groupdDN>,o=<domain name>.com",
"ldapUserIdAttributeType": "mail"
}

Let’s go through this configuration step by step:

  1. Enable security by referencing the security/enableSecurity.config configuration that’s included in the WebSphere sMash framework.
  2. To be able to use security within the context of your application, you need to generate a secret key. The secret key is used to encrypt confidential user data in the WebSphere sMash environment. You generate this from the Zero command line with the command zero secretkey. Once you have generated a secret key, you need to include it in your zero.config file. Listing 10 shows an example secret key.
  3. Choose how you want to authenticate users. You can include a list of users and passwords in your application, or you can hook into an LDAP directory. In this example, you will connect to LDAP, as indicated in this line:

    /config/security/userservice/registryType="ldap"

    For testing, you might want to use a file-based user registry. It's a snap to set up and is described in the WebSphere sMash documentation.

  4. Include the LDAP block that contains code specific to your enterprise’s LDAP server. You will need to customize this with specifics based on the LDAP service you want to use.
  5. The final portion of the configuration, included in Listing 11, indicates which resources you would like to secure and what type of authentication you want to use. Select basic authentication for this example. The configuration indicates that the path beginning with “/resources/” requires authorization. In other words, you've secured all assets under the resource directory rather than your whole application. Imagine that you had some documentation in your application’s public directory that you wanted anyone to be able to access. Using this security configuration wouldn’t secure the public directory because the /public doesn't fall under the /resource/ path in the WebSphere sMash directory structure.

    Notice that conditions for requiring authorization are even more granular. In this example, the application will require authorization for all operations, POST, PUT and DELETE, but not GET, on the system.groovy resource. However, you could just as easily have included HTTP GET operations. We will demonstrate this later on.

  6. Lastly, you have specified an LDAP group, Address-Database-Wrapper-Users, to which you are allowing access. Users who do not belong to this group will not be able to access the service.
    Listing 11. Securing resources
    #uses group discovered through LDAP authentication.
    @include "security/basicAuthentication.config"{
       "conditions": "(/request/path =~ /resources (/.*)?) && 
    	(/request/method =~ (POST| PUT|DELETE)) "
      "groups" :["Address-Database-Wrapper-Users"]   
    }
  7. Restart your application and try performing a GET or POST to http://localhost:8080/resources/system. You will be prompted to authenticate.

Basic authentication is easy to implement, so it is popular for prototypes and situational applications. It's also easy to use for system-to-system scenarios like the one described here. It has some drawbacks, including the aesthetics of the pop-up username and password dialog box that is tied to the browser's implementation. Also, because the browser caches the username and password basic authorization, there is no way to flush it. As a result, logout isn't easily supported. The user needs to close the browser to log out of the application.

For more robust and customizable authentication handling and a smoother user experience, you might want to use form-based authentication instead. We won’t go into form-based authentication in detail here, but the WebSphere sMash framework supports this as well.

Securing the connection with HTTPS

Since you are requiring usernames and passwords, securing the connection using HTTPS is a must in production. You can use a self-signed certificate for development purposes, and WebSphere sMash even includes a test self-signed certificate in the zero.core.webtools component.

To enable HTTPS, you specify a few things in your zero.config file, as shown in Listing 12. Notice that the keystore password is prefixed with "<xor>." This syntax means that the password has been encoded to prevent it from being exposed in plaintext in the configuration file.

This would also be a good time to go back and encode the password to your back end API that you had included in plaintext in groovy.system. Use the XOREncode utility (see Resources) to do this. Also, check out the WebSphere sMash documentation on leveraging XOR encoding in your applications.

Listing 12. Basic HTTPS enablement - inbound
/config/https/port = 8443
/config/https/sslconfig = {
        "keyStore": "./config/key.jks",
        "keyStorePassword": "<xor>JTotMC8+LCw="

’,
        "keyStoreType": "JKS"
}

Configuration files

Let’s take a look some additional settings regarding configuration.

With WebSphere sMash you should always set a context root for your application. This helps you ensure the portability of your application and that you haven't coded under the assumption that your application resources are at the root “/”. It also adds a descriptive nature to URLs in your application. Here is an example of the configuration settings that are needed to set this up in WebSphere sMash:

/config/contextRoot="/addressdb"

With this property set, the base URL of your application changes. While previously you had http://localhost:8080/resources/system, you will now use http://localhost:8080/addressdb/resources/system.

So far, you’ve seen a number of settings that need to be made in a configuration file. By default, WebSphere sMash looks for the configuration file named zero.config. But zero.config can start to get unruly as the configuration grows. There are couple of features in WebSphere sMash that can help avoid this.

Config file includes

One config file can include another. Check out Listing 13 for an example that shows moving your security configuration out to its own file. You might notice that you saw an example of this earlier when you set up security for the application. You included a base WebSphere sMash configuration file to enable security. You can adopt the same method for our own files.

In Listing 13, the username and passwords were added to the configuration to connect to the Address Database so that you can remove the literal values from the code you wrote earlier (Listings 3, 6, 7, 8 and 9). The actual password "systempassword" is encoded using the XOR API described earlier so that it is obfuscated; it can't be read by another user who views the config file. To reference these configuration values in your code, use the same syntax you used for obtaining the remote user. In this case, to retrieve the username use config.addressDB.username[].

Listing 13. Including configuration files
Contents of zero.config:

…
@include "addressDBSecurity.config"
…


Contents of config/addressDBSecurity.config:
….
#default logon ID and password to access backend Address Database
/config/addressDB/username="addressdbid@myorg.org"
/config/addressDB/password=<xor>df3533wsKG8tOw==


# Enable Security
@include "security/enableSecurity.config"

# Secret Key  - run "zero secretkey" CLI command to generate secret key
 
/config/security/secretKey = "xMgwl+sUzcsRBLb4tBkn5w==""

...

Configuration overrides

It's common that you would want to include a config file to help organize your configuration. Sometimes, it's also convenient to override certain attributes contained in the file you are including. WebSphere sMash handles this requirement gracefully. Consider an example: suppose when you are testing your application, you want to use a test username and password to connect to the back end Address Database rather than the default. Listing 14 shows how your zero.config would look to achieve this. In this listing, you are overriding the default username and password that you provided in addressDBSecurity.config.

Listing 14. Overriding the matching rule
Contents of zero.config

…
@include "addressDBSecurity.config"   
#override the username and password used to connect to the backend Address Database.
/config/addressDB/username ="test-addressdbid@myorg.org"
/config/addressDB/password="<xor>MiYvPiwsKG8tOw=="

Again, this mimics a technique you saw earlier when you first set authentication on the resource in Listing 11. In Listing 14, you’re building on the configuration in Listing 13. You moved your entire security configuration to addressDBSecurity.config. When you invoke the include, you’re specifying that you wish to override the basic authentication settings that are in place in addressDBSecurity.config so as not to require authentication on “GET” requests.


Debugging techniques

When both enabling security and connecting to vendor services, it’s sometimes helpful to enable additional tracing. The requestLogging service is helpful in tracing requests against your service. Each request is logged into an individual file and contains valuable information. Also, you might find that you need an additional trace on specific components. Listing 15 shows a sample logging configuration.

Listing 15. Sample logging configuration
#Enable the logging
/config/requestLogging = true

# Enable fine detail on certain components.
/config/logging/levels = {
    "zero.core.config" : "FINE",
    "zero.core.security" : "FINEST"
}

Make sure to disable or reduce logging when you move your application to production, as logging always adds a performance overhead and detailed trace logs tend to grow quickly and can flood your available disk space.

For other valuable recommendations for tuning as you move your application to production, see projectzero.org.


Conclusion

Part 2 of this series explained how WebSphere sMash was used to build a RESTful API wrapper around some legacy Java tools to wrap external systems management applications, and examined more ways in which the conventions of the WebSphere sMash programming model can be used to support rapid application development.

Part 3 will conclude this series with a look at the capabilities within WebSphere sMash to create workflows using visual tools, and how to include them in your applications.


Acknowledgements

The authors thank Natasha Sharma for her work on our implementation of the service described in this document, and to Steve Ims, IBM STSM, for his valuable feedback and attention to detail in reviewing these articles.

Resources

Learn

Get products and technologies

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 WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere, Web development
ArticleID=500170
ArticleTitle=Innovative uses for WebSphere sMash, Part 2: Automate enterprise operations through a cloud by wrapping management tools for external systems
publish-date=07142010