Performing all of your application development with a single language on a single platform may be ideal, but it's not always practical. There are times when you may need to integrate a new application with a legacy one, and communication between the two can be an issue. For instance, you may desire to isolate the two applications so that the new application's design isn't compromised, and the older one can be upgraded later without impacting the newer application.
In the past, I've explored distributed computing solutions that have discussed integrating Java and C++ applications via the Java Native Interface (JNI), Java Message System (JMS), and web services; see the the "Conclusion" section at the end of this article. Although these approaches are good in the right situations, there may be times where these solutions are too complicated or just not ideal. For instance, calling into native code from Java via JNI can be complex, time-consuming, and error-prone. Using JMS requires a JMS provider be licensed, installed, and configured. And a web service requires significant development and web-based infrastructure.
Another solution is to use socket-based network communication directly between the Java and C++ applications. Although this is a relatively low-level approach, it's still an effective solution. With XML as the message protocol between them, you can maintain a degree of platform and language independence. Figure 1 illustrates this in a very simple way; here we show that a C++ application that uses Windows sockets can communicate with a Java application that uses Java IO (scenario
c) just as easily as in the two homogenous examples (scenarios
b), and with no code changes.
Figure 1: A Java application can communicate directly with a C++ winsock application.
The Socket Solution
Let's explore a sample integration solution that includes a Java application that uses
java.io to communicate with a C++ Windows application that uses Windows sockets. The Windows application supports three simple requests for the following data:
- The Windows host name
- The amount of memory installed
- A pseudorandom number
These requests are simple for illustration only, but in reality they may be requests for data only available from a legacy application or a native platform interface. All requests and responses are formatted as simple XML character strings. Specifically, both the client and server wait for data and read bytes from the network stream, with each full message delineated by a NULL — or '\n' — character.
The simple XML request messages are in Example 1. Each message has the same basic XML structure, with only the request name differing between them.
<Request> <Name>GetHostname</Name> </Request> <Request> <Name>GetMemory</Name> </Request> <Request> <Name>GetRandomNumber</Name> </Request>
Example 1: The XML request messages sent from the client, to the server.
If you need to send data along with each request, simply add one or more XML elements to the request message. For example, if you want to change the
GetMemory message to indicate the type of memory (physical or virtual) to request, the XML can be changed to look like the following:
<Request> <Name>GetMemory</Name> <Type>Physical</Type> </Request>
The response messages are similar to the requests with some obvious changes; see Example 2. The main differences are the XML response types, and the inclusion of the data being requested.
<Response> <Name>HostnameResponse</Name> <Hostname> MyServer </Hostname> </Response> <Response> <Name>MemoryResponse</Name> <TotalPhysicalMemory> 1073201152</TotalPhysicalMemory> </Response> <Response> <Name>RandomNumberResponse</Name> <Number>20173</Number> </Response>
Example 2: The XML response messages sent from the server, in response to client requests.
In this sample implementation, the actual data returned in each response will vary according to the computer it's run on. Let's begin to dive into the implementation of the solution, beginning with the Java client application.