Chapter 5. Using SOAP for e-Business
4. Create a message object and send it
Because queues can be transaction resources, they adhere to transaction management.
More specifically, when the order() method is invoked in Listing 5.23, a transaction starts automatically. Then, only when the method successfully exits is a commit message sent to the queue manager. The message is then placed into the queue where the server can get it.
Let's look at the server side, namely OrderManagementListener, which is the front end of the order management system. Listing 5.24 is an OrderManagementListener class that gets order messages from the queue.
Listing 5.24 OrderManagementListener Class
public class OrderManagementListener implements MessageListener { public static void main(String[] args) {
...
try {
jndiContext = new InitialContext();
queueConnectionFactory = (QueueConnectionFactory) jndiContext.lookup("QueueConnectionFactory");
queue = (Queue) jndiContext.lookup(queueName);
queueConnection =
queueConnectionFactory.createQueueConnection();
queueSession =
queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queueReceiver = queueSession.createReceiver(queue);
queueConnection.start();
queueReceiver.setMessageListener(this);
...
} catch (Exception e) { } finally {
if (queueConnection != null) { try {
queueConnection.close();
} catch (JMSException e) {}
} } }
public void onMessage(javax.jms.Message msg) { if(msg instanceof ObjectMessage) {
ObjectMessage message = (ObjectMessage)msg;
OrderData order = (OrderData)message.getObject();
// invoke order management system } else {
// do something
} }}
Unlike on the client side, a queue receiver object is created to get messages from the queue. We extract an OrderData object from a JMS message, then invoke the order management system with the order data. Again, the message is received only when a transaction is committed at the client side.
You can integrate applications in a loosely coupled and extensible manner with message queuing. First, the client does not have to know who receives the message. Second, even if the server is not available because of a server failure or communication problem, the client can still continue to send requests as long as the queue is available. In addition, load balancing is also possible by simply adding replications of the server.
Message-driven Bean
One of main improvements in EJB 2.0 is the introduction of the Message-driven Bean (MDB). MDB improves the programming of the server side although it does not affect the client side at all.
Let's look at OrderManagementListener again. It is a standalone Java program;
therefore, transaction management is not provided at all. You might want to invoke your order management system within a transaction context. MDBs meet such a requirement.
Listing 5.25 is OrderManagementMDB. The functionality is the same as
OrderManagementListener, but there is no code to set up a queue connection and session. In other words, basic operations for getting a message from the queue are performed by an EJB platform; accordingly, MDB just receives the dispatched messages.
More importantly, the onMessage() method is executed in a transactional context. Note that if transaction rolls back, the message receipt is also rolled back (in other words, the message is put back on the queue).
Listing 5.25 OrderManagementMDB Class
public class OrderManagementMDB implements MessageDrivenBean {
public void onMessage(Message inMessage) { ObjectMessage msg = null;
try {
if (inMessage instanceof ObjectMessage) { msg = (ObjectMessage)inMessage;
OrderData order = (OrderData)msg.getObject();
// Invoke order management system } else {
}
} catch (Exception e) { } }
}
Although OrderManagementMDB defines four methods, only onMessage() is shown here.
In contrast to OrderManagementListener, a procedure for receiving messages from the queue is not necessary. So, this class can focus on extracting the OrderData object and invoking the order management system.
MDB is convenient; however, we need an EJB container for performing it. On the other hand, the JMS client can be a standalone Java program like OrderManagementListener.
In some cases, you might use JMS directly (you might not have a proper EJB container in your platform).
JMS As a SOAP Transport
Because SOAP is transport-agnostic, you can use JMS for its transport instead of HTTP.
Furthermore, the concept of an intermediary suggests that SOAP messages can be routed to multiple nodes via different transports. Figure 5.18 illustrates a possible configuration that contains both concepts. Inter-company communication is performed via HTTP(S). The receiver company has a SOAP intermediary that receives SOAP messages via HTTP and forwards them to backend applications via JMS. The key idea here is that the external firewall allows HTTP to pass, whereas the internal firewall allows only JMS.
Figure 5.18. SOAP messaging that includes both HTTP and JMS.
This configuration is typical for several reasons. First, you can augment message processing by adding functions to an intermediary without changing the backend applications. For example, you might add digital signature verification and logging functions there. Even in that case, you do not have to change the backend applications.
In addition, some companies do not want to accept HTTP through their internal firewall for security reasons. However, strictly speaking, simply eliminating HTTP does not necessarily improve the security level. The intermediary also plays a role of security domain boundary; for example, credential mapping from external IDs to internal IDs is performed.
SOAP JMS transport is necessary especially for enterprise customers. Although Axis does not currently support JMS transport, a prototype implementation is provided in our examples. Listing 5.26 is an excerpt from the JMSSender class for the requestor side.
Listing 5.26 JMSSender Class
public class JMSSender extends BasicHandler {
private void sendMessage(MessageContext msgContext, String messageTxt) throws AxisFault {
BytesMessage msg;
try {
queueConnection = queueFactory.createQueueConnection();
queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queueSender = queueSession.createSender(queue);
msg = queueSession.createBytesMessage();
msg.writeUTF(messageTxt);
TemporaryQueue replyTo = queueSession.createTemporaryQueue();
msg.setJMSReplyTo(replyTo);
queueSender.send(msg);
queueConnection.start();
QueueReceiver receiver = queueSession.createReceiver(replyTo);
javax.jms.Message replyMsg = receiver.receive();
if (replyMsg instanceof BytesMessage) {
String replyTxt = ((BytesMessage)replyMsg).readUTF();
org.apache.axis.Message respMsg = new org.apache.axis.Message(replyTxt);
msgContext.setResponseMessage(respMsg);
}
closeConnection();
} catch (JMSException e) {
throw new AxisFault("JMSSender.sendMessage", "JMSException: " + e, null,
null);
} } ...
}
The sendMessage() method in the class implements a synchronous request/response by combining two JMS messages. It creates a temporary queue for a response, sets it as the reply-to queue in the request message, and sends the message to a request queue.
Then, it waits until a response message is delivered to the temporary queue.
Listing 5.27 is a portion of the JMSListener class for the service provider side.
Listing 5.27 JMSListener Class
public class JMSListener implements MessageListener { public void onMessage(javax.jms.Message msg) { BytesMessage bytesMsg = null;
org.apache.axis.Message respMessage = null;
MessageContext msgContext = null;
String msgTxt = null;
AxisEngine engine = AxisServer.getSingleton();
msgContext = new MessageContext(engine);
try {
if (!msg instanceof BytesMessage) { // do error handling ...
}
bytesMsg = (BytesMessage) msg;
replyQueue = (Queue)(bytesMsg.getJMSReplyTo());
sender = session.createSender(replyQueue);
msgTxt = bytesMsg.readUTF();
org.apache.axis.Message soapMessage = new org.apache.axis.Message(msgTxt);
msgContext.setRequestMessage(soapMessage);
msgContext.setTransportName(transportName);
engine.invoke(msgContext);
respMessage = msgContext.getResponseMessage();
String respString = respMessage.getAsString();
BytesMessage reply = session.createBytesMessage();
reply.writeUTF(respString);
sender.send(reply);
} catch (Exception e) { // do error handling }
} }
The central method in this class is onMessage(). Here, we get the reply queue from the incoming message and create a queue sender for returning the response. Main
processing is invoked with engine.invoke(). Finally, we respond via the temporary queue created by the sender.
To execute SOAP over JMS, visit /ch5/ex6/index.jsp in the example navigator (see Figure 5.19). Like other pages, specify some parameters and click the Submit PO button.
Figure 5.19. Example navigator GUI for SOAP over JMS.
Reliable Messaging on the Internet
In addition to transactions, SkatesTown's Dean Caroll wants to use other means to reliably transmit messages over the Internet. Unfortunately, despite some ongoing efforts, there is still no broadly accepted standard in reliable messaging. As in our
previous analysis of security technologies, we can approach this issue at the two levels:
messaging and transport.
An example of a messaging-level approach can be found in the ebXML Transport, Routing and Packaging (ebXML TRP) specification. It defines the MessageHeader element, which is present as a child of the SOAP header element; this element can contain a collection of parameters to perform reliable messaging in a transport-agnostic manner.
Although this specification is well described, it is unfortunately not broadly accepted at this moment.
JMS, as described in this section, is an approach for reliable messaging. However, it requires transport products other than HTTP, such as IBM MQ Series. Recently, IBM announced HTTPR to provide HTTP with reliability and asynchronicity features. There is some commonality between TRP and HTTPR models; for example, they both assume message handlers are present at the sender and receiver sides. Accordingly, their protocols are similar. The big difference is whether their parameters are defined as a SOAP header entry or HTTP headers. HTTPR is IBM proprietary, so whether it will be widely accepted is not certain.
J2EE Security Model
So far, we have reviewed transaction processing aspects of J2EE, focusing particularly on EJB and JMS. In addition to transaction processing, J2EE especially addresses security.
We have already reviewed security technologies such as SSL, digital signatures, and encryption. In this section, we review an end-to-end security model provided in J2EE.
Figure 5.20 depicts J2EE security architecture, which is based on a role-based access control (RBAC). The HTTP server or servlet container authenticates a requestor,
assigning roles to it. Within the servlet container, access to Web resources is authorized based on a URL permission list (not shown in the figure). Within the EJB container, access to EJB objects is authorized based on a method permission list. Permission lists are mappings between roles and target objects: Web resources and EJB objects.
Figure 5.20. J2EE security architecture.
RBAC is flexible because role assignment rules and permission lists can be independently defined. There is a trick here: A credential containing a user ID travels along the method invocation path, which can span multiple EJB containers, and roles are assigned to the
requestor at each container for authorization. This concept is especially useful when the system configuration is extremely complex.
J2EE requires compliant platforms to support the following three authentication methods:
• HTTP basic authentication
• SSL client authentication
• Form-based authentication
Note that we will not discuss the third method because the client is not a browser, but a standalone application.
Authorization in J2EE
Using BASIC-AUTH, let's review how user IDs and roles are defined in J2EE. The following is an excerpt from application.xml, which is a deployment descriptor for the overall J2EE application:
<application>
...
<security-role>
<role-name>GoodCustomer</role-name>
</security-role>
</application>
The GoodCustomer role is used in the J2EE application. J2EE does not prescribe any particular means for user definition and user-role mapping. The following is a platform- dependent format extracted from Sun's J2EE Reference Implementation:
<j2ee-ri-specific-information>
<server-name></server-name>
<rolemapping>
<role name="GoodCustomer">
<principals>
<principal>
<name>ABCRetailer</name>
</principal>
</principals>
</role>
</rolemapping>
...
</j2ee-ri-specific-information>
With this format, you can enumerate user IDs within the role element. A principal indicates a user or a user group. In this example, user ABCRetailer can have a role GoodCustomer.
Let's take a look at method permission definition for EJB objects. The following is an excerpt from ejb.xml, which is a deployment descriptor for EJBs:
<ejb-jar>
<display-name>OrderEjb</display-name>
<enterprise-beans>
</enterprise-beans>
<assembly-descriptor>
<security-role>
<role-name>GoodCustomer</role-name>
</security-role>
<method-permission>
<role-name>GoodCustomer</role-name>
<method>
<ejb-name>POProcess</ejb-name>
<method-intf>Remote</method-intf>
<method-name>order</method-name>
<method-params>
<method-param>java.lang.String</method-param>
<method-param>java.lang.String</method-param>
<method-param>java.lang.String</method-param>
<method-param>int</method-param>
</method-params>
</method>
</method-permission>
</assembly-descriptor>
</ejb-jar>
The security-role element includes a collection of roles that are referenced somewhere in this file. method-permission indicates who can access the target method with role.
role-name specifies the role name for this method permission, in this case, GoodCustomer.
Relation to JAAS
You might notice that there is some commonality between J2EE RBAC and JAAS, which we reviewed in Section "Access Control for Java Classes." A J2EE credential contains a user ID and roles. On the other hand, a JAAS subject contains a user ID and principals.
So, we can provide a mapping between roles in J2EE credential and principals in a JAAS subject. Thus, the J2EE credential and the JAAS subject converge in theory.
A potential scenario for using JAAS in J2EE is described as follows (http://www.research.ibm.com/journal/sj/401/koved.html):
"The EJB container issues a Subject.doAs( ) call to establish the credentials before invoking the EJB object. Through the EJB object's internal actions (e.g., through the ORB),
AccessController.checkPermission( ) is called to determine whether the caller is authorized for the method."
This indicates that EJB authorization could be implemented with JAAS. Although there is no standard for this purpose, JSR 115 might resolve this J2EE and JAAS migration issue.
Once the issue is resolved, we could provide a security framework that accepts
credentials (such as BASIC-AUTH, SSL client authentication, or digital signatures) and authorizes access to Web resources, Java classes, and EJB.
Quality of Service
Sophisticated e-Business Web services should be able to provide various levels of quality according to customer requirements and choices. The Quality of Service (QoS) concept originated in the communications industry, based on the portion of sent packets that is received at the target without corruption. There is a similar concept in e-Business,
although applications involving banking or air ticket reservation are still not allowed to perform erroneous operations or stop operations. This section describes an architecture for enterprise SOAP servers, paying special attention to QoS for e-Business applications.
We provide an overview of the architecture for the enterprise SOAP server, followed by a detailed treatment of the various aspects of QoS.
Enterprise SOAP Server
In the section "Enterprise Application Integration," we reviewed how to integrate existing applications with the J2EE architecture. The typical configuration is comprised of a Web server, a servlet container, some EJB Containers, Databases, and backend applications.
The Web server, Servlet container and EJB Containers portion of this configuration is related to integration. This portion is termed Web Service Container (WSC) for the sake of discussion in this section.
What happens if a WSC receives a large number of requests, beyond its capacity to process them? It is likely that the WSC will take itself offline or, worse yet, one component (such as the Web server) will crash the computer that it is running on. A known technique to avoid such a situation is to prepare clones of the original WSC for load-balancing. Once you introduce clones, the configuration becomes fairly complicated.
Therefore, you need a solid architecture to manage various aspects of the whole system, such as the status of each component and security.
Figure 5.21 illustrates an architectural overview of an enterprise SOAP server. At the heart of this architecture is a collection of Web Services Containers (WSCs). Each WSC invokes backend systems, such as the order management system, and databases. For the sake of simplification, assume that the backend systems and databases are at least as scalable as the WSCs. For example, databases are configured into a Data Area
Network in which data replication is automatically performed in preparation for a possible fail-over.
Figure 5.21. An architecture for an enterprise SOAP server.
Load-balancing, for instance, would be performed by a Round-Robin Domain Name Service (RR-DNS) and a TCP Router , which dispatches an incoming SOAP message to one of the WSCs. A system monitor checks the status of each component in each WSC and might start up another WSC clone when the load becomes too high, for example. In this complex configuration, managing end-to-end security is a difficult task.
In the enterprise SOAP server architecture, there is a single secure domain where all security information is managed; this information is the basis for all security decisions.
Note that the architecture for the enterprise SOAP server shown in Figure 5.21 is not necessarily the best architecture. To come up with the best architecture, the business and system requirements must be considered. However, the architecture in Figure 5.21 does clearly show what aspects should be considered for the purpose of developing an e- Business QoS. Each aspect is discussed in detail in the following sections.
High Availability
Availability is an obvious QoS requirement because users generally expect that services are always, or very nearly always, available. If a service is frequently unavailable, users stop relying on its service provider. An airline ticket reservation system, for example, requires 99% availability; the service can be unavailable for only two hours per week.
Load-balancing is a means to achieving high availability, especially in terms of increasing the scalability of the system. As shown in Figure 5.21, it combines two techniques: RR- DNS and the TCP Router. A Domain Name Service (DNS) maps domain names
(hostnames) to IP addresses, and the round-robin variety of DNS allows a hostname to be mapped to one of several IP addresses. An IP address is chosen in round-robin
manner, meaning that consecutive requests are assigned to the available IP addresses in a pre-determined sequence, repeating itself at the end of the sequence. HTTP redirect is often used instead of RR-DNS for the same purpose. When a client accesses a server, the server responds with a redirect instruction to one of the available hosts. One
disadvantage of this approach is that URLs of the target hosts are visible and then are potentially stored on the client side (such as in a browser's recent URL list or a
bookmark), and the client might directly access this URL in subsequent requests. Thus, the purpose of load-balancing might be defeated.
Using TCP routers, you can configure clusters to scale up processing power. A TCP router forwards incoming requests to WSCs. Although the router's name and IP address are public, the addresses of WSCs are hidden from the client. The TCP router could use a load-based algorithm to select a target WSC, or simply adopt the round-robin process.
There are many commercially available TCP routers, such as IBM Network Dispatcher (ND). ND can run on several operating systems, such as Windows, AIX, and Solaris, and can forward up to 10,000 messages per second when it runs on an embedded OS. In addition to the TCP router approach, you can use a technique called Network Address Translation (NAT) . NAT dynamically edits a particular IP packet header to change the destination address, and edits the return packet in the same manner. Cisco Local Director is an example of a commercial product for NAT.
Scaling up the system with load-balancing techniques might decrease the risk of system failure, but system failure can still occur. But WSC clones, in addition to being used to increase scalability, can also serve as a backup of the original WSC, taking over the processing when the WSC fails. This introduces the system properties of redundancy (using clones for possible backup) and fault tolerance (performing an automated procedure in case of fail-over).
Another issue related to system failure is recovery. Generally speaking, recovery requires the system to perform a complicated recovery sequence. For example, some kind of status indicator might be recorded at certain checkpoints, and the recovery process might rely on the status history. However, because the SOAP server uses transaction processing, there need not be such a complicated recovery sequence in the enterprise server architecture. By definition, operations within a transaction context are committed or aborted. Therefore, in the event of a system failure, the EJB containers will perform most of the recovery sequence on behalf of applications.
System Management
In order to completely fulfill the requirement for high availability, system management must also be considered. Because the configuration of real e-Business systems is fairly complex, as shown in Figure 5.21, there needs to be a systematic means to manage the whole system. Ideally, there would be a single point of management, from which even system resources at other sites can be managed. System management might include the following tasks:
• Monitoring the status of system resources
• Sending alert information to system administrators
• Remotely configuring, deploying, and controlling system resources
• Automatically resolving system resource issues if possible
Typically, system management requires agents, each of which monitors one or more system resources and continuously sends information to the system monitor. Because sending too much information unduly consumes network bandwidth, a proper filtering mechanism is also required.