Skip to main content

skip to main content

developerWorks  >  WebSphere | SOA and Web services  >

Connect non-SOAP HTTP requesters and providers to WebSphere Application Server V6 Enterprise Service Bus

developerWorks
Document options

Document options requiring JavaScript are not displayed


My developerWorks needs you!

Connect to your technical community


Rate this page

Help us improve this content


Level: Advanced

Greg Flurry (flurry@us.ibm.com), Senior Technical Staff Member, IBM India Software Lab Services and Solutions

14 Dec 2005

This article shows you how to connect non-SOAP HTTP service requesters and providers to the IBM® WebSphere® Application Server V6 Service Integration Bus. This lets requesters and providers leverage the integration capabilities of an enterprise service bus.

Introduction

IBM's WebSphere Application Server V6 (hereafter called Application Server) provides a platform for building an Enterprise Service Bus (ESB). Building an Enterprise Service Bus with WebSphere Application Server V6, Part 1: Introduction to WebSphere V6 Messaging Resources is the first part of a series that provides a wealth of information on WebSphere Messaging Resources, also known as the Service Integration Bus, or SIBus, available in Version 6. The SIBus supports many of the integration features required of an ESB. The SIBus ships with mechanisms to connect service requesters and providers that use SOAP/HTTP and Java™ Messaging Service (JMS).

However, there are many sources of service requesters and providers that don't use SOAP/HTTP or JMS. In this article, we'll talk about requesters and providers that use HTTP as a transport, but don't use SOAP, and may not even use XML as the payload. In some cases, such requesters and providers were developed before SOAP became widespread; in other cases, even for recently developed applications, SOAP is considered too heavyweight. See the Resources section for links to XML-RPC, REST, eBay-REST, eBay-XML and Yahoo to get a look at some non-SOAP mechanisms and applications that use them.

Non-SOAP HTTP requesters and providers can be an important part of a service-oriented environment. In this article, you'll learn how to connect such entities to the SIBus. This allows non-SOAP HTTP requesters and providers to benefit from the same integration logic available for SOAP/HTTP and JMS requesters and providers.



Back to top


Our goal

Figure 1 shows a scenario in which a service requester interacts directly with service a provider via XML/HTTP. This means that the requester uses an XML-encoded payload for the request message sent to the provider and expects an XML-encoded payload as the response message. The requester uses HTTP to deliver the request and receive any response.


Figure 1. requester interacts directly with provider
Figure 1. requester interacts directly with provider

Figure 2 shows the scenario we want to achieve, where a requester interacts with a service provider through an ESB that can, for example, log requests, modify requests, or even route requests to a different provider. You'll see later that the payload does not have to be XML.


Figure 2. requester interacts with provider via an ESB
Figure 2. requester interacts with provider via an ESB

Figure 3 shows some additional scenarios possible with an ESB. Integration logic in the ESB can transform requests so that XML/HTTP requesters can interact with SOAP/HTTP providers and SOAP/HTTP requesters can interact with XML/HTTP providers. However, in this article, we'll only deal with the scenario shown in Figure 2.


Figure 3. Mixing requesters and providers
Figure 3. Mixing requesters and providers

An analysis of the XML/HTTP <==> XML/HTTP scenario shows that the ESB must do the following:

  • Receive the XML/HTTP request from the XML/HTTP requester. (At this point, integration logic in a mediation can run to process the request.)
  • Send the request to the XML/HTTP provider
  • Receive the response from the XML/HTTP provider. (At this point, integration logic in a mediation can run to process the response.)
  • Return the response to the XML/HTTP requester



Back to top


Our solution

Figure 4 shows an ESB topology that performs the steps described above. The figure shows a servlet that acts as an XML/HTTP on-ramp for the SIBus, in a manner very similar to the SOAP/HTTP on-ramp for Web services, called the inbound Web service, that ships with the SIBus. The servlet inserts the request into the SIBus, via the JMS sender, where it can be mediated if necessary, and returns the response to the requester, via the JMS listener. A Message-Driven Bean (MDB) acts as an XML/HTTP off-ramp for the SIBus, in a manner very similar to the SOAP/HTTP off-ramp for Web services, called the outbound Web service, that ships with the SIBus. The MDB sends the request to the XML/HTTP provider, via the HTTP client and inserts the response into the SIBus, via the JMS sender, where it can be mediated if necessary.


Figure 4. ESB topology
Figure 4. ESB topology

Note that to support the spectrum of possible non-SOAP request types, the ESB must preserve the fidelity of the HTTP request and response. In particular, the servlet must deal specifically with the following HTTP methods:

  • POST, where the requester sends body content in the request and expects body content in the response.
  • GET, where the requester only expects body content in the response.
  • PUT, where the requester sends body content in the request, but expects no body content in the response.
  • DELETE, where the requester sends no body content in the request, and expects no body content in the response.

In addition, the servlet's JMS sender function inserts the HTTP method, the HTTP path info (part of the URL past the root), the HTTP parameters and the HTTP headers (including cookies) from the HTTP request into a JMS message inserted into the SIBus. For the POST and PUT methods, the JMS sender also inserts the request payload or body (which might be XML) into the JMS message. The JMS sender then sends the message to an SIBus queue destination (the yellow box labeled Request in Figure 4). The servlet then invokes its JMS listener to listen for the response.

The MDB listens for messages arriving on the Request queue. Upon receiving a message, the HTTP client function of the MDB constructs an HTTP request using all the information placed in the request JMS message by the servlet. There is one significant semantic difference between the newly constructed HTTP request and the original HTTP request received by the servlet: the root URL is different so that when the HTTP client sends the request, it goes to the expected provider. The MDB HTTP client waits for the synchronous HTTP response from the provider.

The MDB JMS sender inserts any response payload, the HTTP headers (including Set-Cookie headers) and status code from the HTTP response into a JMS message. The JMS sender also sets the correlation ID of the JMS response message to the message ID of the JMS request message, and then sends the JMS response message to an SIBus queue destination (the yellow box labeled Reply in Figure 4).

The servlet's JMS listener listens for an incoming message on the Reply queue with a JMS selector set to match a response correlated with the request; the correlation ID of the response must be equal to the JMS request message ID. Upon receiving the correlated response message, the JMS listener inserts only the response status code into the HTTP response if the response is not OK. If the response is OK, the JMS listener inserts the response (XML) payload and any headers from the JMS message into the HTTP response. The JMS listener then returns the HTTP response to the original requester.



Back to top


Implementation

Listing 1 shows the servlet skeleton used for the on-ramp. The init() method gets the JMS connection factory and queues, and starts a connection. The connection is held open for the lifetime of the servlet, and is not closed until the servlet's destroy() method gets called. Configuration information, such as JNDI names, is described in detail in the next section.


Listing 1. Servlet skeleton
				
public class XMLHTTP2SIB extends javax.servlet.http.HttpServlet 
implements javax.servlet.Servlet {

	// connection factory and queue resources    
	private final static String 
		JMSCF_JNDI_NAME = "java:comp/env/MDBCF";
 	private final static String JMSRequest_JNDI_NAME = 
		"java:comp/env/MRequest";
 	private final static String 
		JMSReply_JNDI_NAME = "java:comp/env/MReply";

	// session and connection 
	private Session session = null;
	private Connection connection = null;
	// request and reply queues
	private Destination requestQueue = null;
	private Destination responseQueue = null;
 	
	public void init() throws ServletException	{
		try {
			InitialContext context = new InitialContext();
			ConnectionFactory factory = (ConnectionFactory)
    			context.lookup(JMSCF_JNDI_NAME);
	        	requestQueue = (Destination)
    			context.lookup(JMSRequest_JNDI_NAME);
	       	responseQueue = (Destination)
    			context.lookup(JMSReply_JNDI_NAME);
			connection = factory.createConnection();
			session = connection.createSession(
    			false, 
    			Session.AUTO_ACKNOWLEDGE);	
			connection.start();
		} catch (NamingException e) {
			…
		} catch (JMSException e) {
			…
		}
	}

	public void destroy() {
		try {
			connection.close();
		} catch (JMSException e) {
			…
		}
	}
}

Before describing the servlet request and response processing logic, let's discuss the utility class HTTPOutput, partially shown in Listing 2 below. This class is used to convey information from the HTTP response. It has a returnCode field that carries the HTTP response status. The header field contains any response headers, where each member in the Vector is a two-element array of String; the first member of the array is the header name and the second is the header value. The utility class also contains the body in the response field. Note that only the returnCode field is guaranteed to be meaningful; the others can be null.


Listing 2. HTTPOutput class
					
public class HTTPOutput {

	private int returnCode;
	private byte[] response;
	private Vector header = null; 

	// setters and getters not shown
} 

Listing 3 shows the servlet's doPost() method. The method first uses the private sendJMSMessage() method to map the HTTP request into a JMS message and insert that message into the SIBus, as shown below. Note that sendJMSMessage() returns the ID of the message to use in a JMS selector; this helps correlate the response to the request. doPost() then listens for the response on a JMS queue by calling the private getJMSResponse() method; as shown below. If doPost() finds that the status code from the response indicates that request was unsuccessful, it simply returns the status code; otherwise it returns the entire response body and headers. This ensures the response returned to the original requester semantically matches that returned by the actual provider.

Note that header names require a bit of special processing using the utility function XMLHTTPUtil.unfixName(), because JMS properties are used to send the HTTP headers in the response JMS message, and Java does not allow the dash character to appear in JMS property names. The use of the dash is common in HTTP header names, and a companion utility function, XMLHTTPUtil.fixName() used in the MDB that sends the response, replaces any dash characters in a name with underscore characters, as you'll see later.


Listing 3. doPost() method of XMLHTTP2SIB servlet
				
protected void doPost(HttpServletRequest request, HttpServletResponse 
response) throws ServletException, IOException {
	// send request
	String selector = sendJMSMessage(request.getMethod(), request);
	// listen for response
	HTTPOutput output = getJMSResponse(selector, response);
	// return response
	if (output == null) {
		throw new IOException("bad response from HTTP provider");
	} else {
		if(output.getReturnCode() != (HttpServletResponse.SC_OK)) {
			response.setStatus(output.getReturnCode());
		} else {
			// do headers
			Vector header = output.getHeader();
			if ((header != null) && (header.size() > 0)) {
				for (int i = 0; i < header.size(); i++) {
					String[] entry = (String[])header.get(i);
					response.setHeader(XMLHTTPUtil.
    				    unfixName(entry[0]), entry[1]);
				}
			}
			if (output.getResponse() !=null) {
				response.getOutputStream().
    				write(output.getResponse());
				response.getOutputStream().close();
			}
		}
	}
} 

The servlet's doGet(), doPut() and doDelete() methods all simply call the doPost() method described above. The sendJMSMessage() method deals with the differences in the request for the various HTTP methods (POST and PUT have body content, GET and DELETE don't), and as you can see, the doPost() method itself deals with the differences in the response for the various HTTP methods (POST and GET have body content, PUT and DELETE don't).

Listing 4 shows the details of the sendJMSMessage() method for the servlet. It creates a JMS bytes message and, if appropriate, inserts the HTTP payload into the body of the bytes message. It then sets the HTTP method in an application-specific JMS property. Next the method inserts any HTTP headers and parameters into the message as application-specific properties in the JMS message. Note that the names used for the JMS properties are derived from the HTTP header or parameter names; the names are given a prefix that should make them unique and distinguish the headers from parameters; also the utility function XMLHTTPUtil.fixName() replaces any dash characters in a name with underscore characters. The method also puts pathInfo from the HTTP request into the JMS message as an application-specific JMS property. Finally the method sends the message to the request queue. Once the message is sent, sendJMSMessage() forms a JMS message selector that tests whether the correlation ID of an incoming response message equals the message ID of the outgoing request message, which supports correlation of the response with the request.


Listing 4. sendJMSMessage() method of XMLHTTP2SIB servlet
				
private String sendJMSMessage(String type, HttpServletRequest request)
throws IOException {
	String selector = null;
	try {
		MessageProducer producer =
    			session.createProducer(requestQueue);
		BytesMessage outMessage = session.createBytesMessage();
		// send request body only when actually have one
		if (type.equals("POST") || type.equals("PUT")) {
	    		ServletInputStream sis = request.getInputStream();
	    		byte[] body = new byte[sis.available()];
	    		sis.read(body);
	        	outMessage.writeBytes(body);
	      	}        
		// set the message type per the incoming request
		outMessage.setStringProperty("SIB_HTTP_METHOD", type);
		// set the HTTP headers in the message
		Enumeration enum = request.getHeaderNames();
		while (enum.hasMoreElements()) {
			String name = (String)enum.nextElement();
			String transformedName = XMLHTTPUtil.fixName(name);
			outMessage.setStringProperty(
    				"SIB_HTTP_HEAD_"+transformedName,
    				request.getHeader(name));
		}
		// set the HTTP parameters on the message
		enum = request.getParameterNames();
		while (enum.hasMoreElements()) {
			String name = (String)enum.nextElement()
				outMessage.setStringProperty(
					"SIB_HTTP_PARM_"+name,
					request.getParameter(name));
		}
		// set the pathInfo on the message
		String pathInfo = request.getPathInfo();
		String URItail = null;
		if (pathInfo != null) URItail =
    			request.getPathInfo().substring(1);
		outMessage.setStringProperty("SIB_PathInfo", URItail);

	      // send the message
	      producer.send(outMessage);
	      selector = "JMSCorrelationID ='" +
			outMessage.getJMSMessageID() + "'";
	      producer.close();
	} catch (JMSException e) {
		…
	}
	return selector;
}

Listing 5 shows the details of the getJMSResponse() method for the servlet. It creates a consumer listening for a message with the selector that correlates the response to the request, as discussed above. The method then places information from the response into an HTTPOutput instance, including the HTTP status code, the response body and any response headers. Note that getJMSResponse() removes the a prefix from the returned HTTP headers.


Listing 5. getJMSResponse() method of XMLHTTP2SIB servlet
				
private HTTPOutput getJMSResponse (String selector, HttpServletResponse response){
byte [] realResponse = null;
      HTTPOutput output = null;	
	try {
		MessageConsumer consumer =
			session.createConsumer(responseQueue,
			selector);		
		Message message = consumer.receive();
	     	output = new HTTPOutput();
		output.setReturnCode(
			Integer.parseInt(message.getJMSType()));
		BytesMessage theMessage = (BytesMessage) message;
		realResponse =
			new byte[(int)theMessage.getBodyLength()];
		theMessage.readBytes(realResponse);
		output.setResponse(realResponse);	
		// get headers
		Enumeration enum = message.getPropertyNames();
 		Vector header = new Vector();
 		output.setHeader(header);
		while (enum.hasMoreElements()){
			String name = (String) enum.nextElement();
			if (name.startsWith("SIB_HTTP_HEAD_")) {
				String[] headerEntry = new String[2];
				header.add(headerEntry);
				headerEntry[0] = name.substring(14);
				headerEntry[1] = 
       			message.getStringProperty(name);
			}
		}	
		consumer.close();
	} catch (JMSException e) {
		…
	}
	return output;
}


Listing 6 shows the skeleton for the MDB that forms the off-ramp. When the MDB gets created, the ejbCreate() method creates all of the JMS resources required; in this case, the connection factory, the reply queue and the connection. These exist until the MDB is destroyed. At that time, the ejbRemove() method closes the connection, which releases all the JMS resources.

The ejbCreate() method also determines the root URL used to form the new outbound HTTP request. In the code show in Listing 6, the default value is derived from an EJB environment variable set in the deployment descriptor of the EJB module containing the MDB. The default value could be over-ridden by setting a new JMS property in some mediation that runs in the SIBus; however, over-riding is not implemented in this example.


Listing 6. Message Driven Bean skeleton
				
public class XMLHTTPMDB implements javax.ejb.MessageDrivenBean,
	javax.jms.MessageListener {
	
	// the connection factory and queue names
 	private final static String
		JMSCF_JNDI_NAME = "java:comp/env/MDBCF";
 	private final static String
		JMSQ_JNDI_NAME = "java:comp/env/MReply";
 	// the JMS connection information
	private Destination queue = null;
	private Connection connection = null;
	private Session session = null;

	// the root of the URI used to send the HTTP request
	private String default_URI_Root = null;

	// getMessageDrivenContext and setMessageDrivenContext not shown

	public void ejbCreate() {
		try {
			InitialContext context = new InitialContext();
			default_URI_Root = ((String)
				context.lookup(
					"java:comp/env/Default_URI_Root"));
			ConnectionFactory factory = (ConnectionFactory)
				context.lookup(JMSCF_JNDI_NAME);
			queue = (Destination) context.lookup(JMSQ_JNDI_NAME);
			connection = factory.createConnection();
			session = connection.createSession(false,
    			Session.AUTO_ACKNOWLEDGE);
		} catch (NamingException e) {
			…
		} catch (JMSException e) {
			…
		}
	}

	public void ejbRemove() {
		try {
			connection.close();
		} catch (JMSException e) {
			…
		}
	}	
}

Listing 7 shows the details of the onMessage() method of the MDB. The method first retrieves the information about the original HTTP request from the incoming JMS message, including the request body, the HTTP parameters and headers, the HTTP "infoPath" and the HTTP method. Note that HTTP headers and parameters are distinguished by the prefix on the JMS property names. The HTTP parameters are added onto the root URL set in the ejbCreate() method. The onMessage() method then calls the private sendHTTPRequest() method to send the new HTTP request and wait for the response.


Listing 7. onMessage() method of XMLHTTPMDB MDB
				
public void onMessage(javax.jms.Message msg) {
	StringBuffer url = null;
	byte[] body = null;
	String type = null;
	Vector header = new Vector();
	BytesMessage byteMsg = (BytesMessage) msg;
	try {
		// retrieve the HTTP method, message body
		type = msg.getStringProperty("SIB_HTTP_METHOD");
		body = new byte[(int) byteMsg.getBodyLength()];
		byteMsg.readBytes(body);
		// form new target URL
		url = new StringBuffer(default_URI_Root);
		if (msg.getStringProperty("SIB_PathInfo") != null)
			url.append(
				'/'+msg.getStringProperty("SIB_PathInfo"));
		boolean haveParm = false;
		Enumeration enum = msg.getPropertyNames();
		// HTTP parameters, headers
		while (enum.hasMoreElements()){
			String name = (String) enum.nextElement();
			if (name.startsWith("SIB_HTTP_PARM_")) {
				if (haveParm) {
					url.append('&');
				} else {
					haveParm = true;
					url.append('?');
				}
				url.append(
					name.substring(14)+
					"="+msg.getStringProperty(name));	
			} else if (name.startsWith("SIB_HTTP_HEAD_")) {
				String[] headerEntry = new String[2];
				header.add(headerEntry);
				headerEntry[0] = name.substring(14);
				headerEntry[1] = msg.getStringProperty(name);
			}
		}
	} catch (JMSException x) {
		…
	}	
	// send the HTTP request
	HTTPOutput theOutput = sendHTTPRequest(
		url.toString(), type, body, header);
	// send back the reply via JMS
	try {
		MessageProducer queueSender =
			session.createProducer(queue);
		BytesMessage outMessage = session.createBytesMessage();
		// set the status code
		int status = theOutput.getReturnCode();
		outMessage.setJMSType(Integer.toString(status));
		// write the body
		if (theOutput.getResponse() != null) {
			outMessage.writeBytes(theOutput.getResponse());
        	}
     		// set the correlation ID 
        	outMessage.setJMSCorrelationID(msg.getJMSMessageID());    
        	// insert the response headers
        	Vector headerVec = theOutput.getHeader();
        	if ((headerVec != null) && (headerVec.size() > 0)) {
        		for (int i=0; i < headerVec.size(); i++) {
        			String[] entry = (String[]) headerVec.get(i);
        	   		outMessage.setStringProperty(
					"SIB_HTTP_HEAD_"+
					XMLHTTPUtil.fixName(entry[0]), entry[1]);
	     		}
		}
		// send the response message
		queueSender.send(outMessage);
	} catch (JMSException e) {
		e.printStackTrace();
	}
}

After receiving the HTTP response, the onMessage() method extracts the HTTP response information and puts it in a JMS message sent to the reply queue. This message includes the response status, any headers and the body, as needed. The headers must have the names converted, as described above. Note in particular that the method sets the correlation ID of the JMS message to the message ID of the incoming request to support correlation of the response with the request in the servlet. The method then sends the JMS message to the reply queue.

Listing 8 shows the details of the sendHTTPRequest() method of the MDB. The method inserts the headers, the body and the HTTP method into the request. The outgoing HTTP request is therefore semantically equivalent to the original HTTP request except for the root URL. The method sends the HTTP request to the target provider and waits for the HTTP response.


Listing 8. sendHTTPRequest method of XMLHTTPMDB MDB
				
private HTTPOutput sendHTTPRequest(String outboundURL, String method, 
byte[] body, Vector header){
	URLConnection conn = null;
	HttpURLConnection hConn = null;
	OutputStream os = null;
	URL url = null;
	HTTPOutput output = new HTTPOutput();

	// send the HTTP request
	try {
		url = new URL(outboundURL);
		conn = url.openConnection();
		conn.setDoInput(true);
		// put the headers in the request
		for (int i=0; i < header.size(); i++) {
			String[] entry = (String[]) header.get(i);
			conn.setRequestProperty(
    			XMLHTTPUtil.unfixName(entry[0]), entry[1]);	
		}
			
		hConn = (HttpURLConnection) conn;
		System.out.println("method: "+hConn.getRequestMethod());
		hConn.setRequestMethod(method);	
		// ensure that send body only if needed
		if (method.equals("POST") || method.equals("PUT")) {
			conn.setDoOutput(true); 
			os = hConn.getOutputStream();
			if (body != null) os.write(body);
		}		
	} catch (IOException ex) {
		...
	}			
	// retrieve HTTP response
	int returnCode = 999;
	try {
		// get the content and status
		InputStream is = conn.getInputStream();
		returnCode = hConn.getResponseCode();
		int avail = is.available();
		byte[] response = new byte[avail];
		is.read(response,0,avail);
		output.setResponse(response);
			
		// get the headers
		Map headerMap = conn.getHeaderFields();
		Set headSet = headerMap.keySet();
		Object[] headName = headSet.toArray();
		Vector headerVec = new Vector();
		output.setHeader(headerVec);
		for (int i=0; i < headName.length; i++) {
			String name = (String)headName[i];
			if (name != null) {
				String[] entry = new String[2];
				headerVec.add(entry);
				entry[0] = name;
				entry[1] = conn.getHeaderField(name);
			}
		}
		is.close();
	} catch (IOException ex) {
		try { // get the return code when no InputStream
			returnCode = hConn.getResponseCode();
		} catch (IOException ex2) {
			...
		}
	}
	output.setReturnCode(returnCode);
	return output;
}

Once it receives the HTTP response, the sendHTTPRequest() method extracts the response and puts it into an instance of HTTPOutput. The instance contains the status code, and may also contain headers and a body. Note that if there is an error in the HTTP response from the provider, the attempt to get the HTTP response InputStream causes an exception. In that case, the HTTPOutput instance contains only the HTTP status code.



Back to top


Configuration

In Figure 4, you can see that two SIBus queue destinations need to be created for the ESB to support XML/HTTP in the manner described in this article. The two queues, one for the request and one for the response, must be exposed as part of a JMS provider. In particular, you need to create a JMS connection factory for your SIBus and a JMS queue for both SIBus queues. Since the MDB shown in Figure 4 listens for messages on the request queue, you must also create a JMS activation specification for the request queue. Building an Enterprise Service Bus with WebSphere Application Server V6, Part 3 describes these steps in more detail. In the sample configuration that corresponds to the sample code described above, the JMS connection factory has a JNDI name of jms/MDBCF, the request JMS queue has a JNDI name of jms/MRequest, the response JMS queue has a JNDI name of jms/MReply, and the JMS activation specification has a JNDI name of eis/TestMDBAS.

The servlet references the JMS resources defined above. The deployment descriptor for the Web module containing the servlet must define resource references for the connection factory and both the request and reply queues. In Rational® Application Developer, you can define the resource references on the References tab of the Web project deployment descriptor editor, by entering the JNDI names: jms/MDBCF, jms/MRequest and jms/MReply.

The MDB listens for incoming requests on the request queue and sends responses on the reply queue. To allow the MDB to send the response, the deployment descriptor for the EJB module containing the MDB must define resource references for the connection factory and reply queue. In the Rational Application Developer environment, you can define the resource references for the MDB on the References tab of the EJB project deployment descriptor editor, entering the JNDI names: jms/MDBCF and jms/MReply. To listen for the request, the deployment descriptor for the EJB module containing the MDB must define the JMS activation specification and the request queue resources. In Rational Application Developer, you can define the resource references for the MDB on the Bean tab of the EJB project deployment descriptor editor by entering the JNDI names eis/TestMDBAS and jms/MQ in the WebSphere Bindings area under the JCA Adapter property.

The MDB also uses an environment variable to set the root URL for the outbound HTTP request. The deployment descriptor for the EJB module containing the MDB must define the environment variable. In Rational Application Developer, you can define the environment variable for the MDB on the Bean tab of the EJB project deployment descriptor editor, by entering the appropriate name and value of the environment variable in the Environment Variables area. In our example, the environment variable name is Default_URI_Root.



Back to top


An example

Listing 9 shows a POST request generated by a non-SOAP HTTP requester that happens to use an XML body. Note that the root URL of the service provider is /XMLHTTP/XMLHTTP2SIB. Therefore, there is an HTTP InfoPath that equals dofuss. There are also two HTTP parameters and several headers, one specifically introduced by the requester (A-FAKE-HEADER).


Listing 9. Original POST request
				
POST /XMLHTTP/XMLHTTP2SIB/dofuss?xyz=nub&fuzz=bust HTTP/1.1
Content-Type: text/xml; charset=utf-8
Accept: text/*
Cache-Control: no-cache
Pragma: no-cache
A-FAKE-HEADER: WHATEVER-YOU-WANT
User-Agent: Java/1.4.2
Host: localhost
Connection: keep-alive
Content-Length: 179

<?xml version="1.0" encoding="UTF-8"?>
   <GetAccountPositions xmlns="http://test.com/GetAccountPositions">
      <requestData>
         <pdw8_id>10221477</pdw8_id>
      </requestData>
   </GetAccountPositions>

Listing 10 shows the request sent to the default target identified in the MDB environment. You can see the new root, /FakeXMLHTTPService/FakeService, defined by the EJB environment variable (which also contains the host name and port information). You can also see the InfoPath and HTTP parameters are included, though the syntax is a bit different, as the parameters are out of order. You can see that all the original headers appear in the new request, but again, the syntax is a bit different in that the headers are in a different order. Finally the body appears in the new request identical to the original body. Thus, even though the new request syntax is a bit different, the semantics of the original request are preserved.


Listing 10. New POST request sent to service provider
				
POST /FakeXMLHTTPService/FakeService/dofuss?fuzz=bust&xyz=nub HTTP/1.1
Host: localhost
Connection: keep-alive
Content-Length: 179
Content-Type: text/xml; charset=utf-8
User-Agent: Java/1.4.2
Accept: text/*
Cache-Control: no-cache
A-FAKE-HEADER: WHATEVER-YOU-WANT
Pragma: no-cache

<?xml version="1.0" encoding="UTF-8"?>
   <GetAccountPositions xmlns="http://test.com/GetAccountPositions">
      <requestData>
         <pdw8_id>10221477</pdw8_id>
      </requestData>
   </GetAccountPositions>

Listing 11 shows the original response to the POST request. Note that it contains a custom header (XYZ-RQF) and a Set-Cookie header as well as an XML body.


Listing 11. Original response
				
HTTP/1.1 200 OK
Content-Language: en-US
Set-Cookie: my-cookie=my value
Transfer-Encoding: chunked
Date: Fri, 30 Sep 2005 21:47:43 GMT
XYZ-RQF: zipper

<?xml version="1.0" encoding="UTF-8"?>
   <AccountPositions xmlns="http://test.com/AccountPositions">
      <reponseData>
         <pdw8_id>10221477</pdw8_id>
      </reponseData>
   </AccountPositions>

Listing 12 shows the response actually returned to the requester. Note that as with the request, the response returned to the requester is semantically equivalent to the original response, even though the syntax is a bit different.


Listing 12. Response returned to requester
				
HTTP/1.1 200 OK
Set-Cookie: my-cookie=my value
Transfer-Encoding: chunked
Date: Fri, 30 Sep 2005 21:47:43 GMT
Content-Language: en-US
XYZ-RQF: zipper

<?xml version="1.0" encoding="UTF-8"?>
   <AccountPositions xmlns="http://test.com/AccountPositions">
      <reponseData>
         <pdw8_id>10221477</pdw8_id>
      </reponseData>
   </AccountPositions>

You should recognize that while the mechanisms described above ensure semantic fidelity in the request and response, it is possible that integration logic running in the ESB (for example, mediations running in the SIBus) could intentionally break that fidelity. For example, it might be necessary to add HTTP headers or even transform the body.



Back to top


Summary

This article showed you how to attach non-SOAP HTTP service requesters and service providers to an ESB built with the WebSphere Application Server V6 SIBus. The detailed example ensures the semantic fidelity of the request and reply to support the full spectrum of non-SOAP HTTP requesters and providers. This allows your ESB to provide integration logic for non-SOAP HTTP requesters and providers, just as it can for SOAP/HTTP and JMS requesters and providers



Resources

Learn

Get products and technologies
  • eBay REST API: Get information on the eBay REST API and download samples.

  • eBay XMP API: Get information on the eBay XML API and download the schema.

  • Using Yahoo! Search: Get information on Yahoo! Search Web services and download the SDK.


About the author

Greg Flurry photo

Greg Flurry is a Senior Technical Staff Member in IBM's SOA Advanced Technology group. His responsibilities include working with customers on service-oriented solutions and advancing IBM's service-oriented products. If you have comments for the Greg about this article, send them to wsdd@us.ibm.com.




Rate this page


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



 


 


Not
useful
Extremely
useful
 


Share this....

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



Back to top