Up until now the only strategies discussed have been related to the Message Oriented Middleware. To add a new flavor to the discussion, the next sections explore asynchronous integration of Java and .NET applications using Internet e-mail. Internet e-mail servers are used today to connect diverse sets of e-mail clients across different platforms. Desktop e-mail clients and Internet e-mail clients retrieve e-mails from an e-mail server. Most of the e-mail servers including Microsoft Exchange Server and Sun Java System Messaging Server support standard messaging protocols such as Simple Mail Transfer Protocol (SMTP), Post Office Protocol (POP), and Internet Message Access Protocol (IMAP). An important thing to remember with these protocols is the following: E-mail servers use the SMTP protocol to send messages, and e-mail client applications use POP and IMAP protocols to receive messages. Their latest versions are IMAP4 and POP3. Details on individual protocols can be found at [SMTP], [POP3], [IMAP], in the "References" section of this chapter. ScopeBusiness requirements often employ message notification upon finishing request processing or as alert notification when an unexpected error or a failure occurs during request processing. For example, in the Replenish Stock scenario, upon order request validation a notification has to be sent to the WarehouseCallback system. For these types of requirements, developers may use an e-mail infrastructure to interchange messages between Java and .NET applications. SolutionAn SMTP/POP messaging server provides store and forward functionality on the incoming messages, thus guaranteeing message delivery. Both Java and .NET provide Mail APIs to send and receive e-mail messages and can be used to achieve interoperability between Java and .NET applications. Following are a couple examples of sending messages via standard mail APIs. On the .NET side, a System.Web.Mail.SmtpMail library is used to send a MailMessage: MailMessage mail = new MailMessage(); // Set From, To, Subject, Body, and SmtpServer properties SmtpMail.Send(mail); On the Java side there are javax.mail libraries to achieve the same: Listing 9-37. Sending E-mail from Java
Similarly, these Mail APIs can be used to retrieve messages from the server. A .NET or Java client application uses a POP3 protocol to send and access messages. A standard SMTP/POP messaging server receives and sends messages over SMTP transport layer. Figure 9-15 is a high-level diagram outlining the communication flow between the SMTP server and client applications. Figure 9-15. SMTP/POP communication flow
As SOAP messages become the de facto data interchange format, achieving Java EE .NET interoperability with SOAP over SMTP communication is the strategy discussed in this section and is used to build an example. Using SOAP to represent the data contributes to a higher degree of flexibility and interoperability. This example shows how SOAP messages can be sent and received over the SMTP protocol layer with Java and .NET. For that, JAXMail Java APIs and Microsoft Web services Enhancements for Microsoft .NET(WSE) release 2 are used, which extends the .NET Framework and Visual Studio .NET with ability to send SOAP messages over different transport protocols such as TCP or SMTP. See [JaxMail], [JaxMailRI], and [WSE] for more information. This example continues to use WS-I Replenish Stock use case, where a Java Retailer and the .NET Manufacturer system exchange Purchase Order and Shipping Notice information accordingly. The sequence diagram in Figure 9-16 outlines core classes that developed to implement this scenario: Figure 9-16. Exchanging SOAP over SMTP messages between Java and .NET applicationsBenefits and LimitationsThe main advantage of this design is that asynchronous integration between Java and .NET can be achieved without having to invest into a proprietary interoperability solution or having to build custom adapters. Instead, asynchronous integration can be achieved with a messaging infrastructure that most companies already deploy in-house. A client application can be fully offline and yet retrieve messages as needed. An SMTP server persists messages and guarantees their availability to the client. Reliable MessagingCompared to a MOM solution, this strategy does not fulfill a traditional requirement for reliable messaging. With e-mails there is typically no guarantee of delivery. The SMTP messaging infrastructure offers guaranteed delivery of messages via Delivery Status Notification (DSN) and Message Disposition Notification (MDN). But even with guaranteed message delivery, the once-and-only-once constituent of reliable communications may not be satisfied. Messages may get delivered more than once, which may not be an issue with the given application requirements. SecurityIn this strategy, an e-mail message invokes a Web service. Considering security vulnerabilities with desktop applications such as Outlook or Internet Explorer, this scenario needs to be carefully reviewed prior to deploying in production. When using this strategy various security implications need be assessed to minimize potential security breaches. ExampleIn the previous examples, the environment primarily consisted of a messaging server such as MSMQ or JMS provider and other components. This example uses an SMTP/POP server as the middleware infrastructure. See "References" for individual solutions and library downloads [SmtpWin2000]. Setting Up the EnvironmentTo develop a Replenish Stock scenario with SMTP server, Apache Java Enterprise Mail Server (James) is used, [James]. It supports SMTP for sending and POP3 for receiving transport protocols. As mentioned earlier, the JAXMail library is also used, which extends JAX-RPC with support for SMTP transport protocol. JAXMail architecture documentation outlines individual steps of setting up the environment, including James server. To begin the example, the James mail server needs to be started, and two users created, Retailer and Manufacturer. You can achieve this by using telnet to access the mail server's remote manager, and then executing the 'adduser' command, telnet localhost 4555 adduser retailer java adduser manufacturer dotnet where the retailer is a user with the password java and the manufacturer user has the password dotnet. E-mail messages can now be exchanged between Java Warehouse and .NET Manufacturer systems. Because this example uses JaxMail extensions to JAX-RPC, the ${jwsdp.home}/jaxrpc/lib/jaxrpc-ri.jar needs to be replaced with this one: https://jaxmail.dev.java.net/jaxrpc-ri.jar. This applies to both development environment of the Java Web services Development Pack and runtime environment of the Tomcat's JAX-RPC library. The sample application that comes with JaxMail needs to downloaded as this example references it throughout. The IIS server also needs to be started. This is done by starting Computer Management and simply entering compmgmt.msc at the Start/Run text field and selecting Services and Applications. Right click the IIS Manager and select Reconnect to localhost or the Refresh option. For building .NET SOAP over SMTP Manufacturer system, WSE 2.0 should first be downloaded and installed. Place the Microsoft.Web.Services2.dll under the mail/lib directory to be accessible to the build.xml file. In the .NET portion of the code, this example uses Steve Maine's sample of SMTP transport for WSE. Download and extract the Soap over SMTP sample code, [SteveMainSoapSmtp], under the src/manufacturer/SoapSmtp directory. As you may notice, this sample code references Pawel Lesnikowski's POP3 library Mail.dll, [PawelLesnikowskiMail], that is needed to build the code. Download and place the Mail.dll under mail/lib directory and also copy Mail.dll into the mail/ directory to be accessible by the final executable. All links for downloading individual libraries are listed in the "References" section. Building the Retailer SystemThe implementation starts with a Retailer Web service that allows a client application to send SOAP messages over SMTP. Figure 9-17 outlines the high-level diagram of Retailer components: Figure 9-17. Retailer System Integrated with SMTP Server
The Warehouse interface and the WarehouseImpl class implement the Web service endpoint, Retailer Web service. Listing 9-38 shows the code for Warehouse classes: Listing 9-38. Warehouse Class
Basic implementation of this interface is listed in WarehouseImpl.java, Listing 9-39. Listing 9-39. WarehouseImpl.java Class
To deploy this Web service under Tomcat, the Web server should be started and the Web service needs to be deployed in a standard way. The Web service then can be viewed by browsing to the following site, see Figure 9-18: Figure 9-18. JaxMailWarehouse Web serviceClient stubs can now be generated based on the deployed Web service. Java Client ApplicationOn the client side, the SendMailClient.java class accesses the send a SOAP message over SMTP. First the Web service stub, Warehouse_Stub, needs to be accessed: JaxMailService_Impl service = new JaxMailService_Impl(); Warehouse_Stub wh =(Warehouse_Stub)service.getWarehousePort(); Using this stub sets corresponding properties such as user name, SMTP server parameters, and subject to send an e-mail message, Listing 9-40: Listing 9-40. Setting JAX-Mail Properties
For testing purposes, to preview the SOAP message, a ClientHandler.java class has been created. The source code for the ClientHandler class can be found in the j2eedotnet.chapter9.mail.handler package. This class intercepts the SOAP message before it is sent to the e-mail server and displays the SOAP message on the console. Listing 9-41 shows SendMailClient code of handler registration with the Web service: Listing 9-41. Registering ClientHandler class
Next step for the client application is to submit the PurchaseOrder request to the Web service. For that, the SubmitPO stub class is instantiated, which has been auto-generated based on the deployed service and has passed the po object to the Web services' submtiPO() method: SubmitPO po = new SubmitPO("PurchaseOrder_123"); SubmitPOResponse response = wh.submitPO(po); System.out.println("PO_123 Submitted"); WarehouseCallbackBefore running the client code, this section takes a brief look at the Java WarehouseCallback class. The WarehouseCallback is responsible for retrieving messages from the SMTP server by polling the server for messages within a given interval. Once the .NET Manufacturing system, discussed next, asynchronously processes the PurchaseOrder, it sends back the ShippingNotice. This Shipping Notice is received by the WarehouseCallback component. To run the callback, there needs to be a set value for the corresponding user and SMTP server. These values are passed to JaxMail's com.jaxmail.MailDownloader class: MailDownloader client = new MailDownloader("retailer","java","localhost",30,"pop3"); The JaxMail sample application provides a class, TestMailHandler, to perform sample polling functionality, which we re-use in this code sample. To reuse the class, download and place the TestMailHandler.java file under the same directory as the WarehouseCallback.java file and modify the package name to package j2eedotnet.chapter9.mail.client. Here is the remaining logic of WarehouseCallback's main() method: client.setHandler(new TestMailHandler()); client.start(); The preceding logic includes setting the e-mail handler and starting to listen on the known port for incoming e-mail messages. Running the SendMailClientIt is now time to compile and execute the client application. Running the client after the initial build produces the output shown in Listing 9-42: Listing 9-42. Output of Submitting the Purchase Order by SendMailClient Class
To follow the business logic of the Replenish Stock use case, this example now shifts to the .NET programming and builds the Manufacturer system. Building Manufacturer SystemFirst of all it's important to ensure that the soap.smtp sample C# classes, listed under the "Environment Setup" section earlier, are available for build process. The main Manufacturer.cs class uploads the configuration file for the e-mail user and server configurations and invokes POValidator to asynchronously retrieve messages. Core logic of the Main method is shown in Listing 9-43: Listing 9-43. Manufacturer Class
The POValidator calls Mailbox's asynchronous BeginRecieve() method, passing the ProcessResponse's GetPOStatus() method for asynchronous callback (refer to Listing 9-44): Listing 9-44. POValidator's Receive Method
The ProcessResponse class has two important methods. The first one is GetPOStatus, which is passed as a callback to the mailbox.BeginReceive() method. GetPOStatus invokes Mailbox's EndReceive() method to retrieve the SOAP message from the SMTP server. Assuming that the message contains a valid PurchaseOrder request, the GetPOStatus calls the send() message, discussed hereafter. Listing 9-45 shows the GetPOStatus() method: Listing 9-45. PurchaseOrder's GetPOStatus Method
In the preceding code, aside from the described logic, System.Diagnostics is used. TextWriterTraceListener is used as the writer variable that follows, to record e-mail retrieval to the console. The writer is initialized in the init() method: writer = new TextWriterTraceListener(System.Console.Out); Trace.Listeners.Add(writer); The last line of the GetPOStatus() method calls a send() routine that prepares a ShippingNotice SOAP message and sends it to the retailer (see Listing 9-46): Listing 9-46. ProcessResponse's Send Method
Before compiling the .NET Manufacturer classes, corresponding parameters of the Mailbox.cs class need to be configured to ensure that messages between the retailer and the manufacturer users created earlier are exchanged. For that, in the Mailbox.cs file, application settings must be modified to match ones specified in the Manufacturer.config file. The configuration file is located under the same directory as the build.xml filespecifically, in the private void Receive() method, configure host, user name, and password as follows: string server = ConfigurationSettings.AppSettings["MailServer"]; string username = ConfigurationSettings.AppSettings["UserFrom"]; string password = ConfigurationSettings.AppSettings["Password"]; In the same file, that is, Mailbox.cd, within the MailClientAsyncResult class definition section, for testing purposes comment out creation of the new thread pool for asynchronous invocation of the Receive() method. Instead the Receive() operation is explicitly invoked, passing an arbitrary state: // ThreadPool.QueueUserWorkItem( new WaitCallback( this.Receive )); this.Receive("state1"); Finally, in the Send() message of the Mailbox class, modify the target user information and a subject based on the configuration file parameters, as shown in Listing 9-47: Listing 9-47. Outgoing Message Configuration
Running the Manufacturer ApplicationEnsure that all classes and libraries such as Mail.dll and Microsoft.Web.Services2.dll are available under lib directory. Compiling the Manufacturer application results in the Manufacturer.exe executable. Running the Manufacturer.exe produces an output corresponding to the Purchase Order SOAP received from the Retailer system and the ShippingNotice that it sends back to the Retailer. Listing 9-48 lists the output: Listing 9-48. Running Manufacturer Application
On the Retailer side, it's time to start the WarehouseCallback listener to receive the ShippingNotice. Listing 9-49 lists the output from the WarehouseCallback program: Listing 9-49. Running WarehouseCallback Application
In summary, the example developed in this section discusses how to interoperate between Java and .NET using an SMTP server as the messaging middleware and exchange SOAP messages across two applications. |