December 2007 - Posts
Lately, I've been spending some time working with SQL Server 2008. There are a lot of innovative features included in the latest CTP on both the DB and BI engines that are worth checking. I plan to keep blogging about it during the next weeks. On this post I want to focus on what is arguably the biggest improvement on Service Broker (SSB) 2008: conversation priorities.
On the SSB context, Conversation priorities are a set of user-defined rules, each of which specifies a priority level and the criteria for determining which Service Broker conversations to assign the priority level. Normally priority levels determine the order on which messages are sent or receive.
Message queuing prioritization is not exactly a new concept. All the major queued based technologies introduce some level of controlling priorities at the message level. By "at the message level" we mean that given the architecture of most queuing technologies in the market priorities are typically limited only to messages. For instance, technologies like MSMQ or WebSphere MQ assign priorities to messages in order to control the order in which messages are sent or received. What makes service broker approach to this problem unique is the fact that priorities are not only based on messages but also on contract and services.
As part of the current CTP you can use a new Transact-SQL command CREATE BROKER PRIORITY with the following arguments:
- A name for the conversation priority.
- A priority level to assign Service Broker conversations. The levels are specified as integers from 1 (lowest) to 10 (highest). The default is 5.
- The criteria that determine which conversations the priority level applies to the following:
- A contract name or ANY.
- A local service name or ANY.
- A remote service name or ANY.
When an application attempts to receive or send a message, SSB evaluates the priorities based on the best match for the existing local service, remote service and contract. By "best match" we mean that depending on the services and contract involve in a conversation SSB can find multiple priorities that can be applied. For instance, assume a SSB configuration with the following conversation priorities:
- Priority1(Service1, Service2, Contract1)
- Priority2(Service1,ANY,ANY)
Based on that configuration, a conversation between Service1 and Service2 based on contract1 match both priorities, however Priotity1 represents a better match compared with Priority2.
Let's take a look to a more complete example of how to use conversation priorities.
Assume that we have the following SSB configuration with three SSB services. Notice that TargetService1 and TargetService2 share the same physical queue.
|
create queue RequestQueue
create queue ResponseQueue
CREATE MESSAGE TYPE
[RequestMsgType]
VALIDATION = WELL_FORMED_XML ;
CREATE MESSAGE TYPE
[ResponseMsgType]
VALIDATION = WELL_FORMED_XML ;
CREATE CONTRACT
[TestContract]
( [RequestMsgType]
SENT BY INITIATOR,
[ResponseMsgType]
SENT BY TARGET
) ;
CREATE SERVICE InitService
on queue RequestQueue
(TestContract);
CREATE SERVICE TargetService
on queue ResponseQueue
(TestContract);
CREATE SERVICE TargetService2
on queue ResponseQueue
(TestContract); |
In this sample InitService needs to establish conversations with TargetService1 and TargetService2. However, the messages delivered to TargetService2 should take priority over the messages delivered to TargetService1. In order to model the priorities we need to use the CREATE BROKER PRIORITY command assigning a higher priority to the conversation that includes TargetService2.
|
CREATE BROKER PRIORITY Priority1
FOR CONVERSATION
SET (CONTRACT_NAME = TestContract,
LOCAL_SERVICE_NAME = TargetService,
REMOTE_SERVICE_NAME = N'InitService',
PRIORITY_LEVEL = 1);
CREATE BROKER PRIORITY Priority2
FOR CONVERSATION
SET (CONTRACT_NAME = TestContract,
LOCAL_SERVICE_NAME = TargetService2,
REMOTE_SERVICE_NAME = N'InitService',
PRIORITY_LEVEL = 10); |
The following command initiates and sends a message on the conversation with a lower priority and then it repeat the same operations for the conversation with higher priority. Finally, we execute a read statement to receive the messages from the target queue.
|
DECLARE @dialog_handle UNIQUEIDENTIFIER ;
DECLARE @msg xml
set @msg= '<msg>msg1</msg>'
BEGIN DIALOG CONVERSATION @dialog_handle
FROM SERVICE [InitService]
TO SERVICE 'TargetService'
ON CONTRACT [TestContract]
WITH ENCRYPTION = OFF ;
SEND ON CONVERSATION @dialog_handle
MESSAGE TYPE [RequestMsgType]
(@msg) ;
set @msg= '<msg>msg2</msg>'
BEGIN DIALOG CONVERSATION @dialog_handle
FROM SERVICE [InitService]
TO SERVICE 'TargetService2'
ON CONTRACT [TestContract]
WITH ENCRYPTION = OFF ;
SEND ON CONVERSATION @dialog_handle
MESSAGE TYPE [RequestMsgType]
(@msg) ;
WAITFOR
(
RECEIVE cast(message_body as xml ) from ResponseQueue
) |
If we use this application without SSB priorities the messages will be received from the ResponseQueue queue in the same order they were sent. However the use of priorities forces the SSB engine to reorganize the order in which messages are read. In the context of our sample, given that the second message is associated with a conversation with higher priority, the receive statement will produce the following output.
<msg>msg2</msg>
As you can see, the messages were received based on the conversation priorities level.
Although this is a very basic sample I hope it will give you an idea of the scenario on which we can apply conversation priorities on existing SSB applications.
SharePoint Server 2007 SP1 is now available. Among other features it includes integration with ASP.NET AJAX 1.0 and support for custom HTTP and SOAP headers with Business Data Catalog entity models.
Message routing is one of the most used and attractive features of Enterprise Service Buses (ESB). Unfortunately, the traditional view of message routing, most of the times, is reduced exclusively to service orchestration and choreography scenarios. In my opinion, the use of routing is also a fundamental technique for achieving another emerging architecture style of service orientation: service composition. Among the ESBs on the market, Oracle ESB provides a very simple and elegant solution for composing services using routing. The core of this solution is based on one of the fundamental components of Oracle ESB: routing services.
Routing Services are the key component for moving a message across the enterprise service bus - from its entry point to its exit point. Once deployed routing services expose native SOAP interfaces describe it on WSDL so that they can be reuse from any Web Services technology.
ESB as an Architecture pattern is fundamentally based on message mediation. Specifically, ESB-style applications are focused on routing and translating messages between different endpoints that are typically abstracted thru services definition. These services are often registered in some sort of metadata repository so that they can be accessible to multiple applications. Having the infrastructure for routing and transformation together with the repository for storing and cataloging service metadata makes ESBs an ideal candidate for the implementation of composite services; these are services that are create combining operation from other services. However, building composite services still represents a challenge for most of the ESBs in the market. This is mostly given to the fact that most ESBs don't provide a transparent way to express the routing logic into new services that can be consumed by other applications. Instead, developers find themselves trying to implement services that behind the scenes utilize the routing capabilities built into the ESB engine. In the case of Oracle ESB, routing services are first class citizens in the programming model and can be reused by other technologies of the Oracle SOA suite such as Oracle BPEL Process Manager or Oracle Registry.
The fact that the routing logic is now exposed as reusable services opens the door for very creative solutions. For instance, routing services (as any other message brokering pattern) can be used to enhance the interoperability for services whose native implementation are hardly interoperable. For instance, a routing service can be used to provide an interoperable contract for a Windows Communication Foundation (WCF) service that expects a native .NET data type as a parameter. Service composition is another of the SOA scenarios that can be extremely benefited from the use of routing services. Just to give an example, routing services can be used to provide a unified contract for multiple services that can be implemented in complete different technologies.
In order to illustrate some of these concepts let's take the following two services that have been implemented using WCF and Sun WSIT respectively. Both services implement mathematical operations that can be composite into a single contract using Oracle ESB.
WCF Service
The WCF implements a very simple contract with only one operation that adds two numbers.
|
[ServiceContract]
public interface IMathWS
{
[OperationContract]
int Add(int param1, int param2);
}
[ServiceBehavior(AddressFilterMode=AddressFilterMode.Any)]
public class MathWS: IMathWS
{
public int Add(int param1, int param2)
{
int result= param1 + param2;
return result;
}
} |
In order to maximize interoperability we use the basicHttpBinding which produces the following WSDL.
|
<wsdl:definitions name="MathWS" targetNamespace="http://tempuri.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex"> <wsdl:types> <xs:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://tempuri.org/"> <xs:element name="Add"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" name="param1" type="xs:int"/> <xs:element minOccurs="0" name="param2" type="xs:int"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="AddResponse"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" name="AddResult" type="xs:int"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> </wsdl:types> <wsdl:message name="IMathWS_Add_InputMessage"> <wsdl:part name="parameters" element="tns:Add"/> </wsdl:message> <wsdl:message name="IMathWS_Add_OutputMessage"> <wsdl:part name="parameters" element="tns:AddResponse"/> </wsdl:message> <wsdl:portType name="IMathWS"> <wsdl:operation name="Add"> <wsdl:input wsaw:Action="http://tempuri.org/IMathWS/Add" message="tns:IMathWS_Add_InputMessage"/> <wsdl:output wsaw:Action="http://tempuri.org/IMathWS/AddResponse" message="tns:IMathWS_Add_OutputMessage"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="BasicHttpBinding_IMathWS" type="tns:IMathWS"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="Add"> <soap:operation soapAction="http://tempuri.org/IMathWS/Add" style="document"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="MathWS"> <wsdl:port name="BasicHttpBinding_IMathWS" binding="tns:BasicHttpBinding_IMathWS"> <soap:address location="http://localhost:2020/Services/MathWS"/> </wsdl:port> </wsdl:service> </wsdl:definitions> |
Sun WSIT service
Similarly to the WCF service we used Sun WSIT to implement a service that exposes an operation to subtract two numbers.
|
@WebService()
public class wsitMathWS {
@WebMethod()
public int Sub(int param1, int param2)
{
return param1 - param2;
}
} |
The WSDL corresponding to the service is illustrated in the following figure.
|
<?xml version="1.0" encoding="UTF-8"?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is unknown. --><!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is unknown. --><definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://mathws/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://mathws/" name="wsitMathWSService">
<types>
<xs:schema xmlns:tns="http://mathws/" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" targetNamespace="http://mathws/">
<xs:element name="Sub" type="tns:Sub"></xs:element>
<xs:element name="SubResponse" type="tns:SubResponse"></xs:element>
<xs:complexType name="Sub">
<xs:sequence>
<xs:element name="arg0" type="xs:int"></xs:element>
<xs:element name="arg1" type="xs:int"></xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="SubResponse">
<xs:sequence>
<xs:element name="return" type="xs:int"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
</types>
<message name="Sub">
<part name="parameters" element="tns:Sub"></part>
</message>
<message name="SubResponse">
<part name="parameters" element="tns:SubResponse"></part>
</message>
<portType name="wsitMathWS">
<operation name="Sub">
<input message="tns:Sub"></input>
<output message="tns:SubResponse"></output>
</operation>
</portType>
<binding name="wsitMathWSPortBinding" type="tns:wsitMathWS">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"></soap:binding>
<operation name="Sub">
<soap:operation soapAction=""></soap:operation>
<input>
<soap:body use="literal"></soap:body>
</input>
<output>
<soap:body use="literal"></soap:body>
</output>
</operation>
</binding>
<service name="wsitMathWSService">
<port name="wsitMathWSPort" binding="tns:wsitMathWSPortBinding">
<soap:address location="http://localhost:8080/DemoApp/wsitMathWSService"></soap:address>
</port>
</service>
</definitions> |
Oracle ESB routing service.
In order to compose the two mathematical operations into a single contract we can use Oracle ESB routing services. The composite view of the two services looks like the following.

The routing rules of the routing service inspect the SOAP action header and deliver the message to the right service.

The WSDL exposed by the routing service is a combination of the WSDLs of the two services implemented in WCF and Sun WSIT respectively.
|
<definitions targetNamespace="http://oracle.com/esb/namespaces/DefaultSystem" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://oracle.com/esb/namespaces/DefaultSystem" xmlns:ws="http://www.example.com/webservice" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:plt="http://schemas.xmlsoap.org/ws/2003/05/partner-link/" xmlns:esb="http://www.oracle.com/esb/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:import="http://oracle.com/esb/namespaces/DefaultSystem">
<types>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://tempuri.org/" schemaLocation="wcfAddSchema.xsd"/>
</schema>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://mathws/" schemaLocation="wsitSchema.xsd"/>
</schema>
</types>
<message name="Add_request">
<part name="Add" element="wcf:Add"/>
</message>
<message name="AddResponse_reply">
<part name="AddResponse" element="wcf:AddResponse"/>
</message>
<message name="Sub_request">
<part name="Sub" element="wsit:Sub"/>
</message>
<message name="SubResponse_reply">
<part name="SubResponse" element="wsit:SubResponse"/>
</message>
<portType name="Add_ppt">
<operation name="Add">
<input message="tns:Add_request"/>
<output message="tns:AddResponse_reply"/>
</operation>
<operation name="Sub">
<input message="tns:Sub_request"/>
<output message="tns:SubResponse_reply"/>
</operation>
</portType>
<binding name="__esb_ESBMathService_Add_ppt" type="tns:Add_ppt">
<esb:binding />
<operation name="Add">
<esb:operation event-name="DefaultSystem.ESBMathService.Add" />
<input />
<output />
</operation>
<operation name="Sub">
<esb:operation event-name="DefaultSystem.ESBMathService.Sub" />
<input />
<output />
</operation>
</binding>
<binding name="__soap_ESBMathService_Add_ppt" type="tns:Add_ppt">
<soap:binding xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="Add">
<soap:operation xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" style="document" soapAction="Add" />
<input>
<soap:body xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" use="literal" />
</input>
<output>
<soap:body xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" use="literal" />
</output>
</operation>
<operation name="Sub">
<soap:operation xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" style="document" soapAction="Sub" />
<input>
<soap:body xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" use="literal" />
</input>
<output>
<soap:body xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" use="literal" />
</output>
</operation>
</binding>
<service name="Add_pptService">
<port name="__esb_ESBMathService_Add_ppt" binding="tns:__esb_ESBMathService_Add_ppt" />
<port name="__soap_ESBMathService_Add_ppt" binding="tns:__soap_ESBMathService_Add_ppt">
<soap:address xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" location="http://localhost:8888/event/DefaultSystem/ESBMathService" />
</port>
</service>
<plt:partnerLinkType name="Add_pptLT">
<plt:role name="Add_pptProvider">
<plt:portType name="tns:Add_ppt" />
</plt:role>
</plt:partnerLinkType>
</definitions> |
Client application
Implementing a client for the routing service is not different from consuming a normal Web Service. The following code shows a WCF client application that invokes both operations exposed by the routing service.
|
MathWSClient proxy = new MathWSClient();
int result = proxy.Add(12, 12); |
When Oracle ESB receives the request for the routing service it applies the corresponding routing rules and the message gets dispatched to the appropriate endpoint. However, given the composed contract exposed by the routing service this process is completely abstracted from the consumer.
Summary
Routing is a fundamental component to achieve service composition. Oracle ESB exposes routing services as first class services of the programming model that can be use to create composite interfaces based on existing service contracts. The main difference between routing services and other ESB routing technology is the fact that routing services exposes the routing logic as services that can be consume from client applications.
Microsoft Live Labs continues producing amazing things around internet-centric technologies. Yesterday they announced Volta.
Volta is an experimental developer toolset that enables developers to build multi-tier web applications by applying the familiar techniques and patterns of developing .NET applications. In effect, Volta extends the .NET platform to further enable the development of software+services applications, using existing and familiar tools and techniques. Similar to other technology previews from Live Labs, the purpose of releasing Volta as an experiment, allows for testing of the model with customers and partners in order to gather early feedback and continually influence the direction of Live Labs technologies and concepts. In addition, where and how Volta will fit into a product roadmap is not the end goal, but rather to experiment with new alternative models to enable Microsoft to continue to be innovative in this new generation of software+services.
- Volta is an experimental developer toolset that enables developers to build multi-tier web applications by applying the familiar techniques and patterns from the development of .NET applications.
- o Developers can use C#, VB, or other .NET languages utilizing the familiar .NET libraries and tools.
- o Volta offers a best effort experience in multiple environments without requiring tailoring of the application.
- Volta furthers Microsoft's software+services efforts by making it easier to write and build multi-tier applications.
- o Volta automates certain low-level aspects of distributing applications across multiple tiers, allowing programmers to devote their creative energy to the distinguishing features of their applications.
- o Via declarative tier splitting, Volta lets developers postpone irreversible design decisions until the last responsible moment, making it faster and cheaper to change the architecture to accommodate evolving needs.
- o Through MSIL rewriting, Volta follows developer's declarations to turn a single-tiered application into a multi-tiered application, generating boilerplate code for communication and serialization.
- Volta, like other technology previews from Microsoft Live Labs, is an example of the rapid innovation of web-centric technologies happening at Microsoft.
- o The purpose of the technology previews, such as Volta, is to test new technologies and product concepts with customers and partners and to gather early feedback to influence the direction of Live Labs projects.
I came across Reg Braithwaite’s weblog thru Steve Vinosky’s and I truly recommended it. This is one of the most prolific weblogs I’ve read in a long time. Check out this post about developer’s culture when comes to learn new programming paradigms.
More Posts