Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

JVM Languages

Basic SOA Using REST


3.3 REST Clients with and without JWS

A basic capability you often need when implementing an SOA Web service is easily downloading and uploading XML files from/to an HTTP server. For example, suppose that the OMS runs a nightly batch job and writes all new and changed orders from the previous day to a set of XML documents that can be accessed using a Web service named NewOrders. The CSS can then, each morning, retrieve those files and update its Customer History. This is a simple, but common and highly practical, form of SOA-style loosely coupled integration.

The next few sections focus on uploading/downloading XML documents with bare-bones RESTful Web Services. I show how to write clients for RESTful services with and without JWS. This material may seem very basic to advanced Java programmers, but it is always good to review the basics before diving into a complex subject like SOA with Java Web Services.

It is a common misconception that implementing Web Services with Java requires lots of heavy machinery like JAX-WS. This is not the case, as even J2SE 1.4 provides powerful tools for HTTP communication and XML processing that enable you to build and consume RESTful Web services.

JAX-WS and the other JWS tools provide many advantages, of course, which we discuss later in this section and throughout the rest of this book.

Doing REST without JWS gives you a hands-on appreciation for what HTTP can and cannot do. It quickly becomes clear that, although it is easy to do simple things without the JWS machinery, as you get more ambitious, you start to need some more powerful tools to handle invocation, serialization, and the other components of an SOA Web Services infrastructure.

Since this is a book about Java, I start with the assumption that the EISs have Java APIs for accessing the needed records. The challenge addressed in the next few sections is to deploy a Java API as a Web service or to invoke a Web service using Java.

4. Perhaps this is because such interface definitions complicate the REST model, and REST proponents like to position it as simpler than SOAP.

3.3.1 Getting EIS Records from a REST Service without Using JWS

This section briefly examines how to get an XML document from a RESTful Web service. In this example, the Web service is accessed with an HTTP GET request. The client application needs to issue the HTTP GET, and process the HTTP response stream that contains the XML document.

Instead of using the JWS APIs (e.g., JAX-WS), I simply use the javax.net.HttpURLConnection class to handle most of the work related to generating the HTTP GET and processing the response.

Figure 3-3 illustrates the XML transfer process from the client’s side.

Note that the client is implemented as the class GetNewOrders and that it uses instances of the classes URL and HttpURLConnection. The following steps show how these classes work together to implement the XML document download protocol.

1. The client uses the URL.openConnection() method to create an instance of HttpURLConnection representing a connection to the Web service’s URL.
2.
HttpURLConnection.connect() sends the HTTP GET request that has been configured using the Web service’s URL.
3.
The Web service processes the request and writes the appropriate XML document to the HTTP response stream.
4.
The HttpURLConnection’s InputStream is used to read the HTTP response’s XML document.

In the implementation of this example, the client simply writes the XML document to the console. You will see it print out on your console when you run it (instructions follow). In a real SOA-style loosely coupled application, the document might be parsed, transformed, and sent to another component of the distributed application. An example of such processing is provided in Section 3.4.

Example 3-5 shows the client-side code for issuing the HTTP GET request and receiving the XML document via the HTTP response. Notice that the String used to construct the URL instance is passed to the client as args[0]. The HttpULRConnectioncon—doesn’t send the HTTP request until its connect() method gets invoked. Before this happens, the setRequestMethod() is invoked to specify that a GET request should be sent.

Example 3-5 Implementing a Java Client to Download an XML Document from a RESTful Web Service

27 public static void main(String[] args) throws Exception {
28
29 if (args.length != 1) {
30 System.err.println
31 ("Usage: java GetNewOrders <Web Service URL>");
32 System.exit(1);
33 }
34 // Create the HTTP connection to the URL
35 URL url = new URL(args[0]);
36 HttpURLConnection con =
37 (HttpURLConnection) url.openConnection();
38 con.setRequestMethod("GET");
39 con.connect();
40 // write the XML from the input stream to standard out
41 InputStream in = con.getInputStream();
42 byte[] b = new byte[1024]; // 1K buffer
43 int result = in.read(b);
44 while (result != -1) {
45 System.out.write(b,0,result);
46 result =in.read(b);
47 }
48 in.close();
49 con.disconnect();
50 }
book-code/chap03/rest-get/client-http/src/java/samples/GetNewOrders.java

To run this example, do the following:

1. Start GlassFish (if it is not already running).
2. Go to
<book-code>/chap03/rest-get/endpoint-servlet.
3.
To build and deploy the Web service enter:
mvn install 5 ... and when that command finishes, enter:
ant deploy
4.
Go to <book-code>/chap03/rest-get/client-http.
5.
To run the client enter:
mvn install
6.
To undeploy the Web service, go back to <book-code>/chap03/restget/ endpoint-servlet and enter:
ant undeploy

In this example, the HttpURLConnection class does all the work. It sends the HTTP GET request to the Web service URL6 and provides access to the response as an InputStream. Now, let’s look at how this is done using JWS.

5. mvn is the command to run Maven, the build tool used throughout this book. See Appendix B, Software Configuration Guide, for details about installing and running the examples in this book.
6. In this example, the URL where the RESTful service deployed is http://localhost:8080/ rest-get-servlet/NewOrders (assuming your Java EE Web container is running on localhost: 8080). You can always see what parameters are used to invoke code in the examples by examining the build.xml file from the directory where you are running the example.

3.3.2 Getting EIS Records from a REST Service with JWS

When using the JAX-WS 2.0 API to create a client that consumes a RESTful Web service, the javax.xml.ws.Dispatch<T>7 interface does most of the work—performing a role similar to HttpURLConnection.

Figure 3-4 shows how the JAX-WS-based client works. This time, the class GetNewOrders is implemented using the javax.ws.xml.Service class. Service is an abstraction that provides a client interface to a Web service. First introduced in JAX-RPC 1.0, Service is designed to represent a WSDL defined service. Since RESTful services do not have WSDL representations, the Service API is a little awkward for our purposes here (as you can see in the discussion of the code). However, that is how the JAX-WS API is designed.

7. A detailed discussion of the javax.xml.ws.Dispatch<T> interface is provided in Chapter 6, Section 6.2, where the JAX-WS client API is explained in depth.

In this example, Service is used to create an instance of javax.xml.ws.Dispatch<Source>, which enables XML message-level interaction with the target Web service. Dispatch is the low-level JAX-WS 2.0 API that requires clients to construct messages by working directly with the XML, rather than with a higher-level binding such as JAXB 2.0 schemaderived program elements. For many REST proponents, however, this is exactly the programming paradigm they want—direct access to the XML request and response messages.

The following steps trace the execution of the JAX-WS version of the GetNewOrders client illustrated in Figure 3-4.

1. The client uses the Service.addPort() method to create a port within the Service instance that can be used to access the RESTful Web service.
2. Next, the
Service.createDispatch() method is invoked to create an instance of Dispatch<Source>—a Dispatch instance that enables you to work with XML request/response messages as instances of javax.xml.transform.Source.
3.
The Dispatch.invoke() method then packages the XML request—per the JAX-WS 2.0 HTTP Binding—and sends it to the RESTful service. The invoke() method waits for the response before returning.
4.
The service processes the HTTP GET and sends an HTTP response that includes the XML.
5.
The invoke() method returns the response XML message as an instance of Source.

Example 3-6 shows the code used to implement the JAX-WS version of GetNewOrders. Browsing through this code, you can see some of the awkwardness that comes from applying the WSDL-oriented Service API in a REST context. First, notice that you have to create QName instances for the Service instance and the “port” that corresponds to the RESTful Web service.

In a SOAP scenario, these qualified names would correspond to the WSDL definitions for the wsdl:service and wsdl:port. Since there is no WSDL when invoking a RESTful service, these QName instances are gratuitous in this example. They are required by the API, but not used to invoke the RESTful service.

Example 3-6 The GetNewOrders Client As Implemented with JAX-WS

35 public static void main(String[] args) throws Exception {
36 if (args.length != 1) {
37 System.err.println
38 ("Usage: java GetNewOrders <Web Service URL>");
39 System.exit(1);
40 }
41 QName svcQName = new QName
("http://sample", "svc");
42 QName portQName = new QName("http://sample", "port");
43 Service svc = Service.create(svcQName);
44 svc.addPort(portQName, HTTPBinding.HTTP_BINDING, args[0]);
45 Dispatch<Source> dis =
46 svc.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
47 Map<String, Object> requestContext = dis.getRequestContext();
48 requestContext.put(MessageContext.HTTP_REQUEST_METHOD, "GET");
49 Source result = dis.invoke(null);
50 try {
51 TransformerFactory.newInstance().newTransformer()
52 .transform(result, new StreamResult(System.out));
53 } catch (Exception e) {
54 throw new IOException(e.getMessage());
55 }
56 }
book-code/chap03/rest-get/client-jaxws/src/java/samples/GetNewOrders.java

To run this example, do the following:

1. Start GlassFish (if it is not already running).
2. Go to
<book-code>/chap03/rest-get/endpoint-servlet.
3.
To build and deploy the Web service enter:
mvn install
... and when that command finishes, then enter:
ant deploy
4.
Go to <book-code>/chap03/rest-get/client-jaxws.
5.
To run the client enter:
mvn install
6.
To undeploy the Web service, go back to <book-code>/chap03/ rest-get/endpoint-servlet and enter:
ant undeploy

Looking at the code in Example 3-6, you can also see that the addPort() method takes a URI parameter that defines the transport binding.

The default is SOAP over HTTP, but in this case, the HTTPBinding.

HTTP_BINDING URI is used to specify the JAX-WS 2.0 HTTP Binding.

The final parameter passed to the addPort() method is the URL of the RESTful Web service—in this case, args[0].

Once the port for the RESTful service has been added by the addPort() method, it can be used to create an instance of Dispatch< Source>. The type parameter—in this case, Source—is passed as a parameter to the createDispatch() method. The type of payload is specified as well. Here, I have specified Service.Mode.PAYLOAD (as opposed to Service.Mode.MESSAGE). When working with SOAP, the MESSAGE mode indicates that you want to work with the entire SOAP envelope as opposed to just the SOAP body (or payload). In the REST scenario, there is no envelope, so PAYLOAD is the option that makes sense.

Besides Source, the other valid type parameters for Dispatch are JAXB objects, java.xml.soap.SOAPMessage, and javax.activation.Data- Source. In Chapter 6,8 I look at examples using JAXB and SOAPMessage.

DataSource enables clients to work with MIME-typed messages—a scenario I don’t cover in this book.

How does this implementation compare with the HttpURLConnection version illustrated in Example 3-5? Table 3-2 illustrates some similarities and differences.

As you can see, the JAX-WS version gives us a much richer interface, although in a simple REST scenario like this, it is not always that useful. A URL is an adequate representation of a RESTful service since there is no associated WSDL to provide further definition anyway. About the only other information that is needed is whether to use HTTP POST or HTTP GET. As we have seen, Service is really designed to be a Java representation of WSDL, so it’s not particularly helpful here.

8. Chapter 6 is a detailed overview of the JAX-WS client-side API.

The Dispatch interface, on the other hand, is better suited for working with XML request/response than HttpURLConnection. First, its invoke() method captures the request/response semantics of the HTTP Binding better than the HttpURLConnection.connect() method. Second, rather than reading and writing streams, the Dispatch interface enables us to work directly with XML representations such as Source. This is much more natural, as we will see when we start linking RESTful services together and using XSLT for data transformation (Section 3.4).

Having looked at clients that get XML from a RESTful Web service, the next two sections show how to send XML to such a service. These sections also demonstrate how to pass parameters to the RESTful service as part of the URL.

3.3.3 Sending EIS Records to a REST Service without Using JWS

In Section 3.3.1, I used HttpURLConnection to implement a “pull” architecture for XML document messaging—in other words, the document is “pulled” by the client from the Web service. In a “pull” architecture, the receiver of the XML document initiates the transfer. In the code example provided, we used the HTTP GET method to serve as the request mechanism.

Sending XML to a RESTful Web service is not much different from getting XML. The main differences for the “push” architecture are that the sender initiates the transfer and the HTTP POST method is used. This architecture is used, for example, when the OMS wants to upload all new and changed orders to the CSS on a regular basis. To implement such an upload process, the CSS would need to provide a Web service where the OMS could post XML documents.

In this example, I implement a “push” architecture using HttpURLConnection.

Figure 3-5 illustrates push messaging. As you can see, it is similar to the previous example, except that the client is now the sender of messages and the Web service is the receiver. The following steps are illustrated in the figure:

1. The client uses the URL.openConnection() method to create an instance of HttpURLConnection representing a connection to the RESTful Web service’s URL. In this example, the URL has a parameter:

SourceSystem=OMS. This parameter indicates that the XML document being sent comes from the “OMS” system.
2.
HttpURLConnection.connect() begins the HTTP POST request to the Web service’s URL.
3.
The client writes the XML document to the HTTP request stream, essentially appending it to the POST request that has been started.
4.
The RESTful service processes the HTTP POST.
5.
The response—a simple “200 OK”—is sent back to the client indicating that the document has been received.

Example 3-7 shows the client-side code for implementing the HTTP POST with an HttpULRConnection. Notice that we use setRequestMethod("POST") to configure the HTTP request as a POST. After that, the connect() method initiates the HTTP request, and the remaining code writes the XML document (specified by the filename args[0]) to the output stream.

Example 3-7 Client Uses POST to Upload an XML Document to the Web Service

28 public static void main(String[] args) throws Exception {
29 if (args.length != 2) {
30 System.err.println
31 ("Usage: java PostCustomerHistory <XML file name> "
32 + "<Web Service URL>");
33 System.exit(1);
34 }
35 FileInputStream in = new FileInputStream(args
[0]);
36 URL url = new URL(args[1]);
37 HttpURLConnection con =
38 (HttpURLConnection) url.openConnection();
39 con.setDoOutput(true);
40 con.setRequestMethod("POST");
41 con.connect();
42 OutputStream out = con.getOutputStream();
43 // write the XML doc from file to the HTTP connection
44 byte[] b = new byte[1024]; // 1K buffer
45 int result = in.read(b);
46 while (result != -1) {
47 out.write(b,0,result);
48 result = in.read(b);
49 }
50 out.close();
51 in.close();
52 // write HTTP response to console
53 System.out.println(con.getResponseCode() +
54 " " + con.getResponseMessage());
55 }
book-code/chap03/rest-post/client-http/src/java/samples/
PostCustomerHistory.java

To run this example, do the following:

1. Start GlassFish (if it is not already running).
2. Go to
<book-code>/chap03/rest-post/endpoint-servlet.
3.
To build and deploy the Web service enter:
mvn install ... and when that command finishes, then enter:
ant deploy
4. Go to <book-code>/chap03/rest-post/client-http.
5.
To run the client enter:
mvn install
6.
To undeploy the Web service, go back to <book-code>/chap03/ rest-post/endpoint-servlet and enter:
ant undeploy

What you can’t see here is the form of the URL that is passed in as args[1]. To see the URL being used, you can look at the <book-code>/ chap03/rest-post/endpoint-servlet/build.xml file containing the goal used to invoke this service. You will see that the URL has the form:

http://<somepath>?SourceSystem=OMS

The parameter SourceSystem specifies where the XML document (i.e., the customer history entry) is coming from. In this example, the only value for SourceSystem that the RESTful Web service accepts is “OMS.” Try changing the URL inside build.xml to specify SourceSystem=XYZ and see what happens.

You will get an error message indicating the source is not supported yet.

The URL parameter SourceSystem is a parameter of the RESTful Web service. That is one way parameters are passed to RESTful services. Chapter 4 discusses how SOAP services get parameters—they are embedded in the SOAP message itself. You can also design a RESTful service that receives parameters in the XML document, but this is kind of like reinventing SOAP.

The REST approach of using URL parameter passing is simple, but it also has drawbacks. The primary drawback is that there is no interface description of a RESTful service, so there is no way to determine—without some other form of documentation—what URL parameters are required.

Some REST purists handle that objection by pointing out that URL parameters are not needed for proper REST systems where resources are uniquely defined by URIs. In this example, the URL could instead have the form:

http://<somepath>/OMS

In this case, the convention is that you post customer histories from the OMS to the .../OMS URI, and customer histories from the XYZ system to the .../XYZ URI, and so on.

Other REST advocates, who are slightly less purist, argue that URL parameters are fine as long as they are nouns rather than verbs. An example of a verb parameter would be something like:

http://<somepath>/ShoppingCart?action=clear

In this case, the action parameter specifies an operation to be carried out on the resource—clearing the shopping cart. Specifying verbs like this is a big REST no-no, but you can still find lots of so-called RESTful services out there that are implemented this way.

My perspective on this debate is that, even if we follow the REST purists and do away with URL parameters, we have just changed the syntax, not the semantics. The underlying semantics (and therefore the implementation) defines a resource (Customer History System) that can receive updates from various sources (e.g., OMS, XYZ), and needs to know what the source is.

If you implement that semantics by embedding parameters in the URL path—rather than by using URL parameters—you have only made the system’s interface even harder to understand. For example, when you use the URL parameter form (e.g., http://<somepath>?SourceSystem=OMS), at least you can tell that the OMS is a parameter designating the source system.

However, when you use the normalized version without parameters (e.g., http://<somepath>/OMS), you don’t get any clues as to the meaning of the “OMS."

But, in either case, REST still provides you with no way to document your interface—in other words, no WSDL. In my opinion, this is the primary reason why SOAP is more appropriate than REST for SOA-style systems integration. Doing systems integration is all about defining the interfaces between systems. If you don’t have a language in which to express the interfaces (i.e., no WSDL), it is very hard to be rigorous about defining the interfaces. As indicated in Section 3.2.1, you can try to work around this REST limitation by using XML Schema to define the interface. That approach works, but in addition to not being standard practice, it has other limitations. For example, in the case just discussed, the parameter (SourceSystem=OMS) is not part of the XML message received by the RESTful service. So, to define an interface that specifies this parameter, you would have to refactor the RESTful service to accept a parameter inside the XML message that indicates the source system.

The basic problem here is that URL parameters, since they are not part of the XML message, cannot be specified in an XML Schema-based interface definition.

This example has shown how to develop an HttpURLConnection-based client for sending XML documents to a RESTful service that requires URL parameters. The next section shows you how to do the same thing using JAX-WS 2.0.

3.3.4 Sending EIS Records to a REST Service with JWS

As in Section 3.3.2, the client in this section uses javax.xml.ws.Service and javax.xml.ws.Dispatch rather than java.net.URL and HttpURLConnection.

The major difference from that section is that here, the XML document is being pushed to the service. To do that, the XML document needs to be stored as an instance of a Java class that can be used by the Dispatch< Source> instance. In this case, the type parameter is Source, so a Source instance must be created from the XML document that is to be sent to the RESTful service.

This example also illustrates how to get HTTP-related information from the Dispatch object by accessing its response context. As demonstrated here, a bit more work is needed to get the HTTP status code than with the simple HttpURLConnection.getResponseCode() method used in the previous example.

Figure 3-6 illustrates push messaging as implemented with JAX-WS 2.0. There is a little more detail here than shown in the HttpURLConnection example from Figure 3-5. The steps are as follows:

1. The client uses the Service.addPort() method to create a port within the Service instance that can be used to access the RESTful Web service.
2. Next, the
Service.createDispatch() method is invoked to create an instance of Dispatch<Source>—a Dispatch instance that enables you to work with XML request/response messages as instances of javax.xml.transform.Source.
3.
The XML file to be posted to the RESTful service is wrapped in an instance of javax.xml.transform.stream.StreamSource. Stream- Source implements the Source type parameter required by Dispatch< Source>.
4.
The Dispatch.invoke() method then packages the XML document into an HTTP POST request—per the JAX-WS 2.0 HTTP Binding— and sends it to the RESTful service. The invoke() method waits for the response before returning.
5.
The service processes the HTTP POST and sends an HTTP response that includes an HTTP response code.
6.
Because the HTTP response code is part of the HTTP message (transport level), and not part of the XML payload, to examine it the client invokes Dispatch.getResponseContext() to get the HTTP context for the response.
7. The HTTP context is represented as a Map<String, Object> instance. This map provides access to the HTTP headers and other information that is outside the XML payload. Here, it is used to access the HTTP response code (i.e., 200 for “OK,” 500 for “Server Failure,” etc.).

Example 3-8 shows the implementation of PostCustomerHistory using JAX-WS. It is similar to Example 3-6, and you should review the discussion of REST and JAX-WS given there.

The main difference here from the HttpURLConnection version (Example 3-7) is that the Dispach.invoke() method is invoked with a StreamSource parameter that is constructed from the XML file being posted to the RESTful Web service. Notice that there is no need to write the XML out to a stream as in the HttpURLConnection example. The Dispatch< Source> instance lets you deal with the XML request and response payloads as instances of Source.

Example 3-8 The PostCustomerHistory Client as Implemented with JAX-WS

33 public static void main(String[] args) throws Exception {
34 if (args.length != 2) {
35 System.err.println
36 ("Usage: java XMLUploadSender <XML file name> "
37 + "<Web Service URL>");
38 System.exit(1);
39 }
40 QName svcQName = new QName
("http://sample", "svc");
41 QName portQName = new QName("http://sample", "port");
42 Service svc = Service.create(svcQName);
43 svc.addPort(portQName, HTTPBinding.HTTP_BINDING, args[1]);
44 Dispatch<Source> dis =
45 svc.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
46 dis.invoke(new StreamSource(new File(args[0])));
47 Map<String, Object> respContext = dis.getResponseContext();
48 Integer respCode =
49 (Integer) respContext.get(MessageContext.HTTP_RESPONSE_CODE);
50 System.out.println("HTTP Response Code: "+respCode);
51 }
book-code/chap03/rest-post/client-jaxws/src/java/samples/PostCustomerHistory.java

To run this example, do the following. After the example is run, the results (customer history entries) are written by the application to a temporary file of the form ${user.home}/tmp/soabook*.xml. So, you can look to your ${user.home}/tmp directory to verify that the example ran properly.

1. Start GlassFish (if it is not already running).

2. Go to <book-code>/chap03/rest-post/endpoint-servlet.
3.
To build and deploy the Web service enter:

mvn install

... and when that command finishes, then enter:

ant deploy
4.
Go to <book-code>/chap03/rest-post/client-jaxws.
5.
To run the client enter:

mvn install
6.
To undeploy the Web service, go back to <book-code>/chap03/ rest-post/endpoint-servlet and enter:

ant undeploy

As you can see from this example, getting the HTTP response code from the Dispatch instance is a little awkward. First, you need to request the response context. That is because Dispatch is not an HTTP-specific interface. So, it doesn’t make sense for Dispatch to have a convenience method like HttpURLConnection.getResponseCode(). The JAX-WS Expert Group envisions scenarios where Dispatch is used with non-HTTP bindings. So, the way it works is that the Dispatch.getResponseContext() method provides an instance of Map<String, Object> that contains context information about the underlying protocol.

The getResponseContext method is inherited from the javax.xml.ws.BindingProvider interface (of which Dispatch is a subinterface).

BindingProvider provides a representation of the underlying protocol binding (e.g., XML/HTTP or SOAP/HTTP) being used for Web Services communication. When a BindingProvider does a request/ response, the request and response messages are embedded in a context that is binding-specific. The message and its context move through a chain of handlers during the invocation process. All this is beyond the scope of our simple discussion here, but it is useful background (see Chapter 6 for a detailed discussion of JAX-WS client-side handlers). The response context represents the final state of the message context after the invocation is completed.

So, access to the response context is provided through the JAX-WS handler framework APIs.

The way this handler framework manifests itself here is that the keys that are used to look up information in the response context are provided by javax.ws.handler.MessageContext. As shown in the code, Message- Context.HTTP_RESPONSE_CODE is the key used to access the HTTP response code.

In the HttpURLConnection case, there is no distinction between the message and its context. One works directly with the HTTP requests and responses. So, the processing model is simpler. However, the drawback is that you have to create your own code to extract the XML messaging from the HTTP communications. In these simple examples, that doesn’t seem like a big deal. The only manifestation of that extraction process so far has been reading and writing XML to the HTTP input and output streams. However, as the complexity of the processing increases, dealing with messages rather than streams becomes a valuable additional layer of abstraction. For example, when you want to introduce handlers to do Java/XML binding or reliable messaging, you don’t want to have to create your own handler framework for pre- and post-processing of the HTTP streams.

That wraps up our basic discussion about how to invoke RESTful Web services. Next, the discussion turns to XSLT—the XML data transformation language—and how it can be used to implement basic SOA-style loosely coupled integration of multiple Web services.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.