Establish a policy-driven SOA using WebSphere Service Registry and Repository and WebSphere ESB

The WS-Policy specification provides a simple language for expressing policies supported by Web services. IBM® WebSphere® Service Registry and Repository supports loading, changing, and retrieving policy documents, and also supports using policy attachments to link a given policy with a service. This can then be used by a run time component, like an Enterprise Service Bus, to retrieve defined policies for a particular service or operation and act accordingly. This article shows how you can utilize standard WS-Policy documents stored in a registry to impact run time behavior in an ESB -- and then change that behavior on the fly with no code changes or redeployment. This content is part of the IBM WebSphere Developer Technical Journal.

Share:

Andre Tost (andretost@us.ibm.com), Senior Technical Staff Member, IBM

Andre TostAndre Tost works as a Senior Technical Staff Member in the IBM Software Services for WebSphere organization, where he helps IBM customers establishing Service-Oriented Architectures. His special focus is on Web services and Enterprise Service Bus technology. Before his current assignment, he spent ten years in various partner enablement, development and architecture roles in IBM software development, most recently for the WebSphere Business Development group. Originally from Germany, Andre now lives and works in Rochester, Minnesota. In his spare time, he likes to spend time with his family and play and watch soccer whenever possible.


developerWorks Master author
        level

08 October 2008

Also available in Chinese Japanese

Introduction

One of the goals of leveraging an Enterprise Service Bus (ESB) is separation of concerns. Service logic can be implemented with a focus on business relevant concerns, and more technically-oriented logic can be implemented in the ESB, among other places.

Moreover, this ”integration” logic can be created in a way that makes it easier to adapt to ever changing requirements by enabling you to define its behavior externally. A service registry, which supports storing and retrieving standards-based policies, can be positioned as a policy decision point, with the ESB then performing the policy enforcement.

This article describes how you can implement a mediation in IBM WebSphere ESB that retrieves policy information to make run time decisions, following the WS-Policy standard from IBM WebSphere Service Registry and Repository (hereafter referred to as Service Registry). The example described here is very basic, but can easily be extended to cover more complex scenarios and policies.


What is a policy?

The term policy is somewhat overloaded and is being used in many different contexts, even when looking at how it’s used in just the world of IT systems. What is described in this article are policies that apply to a Web service. Even more specifically, we are talking about policies that are expressed in a standard language, namely WS-Policy (see Resources for more about this and other standards).

In a nutshell, the WS-Policy standard gives you a language for describing policies in XML. Each policy consists of one or more policy assertions. These assertions do not really follow any predefined format, other than the fact that they use XML and are embedded in an element called <Policy>. For example, this code segment shows an “audit” policy:

Listing 1
<wsp:Policy xmlns:wsp="http://www.w3.org/2006/07/ws-policy">
  <Audit/>
  </wsp:Policy>

You could say that the example above is pretty much the most basic policy possible, as it only consists of one policy assertion called Audit.

Besides defining the <Policy> element, the WS-Policy standard describes how to create policies that consist of more than one policy assertion, and how to define which or if all assertions must be met, to name one example. For this purpose, the standard provides two additional elements, named <All> and <ExactlyOne>. Moreover, it lets you refer to another policy via the <PolicyReference> element. And that’s it! The specification only defines four elements, plus one attribute called Optional.

The details of how to combine policy assertions is beyond the scope of this article, but the point is that WS-Policy is a relatively open language that only defines a very basic set of elements.

A set of additional specifications exists that applies the WS-Policy language to a particular domain. For example, the WS-SecurityPolicy specification defines a set of policy assertions that are used to define security-related policies; the WS-AtomicTransaction specification defines policies to describe the transactional behavior of a service, and so on.

WS-Policy and WSDL

One main use case for policies is to describe the capabilities or requirements of a Web service provider. We can reuse the examples above: with WS-Policy, you can indicate that a Web service request message must be encrypted, or you can define that a transactional context must be flowed along with it, or you can simply indicate a certain behavior of your service. For example, the Audit policy might be used to indicate that all messages sent to a service are logged for auditing purposes.

So how do you associate a policy with a Web service? You can add them to your WSDL definitions:

  • WS-Policy elements can be added directly to the WSDL, and they are then associated with the WSDL element they are in. This enables scoping a policy to just one operation, or even to just one message within the service, or to the entire service.
  • WS-Policy elements that are defined in an external file can be referred to from within the WSDL by using the <PolicyReference> element.

Adding a policy to your WSDL definitions means that the policy is then part of the WSDL in which it is defined. Changes to a policy require the WSDL file to be changed. Policy assertions cannot easily be reused across multiple services without copying them into every WSDL in which they are used. To address this, you can utilize an additional standard, WS-PolicyAttachment, which defines a way of linking elements of a WSDL definition with a policy without requiring a change to either one of them. Essentially, you create a document that contains a link to an existing WSDL definition, as well as a policy definition. Alternatively -- and this is the approach used in the example below -- the attachment can also contain a link to an existing policy document, instead of the policy definition itself.

Figure 1 shows an example of a PolicyAttachment linking a service definition in WSDL with a policy. In this example, all three parts exist in separate files and can therefore be developed and maintained separately.

Figure 1. A policy attachment links a policy with a WSDL definition
Figure 1. A policy attachment links a policy with a WSDL definition

Procedure interoperability
Tools and run time products from different vendors might not support all of the styles of connecting policy information with service definitions as described here. This example works with the WebSphere set of products, but might require changes if ported to a different environment.

WS-Policy and WS-PolicyAttachment definitions in Service Registry

WebSphere Service Registry and Repository supports the loading, retrieving, and editing of policies and policy attachments. Policy definitions contained in WSDL are detected and parsed automatically when a new WSDL file is loaded. Upon loading of any WSDL, the registry creates a set of logical objects representing the different parts of the service definition, and the included policies are just another part of that.

Beyond that, you can load XML files containing WS-Policy or WS-PolicyAttachment compliant definitions. These documents will also be parsed and the appropriate set of logical objects will be created.

One thing not yet shown here is how a policy attachment can link to a service definition on one hand, and link to a policy on the other hand, when both are loaded in the registry as separate files.

A policy attachment uses the <AppliesTo> element to “point to” the right service element. For attachments loaded into Service Registry, you can specify a Service Registry-specific query that selects the appropriate element. Here is an example for what this looks like:

Listing 2
<wsp:PolicyAttachment ...>
	<wsp:AppliesTo>
		<wsrr:PolicySubjectQuery
			wsrr:xpath="/WSRR/WSDLService[matches(@name, 'IBM.*')]">
		</wsrr:PolicySubjectQuery>
	</wsp:AppliesTo>
	<wsp:PolicyReference URI="..."/>
</wsp:PolicyAttachment>

The <AppliesTo> element in the listing above points to all service definitions stored in Service Registry that have names starting with "IBM." The xpath attribute within the <wsp:PolicySubjectQuery> element lets you select the service element the policy applies to.

The <PolicyReference> element contains an attribute called URI, which refers to the policy definition. In the case of Service Registry, the attribute relates to the Name attribute in the <Policy> element (the WS-Policy specification does not define how you refer to a policy definition that resides in a separate file). Thus, a policy definition that looks like this:

Listing 3
<wsp:Policy xmlns:wsp="http://www.w3.org/2006/07/ws-policy"
            Name="http://www.ibm.com/samples/mypolicy">
  ...
</wsp:Policy>

can be referenced in an attachment like this:

Listing 4
<wsp:PolicyReference xmlns:wsp="http://www.w3.org/2006/07/ws-policy"
              URI="http://www.ibm.com/samples/mypolicy"/>

Again, the syntax of the reference differs depending on the environment you use; this example works when using Service Registry. See the Service Registry Information Center for details about how to load and edit policy documents.


Querying Service Registry from within a mediation flow component

Now that you have seen how to link policies and service definitions in Service Registry, you need to see how you can retrieve this information at run time. After all, you want to leverage these definitions to influence the behavior of the ESB.

Creating a SOAP API proxy

Service Registry offers a variety of APIs that enable programmatic access to its content. There is a Java™ API, a Web services API, an EJB API, and a REST API. So which one do you use when accessing the registry from within WebSphere ESB?

One obvious choice, namely the Java API (represented by a set of JAR files containing a client Java proxy), includes an implementation of the SDO standard, which is incompatible with the SDO implementation that is included in WebSphere ESB. Using this API, therefore, will result in class version conflicts.

The EJB API requires configuring the WebSphere ESB mediation module as an EJB client to the registry. This might not be a straightforward and simple activity, depending on the operational environments in which both products are running.

The REST API is another valid option, but there is no simple way of programming this API from within Java code. For example, you cannot easily generate a Java proxy that encapsulates this API and makes it accessible to a Java client.

Which leaves us with the SOAP API. The registry is fully accessible via its Web services interface, and it exposes a set of WSDL and XML Schema definitions that you can use to generate a JAX-RPC-based proxy.

You can retrieve the WSDL definition for the core API that will be used for the remainder of this article at http://[hostname]:[portnumber]/WSRR6_2/services/WSRRCoreSDOPort?wsdl. You can then use the WSDL2Java utility that comes with each copy of WebSphere Application Server, WebSphere ESB, or WebSphere Integration Developer to generate a client proxy and related classes and interfaces. However, you need to turn on the allowRelativeNamespace option when using this utility. Assuming that you have Service Registry installed on the local machine on port 9080, here is what the call looks like:

Listing 5
WSDL2Java -r client -properties allowRelativeNamespace=true 
http://localhost:9084/WSRR6_2/services/WSRRCoreSDOPort?wsdl

This call will create all of the Java classes and interfaces you need. You can then import them into a Java project in WebSphere Integration Developer, thereby making them available to any mediation you develop there.

Similarly, you can also do this in WebSphere Integration Developer by importing the WSDL file (including its dependent schemas) and use the Web services wizards in the tool to generate the client package. In WebSphere Integration Developer, know that you also need to set the allowRelativeNamespace option via the Preferences window, as shown in Figure 2.

Figure 2. Setting the allowRelativeNamespace option in WebSphere Integration Developer
Figure 2. Setting the allowRelativeNamespace option in WebSphere Integration Developer

In your client code, you now need to obtain an instance of the client proxy. The code segment below shows an example of what that looks like (all the code shown in this article is available in the download file included with this article, along with a fully operational sample).

Listing 6
import 
   com.ibm.www.xmlns.prod.serviceregistry._6._2.ws.sdo.WSRRCoreSDOServiceLocator;
import 
   com.ibm.www.xmlns.prod.serviceregistry._6._2.ws.sdo.portType.WSRRCoreSDOPortType;

...

java.net.URL url = new java.net.URL(
   "http://localhost:9080/WSRR6_2/services/WSRRCoreSDOPort");

WSRRCoreSDOPortType port = 
new WSRRCoreSDOServiceLocator().getWSRRCoreSDOPort(url);
...

You need to adjust the URL used in the code for the hostname and port number of your installed Service Registry instance.

Service Registry security

If your Service Registry is running in secure mode, you need to add additional code to establish a connection between your client and the registry. You need to define a key store filename and password, as well as a trust store filename and password, as shown here:

Listing 7
System.setProperty("javax.net.ssl.trustStore","C:\\WebSphere\\AppServer\\profiles\\
	AppSrv03\\etc\\trust.p12");

System.setProperty("javax.net.ssl.trustStorePassword","WebAS");

System.setProperty("javax.net.ssl.keyStore","C:\\WebSphere\\AppServer\\profiles\\
	AppSrv03\\etc\\key.p12");
System.setProperty("javax.net.ssl.keyStorePassword","WebAS");

java.net.URL url = new java.net.URL(
   "http://localhost:9080/WSRR6_2/services/WSRRCoreSDOPort");

WSRRCoreSDOPortType port = 
new WSRRCoreSDOServiceLocator().getWSRRCoreSDOPort(url);

The file location and password used above are just examples, which you have to change to fit your own runtime environment. Moreover, once you have obtained an instance of the proxy, you have to set a valid user ID and password on the stub, like this:

Listing 8
((javax.xml.rpc.Stub)port)._setProperty(javax.xml.rpc.Stub.USERNAME_PROPERTY,"admin");
((javax.xml.rpc.Stub)port)._setProperty(javax.xml.rpc.Stub.PASSWORD_PROPERTY,"admin");
...

And again, the values used above (admin/admin) are just examples.

Querying policy documents

To use the proxy instance you retrieved in the code above, you have to prepare a query object and insert it into a datagraph that is sent to the registry. This code shows how to set this up:

Listing 9
import sdo.commonj.DataGraphType;
import com.ibm.www.xmlns.prod.serviceregistry._6._0.sdo.BaseObject;
import com.ibm.www.xmlns.prod.serviceregistry._6._0.sdo.GraphQuery;
import com.ibm.www.xmlns.prod.serviceregistry._6._0.sdo.WSRR;
...
GraphQuery query = new GraphQuery();
query.setDepth(-1);
query.setBsrURI("_1");
DataGraphType dg = new DataGraphType();
WSRR wsrr = new WSRR();
BaseObject[] artefacts = new BaseObject[] {query};
wsrr.setArtefacts(artefacts);
wsrr.setRoot("_1");
dg.setWSRR(wsrr);

Finally, you need to set the query string that you will execute on the registry. In this case, of course, you want to query policy documents that apply to a certain part of your service. This query is closely related to how the policy was attached to the service. The following query statement will return all PolicyDocument objects, regardless of whether or not they are attached to any service:

Listing 10
query.setQueryExpression("/WSRR/PolicyDocument");

As another example, the next query returns all PolicyAttachment objects that have been applied to a service starting with the name "IBM" (which is what we used in the earlier example for the <AppliesTo> element):

Listing 11
query.setQueryExpression(	
   "/WSRR/PolicyAttachment[appliesTo(.)/WSDLService[matches(@name, 'IBM.*')]]");

If you want to test your query expressions before inserting them into the code, you can use the Service Registry REST interface. For example, you can enter this URL into the address field of your browser:

Listing 12
http://localhost:9080/WSRR/6.2/Metadata/XML/GraphQuery?query=/WSRR/PolicyAttachment
[appliesTo(.)/WSDLService [matches(@name, ‘BM.*’]]

This will return any policy attachments satisfying the query criteria right in the browser window. By replacing the part of the expression after ”query=“ in the string above, you can experiment further with different types of queries, which is most likely simpler than testing it in your code.


An example

So far, you have seen how to define policies, attach them with a service, and load them into the registry. You have also seen how to generate a SOAP client to the registry and use it to query and retrieve policy and policy attachment information. You now get to put these two together in an example that shows how to create a WebSphere ESB mediation that makes run time decisions based on defined policies for a service.

Name and namespace

The mediation you create will make decisions based on defined policies. Policies can be scoped to various elements of a service definition; for example, to an operation, a message, a particular port, or the entire service. All of these elements have a name and a namespace that makes them identifiable. Assume you want to query for a policy that has been attached to a certain operation. You need to add the name and namespace of that operation to the query string, which would look like this:

Listing 13
/WSRR/PolicyAttachment[appliesTo(.)[(@name='TheOperation') and
		(@namespace='http://mynamespace')]]

In this example, the operation and namespace names are hardcoded, but you should use parameters for these values if you want to create a mediation that is reusable across multiple services and operations. WebSphere ESB does not yet offer an API that enables you to retrieve the service name and operation name of the currently executing flow. Therefore, the only option to obtain the values used for the query dynamic is to introduce user-defined properties to the mediation primitive.

Assumptions
This article assumes familiarity with building mediation modules and mediation flow components for WebSphere ESB. In lieu of detailed steps, this article describes how the solution was built so you will have enough information to build a similar solution of your own. Alternatively, you can import the Project Interchange file provided with this article into WebSphere Integration Developer and deploy and test it there. WebSphere Integration Developer and WebSphere ESB V6.1.2, and Service Registry V6.2 (the latest versions at this writing) were used to create this example.

Putting it all together

  1. To keep things simple, you can use a publicly available temperature conversion service for this example. Retrieve its WSDL service definition and import the WSDL into a new mediation module so that you can associate it with your mediation. Also load this WSDL into the registry.

  2. The Temperature Converter service has an operation called CelciusToFahrenheit. To define a policy that calls for auditing and attach it to this operation, you first create a file called audit.xml, which has this content:

    Listing 14
    <wsp:Policy xmlns:wsp="http://www.w3.org/2006/07/ws-policy"
                xmlns:tns="http://www.ibm.com/samples" 
                Name="http://www.ibm.com/samples/auditpolicy">
       <tns:Audit/>
       </wsp:Policy>

    Load this policy document into the registry.

  3. Next, create a file called auditattachment.xml, which contains this attachment code:

    Listing 15
    <wsp:PolicyAttachment xmlns:wsp="http://www.w3.org/2006/07/ws-policy"
    	xmlns:wsrr="http://www.ibm.com/xmlns/prod/serviceregistry/6/2/wspolicy"
                xmlns="http://www.ibm.com/samples">
       <wsp:AppliesTo>
         <wsrr:PolicySubjectQuery 
      wsrr:xpath="/WSRR/WSDLPortType[@name='TemperatureConversionsSoapType' and 
    	@namespace='http://webservices.daehosting.com/temperature']/
    	operations[@name='CelciusToFahrenheit']"/>
       </wsp:AppliesTo>
       <wsp:PolicyReference URI="http://www.ibm.com/samples/auditpolicy"/>
       </wsp:PolicyAttachment>

    Notice the value of the xpath attribute in the <AppliesTo> element, stating that the referenced policy applies to an operation named CelciusToFahrenheit in a port type named TemperatureConversionSoapType, which is in the http://webservices.daehosting.com/temperature namespace. You will see later how the policy query you execute in the mediation directly relates to this.

  4. After you have loaded the attachment file into the registry, you should be able to navigate to the attachment in the Service Registry admin console (Figure 3).

    Figure 3. The policy attachment in the WSRR admin console
    Figure 3. The policy attachment in the WSRR admin console
  5. When you click on the Graphical View for the attachment, it becomes clear that it is linking the CelciusToFahrenheit operation with the Audit policy (Figure 4).

    Figure 4. Graphical View of the policy attachment
    Figure 4. Graphical View of the policy attachment
  6. In the mediation module, create a simple assembly with a SOAP/HTTP export for testing, the mediation flow component performing the policy lookup, and the import to the Temperature Converter service (Figure 5).

    Figure 5. Assembly for the policy mediation module
    Figure 5. Assembly for the policy mediation module
  7. In the PolicyMediation component implementation, you only add specific functionality to the request flow of the CelciusToFahrenheit operation, which looks Figure 6.

    Figure 6. Mediation flow component
    Figure 6. Mediation flow component

Notice that a custom mediation primitive called PolicyRetrieval was added here. This primitive has two output terminals, one of them wired directly to the callout node, the other wired to a message logger primitive called MessageLogger. In essence, if the message is fired on the first output terminal of the custom mediation primitive, it is not logged, whereas if it is fired on the second terminal, it is logged to a database.

The custom mediation primitive uses a Java utility class called PolicyQueryTest, which encapsulates the registry proxy code explained above:

Listing 16
try { 
 PolicyQueryTest pq = new PolicyQueryTest();
 pq.init(WSRRPortURL);
 if (pq.hasPolicyDefined(PolicyQueryTest.AUDIT_POLICY_NAME, 
                                      operationNamespace, operationName))
 	auditOut.fire(smo);
 else
 	out.fire(smo);	
} catch (Exception x) {
	System.out.println("Exception during policy query : "+x.getMessage());
	throw new ServiceRuntimeException(x);
	}

The listing above shows how the message is fired on the auditOut terminal if the policy for auditing is found in the registry. This terminal is wired to the MessageAudit primitive shown above. The PolicyQueryTest class uses the following query string to find out if the audit policy was defined for this operation:

Listing 17
query.setQueryExpression(
      "/WSRR/PolicyAttachment[appliesTo(.)[(@name='"+operationName+"') and 
      (@namespace='"+namespace+"')]]");

The code then parses the returned response message to find out if the policy attachment indeed references the Audit policy. (This code is not shown here.)

You can further experiment with this code by changing the policy content via the Service Registry admin console. For example, if you change the defined policy element to contain an element called <NoAudit>, the mediation will not find the expected policy, and it will fire the message on the terminal directly wired to the Callout node, and thus the message will not be logged.

You can see how using this mechanism enables you to influence the behavior of the ESB, and how it handles incoming requests based on policy definitions you store in the registry.


Summary

This article showed that WS-Policy provides you with a simple language for expressing policies supported by Web services. And while many additional standards expand this language to address different domains, like security, you can also define your own custom policies.

WebSphere Service Registry and Repository supports loading, changing, and retrieving policy documents. It also supports using policy attachments to link a given policy with a service. This can then be used by a run time component, like an Enterprise Service Bus, to retrieve defined policies for a particular service or operation and act accordingly. One way of adding the required custom logic to your runtime is to generate a JAX-RPC based SOAP proxy.

Finally, this article showed an example of how this proxy can be leveraged in a mediation flow component running in WebSphere ESB. The example checked whether or not the Audit policy was defined for an operation, and, if so, it made sure the request message was logged.

This serves as a basic example for showing how to utilize standard WS-Policy documents stored in a registry to impact run time behavior in an ESB. This behavior can now be changed on the fly by changing the policy in the registry, and no code changes or redeployment of code is required.


Acknowledgements

The author thanks Laura Olson from the IBM Software Group Worldwide Technical Sales team for her help with this article.


Download

DescriptionNameSize
Code samplePolicyMediationExample.zip285 KB

Resources

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 Business process management on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Business process management, WebSphere, SOA and web services
ArticleID=343979
ArticleTitle=Establish a policy-driven SOA using WebSphere Service Registry and Repository and WebSphere ESB
publish-date=10082008