![]() ![]() |
Enterprise Application IntegrationIn real business situations, it is not sufficient to develop Web applications with servlets alone. Integration of existing applications and business processes is more important. SkatesTown has a number of legacy applications such as order management, inventory management, and delivery systems, and is eager to integrate them. This process is called Enterprise Application Integration (EAI). A basis for EAI must be interaction models that support synchronous and/or asynchronous interactions among applications. The interaction models should include coordination of transactions over applications and a secure execution environment. Robustness, flexibility, and scalability are also required to implement the models. In this section, we describe Java 2 Enterprise Edition (J2EE) as a vehicle to perform EAI. Enterprise Java Beans (EJBs) provide a message-oriented and object-oriented component interaction model that supports both synchronous and asynchronous interactions. J2EE is a framework to integrate EJBs and other Web application components such as the servlet container. With J2EE, a request to a servlet can be performed within a transaction context in a secure manner. The rest of this section is structured as follows: First, we review a typical SOAP server architecture for EAI on the basis of J2EE. Transactions and reliable messaging are respectively described in the context of the SOAP server architecture. Finally, we review the J2EE security model, referring to the previous section. SOAP Server Based on J2EEThe J2EE specification addresses the development of new business services that combine many of the new, best-of-breed applications while leveraging previous investments in legacy systems. Because these services are architected as multitier applications including Web clients, Web servers, servlet containers, application servers, and databases, the main goal of J2EE is to reduce the cost and complexity of developing these multitier services, resulting in services that can be rapidly deployed and easily enhanced. Accordingly, J2EE is a meta-specification over a collection of existing Java standards as follows:
We will not examine all these specifications. Rather, we'll consider how to architect a SOAP server on top of J2EE. Figure 5.13 shows an initial cut of the SOAP server architecture that takes into account EAI. In this architecture, the front-end is an HTTP server, and a servlet container sits next to it. The server hosts a SOAP engine (for example, Axis), which is the heart of a SOAP server. At the back end, we might have an application server—that is, an EJB container, database, or collection of business applications. Figure 5.13. SOAP server on J2EE architecture.In the simplest case, we only have a Java program within a servlet container as in most examples mentioned so far. The Java program can access a database via JDBC, or invoke a business application via JMS. An application can be provided as an EJB (hosted by the application server). The EJB can invoke a database, a business application, or even another EJB object hosted by another application server. One of key features of J2EE is transaction support. The next section describes transactions in terms of the path of SOAP engines, EJB objects, and databases. In addition, reliable messaging is discussed, especially taking JMS into account. J2EE provides a security model that includes authorization to EJB. The J2EE security model is also discussed, clarifying further requirements for the SOAP server. Transaction ProcessingSo far, our purchase order example had been simplified so that we could focus on addressing SOAP features. However, in reality, the process is much more complicated because we might have to integrate multiple applications, data, and even business processes. In this section, we extend the purchase order example to include a transaction We include two databases in our purchase order example: Product and Order. The Product database stores product information, such as name, type, and description. Furthermore, inventory management is performed with this database so that only products in stock are sold. The Order database records purchase orders that are accepted. We have to extend our purchase order program to integrate the Product and Order databases. There are two operations in this new context:
However, simply executing these operations sequentially is not sufficient because the application might fail just after completing the first operation. In this case, the stock number in the Product database is decreased, but the order is not recorded. The result of the application should be all or nothing—that is, all of the operations must complete, or none of the operations should be allowed to complete. Such a requirement is called atomicity and is one of key properties of transaction processing. In addition to atomicity, transactions should have three other properties: consistency, isolation, and durability. These properties will be described more in detail after we review how our program can be implemented with EJB. With EJB, data resources are represented as Java objects, and transaction processing over the objects is ensured. Figure 5.14 illustrates an overview of the purchase order program, which incorporates databases with EJB. A Product object in the EJB container corresponds to a record in the product table. In the same manner, an Order object corresponds to a record in the order table. These EJB objects are called Entity Beans Figure 5.14. Purchase order processing with EJB.On the other hand, the POProcess object reads and updates data in a database on behalf of the client. A Session Bean Let's review our EJB objects. When providing EJB objects, we must implement a home interface
Let's take a closer look at some of these EJBs. Listing 5.18 is the definition of the Product EJB. Product is an interface for a product, so it defines a collection of methods to get and set data fields, such as SKU, Name, Type, and so on. POProcess uses this interface to look up and update the fields. Listing 5.18 Definition of the Product Interfacepublic interface Product extends javax.ejb.EJBObject { String getSKU() throws java.rmi.RemoteException; void setSKU(String newValue) throws java.rmi.RemoteException; String getName() throws java.rmi.RemoteException; void setName(String newValue) throws java.rmi.RemoteException; String getType() throws java.rmi.RemoteException; void setType(String newValue) throws java.rmi.RemoteException; String getDesc() throws java.rmi.RemoteException; void setDesc(String newValue) throws java.rmi.RemoteException; int getPrice() throws java.rmi.RemoteException; void setPrice(int newValue) throws java.rmi.RemoteException; int getInStock() throws java.rmi.RemoteException; void setInStock(int newValue) throws java.rmi.RemoteException; } ProductBean is the implementation of Product; therefore, it defines the set/get methods and data fields for them. In addition, it implements a collection of methods defined by the EntityBean interface, such as ejbCreate, ebjLoad, ejbActivate, and so on (see Listing 5.19). These methods are derived from an EJB object lifecycle model. The lifecycle model is beyond the scope of this book, so interested readers should refer to the EJB specification. Listing 5.19 ProductBean Classpublic class ProductBean implements EntityBean { private javax.ejb.EntityContext entityContext = null; public String sku; public int price; public String name; public String type; public String desc; public int inStock; public void ejbActivate() throws java.rmi.RemoteException {} public String ejbCreate(java.lang.String sku) throws javax.ejb.CreateException, java.rmi.RemoteException { this.sku = sku; return sku; } public void ejbLoad() throws java.rmi.RemoteException { } public void ejbPassivate() throws java.rmi.RemoteException { } public void ejbPostCreate(java.lang.String argProductId) throws java.rmi.RemoteException { } public void ejbRemove() throws java.rmi.RemoteException, javax.ejb.RemoveException { } public void ejbStore() throws java.rmi.RemoteException { } public javax.ejb.EntityContext getEntityContext() { return entityContext; } public void setEntityContext(javax.ejb.EntityContext ctx) throws java.rmi.RemoteException { entityContext = ctx; } public void unsetEntityContext() throws java.rmi.RemoteException { entityContext = null; } public String getSKU() { return sku; } public void setSKU(String newValue) { this.sku = newValue; } public String getName() { return name; } public void setName(String newValue) { this.name = newValue; } public String getType() { return type; } public void setType(String newValue) { this.type = newValue; } public String getDesc() { return this.desc; } public void setDesc(String newValue) { this.desc = newValue; } public int getPrice() { return price; } public void setPrice(int newValue) { this.price = newValue; } public int getInStock() { return inStock; } public void setInStock(int newValue) { this.inStock = newValue; } } As you can see, defining Product and ProductBean is pretty easy, because doing so is almost the same as creating ordinary Java programs. Now, how do you relate Product to the database? You do not have to change the program at all; rather, you can define the mapping to database at deployment time. It is worthwhile to mention that EJB programs are deployed with deployment descriptors, each of which declares all the EJB's external dependencies (such as the names of resources that the EJB uses). Listing 5.20 is a definition for Product excerpted from the deployment descriptor of our application. As you can see, it defines that Product is a CMP bean (see persisence-type element), specifying which fields of the CMP bean are managed by the EJB container. Note that how these fields are persisted is left to each vendor. It also must be noted that Listing 5.20 is an EJB 1.1 style deployment descriptor that is different from the format defined for EJB 2.0. Listing 5.20 Deployment Descriptor for the Product EJB<entity> <display-name>Product</display-name> <ejb-name>Product</ejb-name> <home>ProductHome</home> <remote>Product</remote> <ejb-class>ProductBean</ejb-class> <persistence-type>Container</persistence-type> <prim-key-class>java.lang.String</prim-key-class> <reentrant>False</reentrant> <cmp-version>1.x</cmp-version> <cmp-field> <description>no description</description> <field-name>name</field-name> </cmp-field> <cmp-field> <description>no description</description> <field-name>type</field-name> </cmp-field> <cmp-field> <description>no description</description> <field-name>inStock</field-name> </cmp-field> <cmp-field> <description>no description</description> <field-name>price</field-name> </cmp-field> <cmp-field> <description>no description</description> <field-name>desc</field-name> </cmp-field> <cmp-field> <description>no description</description> <field-name>sku</field-name> </cmp-field> <primkey-field>sku</primkey-field> <security-identity> <description></description> <use-caller-identity></use-caller-identity> </security-identity> </entity> Product, ProductHome, and ProductBeans are specified with home, remote, and ejb-class elements. persistence-type specifies a Container to indicate that this entity bean is CMP. The field-name element under cmp-field indicates a data field that is included in ProductBean and will appear as a column name in a database table. Because the definition of Order is inherently the same as Product, we move on to the POProcess session bean. Its core portion can be found in POProcessBean.order(). Listing 5.21 is a portion of POProcessBean. Listing 5.21 POProcessBean Classpublic class POProcessBean implements SessionBean { public Order order(String shipId, String billId, String sku, int quantity) throws POProcessException { try { Product product = productHome.findByPrimaryKey(sku); if (quantity>product.getInStock()) { throw( new POProcessException("Stock is not enough")); } product.setInStock(product.getInStock()-quantity); Order order = orderHome.create(""+System.currentTimeMillis()); System.out.println("order class: " + order.getClass() ); order.setBillTo(billId); order.setShipTo(shipId); order.setSKU(sku); order.setProductName(product.getName()); order.setQuantity(quantity); int total=quantity*product.getPrice(); order.setTotalPrice(total); if (total>MAX_TOTAL) { throw( new POProcessException("Exceed the max charge ("+MAX_TOTAL+")")); } return order; } catch(POProcessException e) { mySessionContext.setRollbackOnly(); throw e; } catch(RemoteException e) { throw new EJBException("Fail in Order.order: " +e.getMessage()); } catch(CreateException e) { throw new EJBException("Fail in Order.order: " +e.getMessage()); } catch(FinderException e) { throw new EJBException("Fail in Order.order: " +e.getMessage()); } } } In plain terms, the processes here are as follows:
The sequence of operations is performed within a transaction context although you see very few instructions related to transactions. If you use UserTransaction class, you invoke the begin() method to start a transaction, the commit() method to complete it, and the rollback() method to abort it. However, explicitly comitting and rolling back transactions is not a good practice. Rather, you are strongly advised to use container-managed transactions instead. If you take this approach, operations are performed automatically in a transactional context. Only if you want to allow rollback should you invoke setRolebackOnly() method of the SessionContext class as shown in the listing. For example, if the total charge is more than MAX_TOTAL, the update on Product and the creation of the Order object is undone. ACID and Two-Phase CommitSo far, we have only mentioned atomicity. Now, we will review the four transaction properties known as ACID (Atomicity, Consistency, Isolation, and Durability) Atomicity ensures that a computation will either terminate normally, updating the involved data resources in the intended way, or abort, updating nothing. In other words, no intermediate situation can exist where data resources are partially updated. This property should be ensured even if there is a system failure. In our example without atomicity, if we encountered a system failure, we would have a situation in which the product database is updated, but the order database is not updated. Consistency ensures that only consistent-state changes to data resources occur despite concurrent access and system failures. In our case, we have the following constraint over the product and order databases:
The consistency property relies on application programs to some extent, unlike other properties, because constraints on data are not explicitly represented. More specifically, such constraints are embedded in application logic; therefore, a transaction management system cannot monitor them. Isolation ensures that concurrent computations do not interfere with each other. In other words, the result of concurrent execution of transactions should be equivalent to the case of sequential execution. In our example, the inStock field of Product is critical data, so it requires isolation. Assume that the stock is 10, and two transactions are executed, each of which requires 8 products. Without proper isolation, or a locking mechanism, both transactions would successfully terminate as long as they both satisfy the atomicity constraint. Durability ensures that once the transaction terminates normally, its result is stored permanently. Generally speaking, termination of a transaction does not mean the completion of a database update; rather, it means that necessary information for updating is recorded. Therefore, this property is related to recovery from failure. The two-phase commit (TPC)[gl] protocol is a broadly accepted solution for ensuring the ACID properties over distributed data resources. The TPC protocol defines two types of messages: "prepare" and "commit". To complete a transaction, these messages are sent to all data resources. However, the prepare and commit messages are never mixed; therefore, the completion phase is comprised of two phases: the prepare and commit phases. This simple principle is the basis for various transaction theories. EJB wraps TPC protocols carefully so that application programmers can develop transaction processing easily and safely. Container-managed transaction is a typical example to simplify development. In summary, EJB lets you develop transaction processing properly without worrying about the details of transaction theories. Executing EJB from AxisIn this section, we execute the EJB version of the purchase order with Axis. Go to /ch5/ex5/index.jsp in the example navigator. Through the page, you can specify the shipping ID, billing ID, SKU, and quantity, and issue a purchase order (see Figure 5.15). As long as the database indicates that sufficient quantity exists to fill the order, you receive an invoice. Otherwise, you receive an error message. Figure 5.15. Example navigator GUI to invoke EJB purchase order.Listing 5.22 shows a SOAP client program for the purchase order. Listing 5.22 Client Code for Invoking an EJB Servicepublic class POProcessClient { private String url; private String urn; public POProcessClient(String targetUrl, String serviceUrn) { url = targetUrl; urn = serviceUrn; } public OrderData order(String shipid, String billid, String sku, int quantity) throws Exception { ServiceClient client = new ServiceClient(endpointURL); OrderData order = (OrderData)client.invoke(urn, "order", new Object[] { shipid, billid, sku, new Integer(quantity)} ); return order; } } As you can see, there is no difference from ordinary Remote Procedure Call (RPC) Using EJB with SOAP EnginesLet's examine how we can use EJB with SOAP engines. Our motivation for introducing EJB was to carry out EAI. EJB objects can be published externally through a SOAP engine. The example in this section has demonstrated that you can integrate multiple databases even when they are distributed in a complicated configuration. However, you might also want to integrate other kinds of applications. For example, you might have an inventory management application instead of the product database in our example. In some cases, you can use a Bean-Managed Persistence (BMP) Furthermore, the J2EE Connector Architecture Once you understand EJB transaction processing capability, a question arises: Can the SOAP engine be improved with EJB? Axis currently provides a SOAP engine that works on top of the servlet container. Let's examine how to move the SOAP engine to an EJB container. Figure 5.16 illustrates an architecture where a SOAP engine is located within an EJB container. Because requests are sent via various transports, there might be different types of listeners, such as SMTP Listeners, FTP Listeners, and HTTP Listeners. An HTTP Listener is developed as a servlet. Each listener delegates the incoming request to the EJB container via the Remote Method Invocation over Internet Inter-ORB (RMI-IIOP) protocol Figure 5.16. SOAP Engine within EJB ContainerWithin the SOAP engine, there are five handlers to process the request. First, the digital signature of the message is verified, then the message is logged, and the POProcess EJB is invoked to process the purchase order in the message. The response from POProcess, an invoice, is digitally signed and logged before being returned to the requestor. In practice, the SOAP engine would be implemented as a Stateless Session Bean and would invoke the handler chain from the EJB. If you use container managed transactions, a transaction starts automatically when the SOAP engine is invoked. So, atomicity over the update of three databases is ensured within the transaction context. This architecture is especially useful in the case of a system failure. The system might fail during execution of the signature handler in Figure 5.16. In that case, we cannot return an invoice to the requestor, and we might want to roll back the previous operations. This architecture allows us to roll back the transaction automatically so that we do not have to worry about complicated recovery sequences. A SOAP engine within a servlet can handle normal errors that are typically recognized by Java exceptions. However, it cannot handle system failures properly because such an engine does not record enough information for recovery. On the other hand, the EJB-based architecture is robust against system failure in the sense that a recovery sequence is automatically and properly carried out by the EJB container. Transactions over the InternetDean Caroll of SkatesTown now realizes the advantages of using transactions to integrate legacy applications. Transactions ensure that application data is consistently updated and simplify error handling tremendously. However, he has one lingering concern: Can we use the transaction processing model for B2B collaboration over Internet? There are some standardization efforts for modeling transaction processing onto B2B. Transaction Internet Protocol (TIP) What is the key difficulty in managing transactions over the Internet? We need to keep the two-phase commitment (TPC) protocol in mind. According to the TPC protocol, a transaction manager sends prepare messages to resource managers, and eventually receives OK messages from them. Once a resource manager sends the OK message, it has to wait for a commit or abort message from the transaction manager. This suggests that the resource manager might have to wait a while for the message. Within an intranet, we can expect each system to be stable, and thus the network to be stable. However, we cannot expect the same level of stability when relying on other companies' systems using the Internet. A more practical approach is to instead use compensation transactions, which have proper transaction models for the Internet. In our purchase order example, we can reconstruct the architecture to use compensation transactions by including two transactions (product and order databases updated with different transactions). Assume that the product database is successfully updated, but some problem occurs during the order creation. In that case, we issue a compensation transaction to cancel the update on the product database. Although ACID properties are not ensured here, many real cases can be covered with this protocol. Reliable MessagingThe EJB architecture integrates object-oriented programming with transaction processing in an elegant way. Its distributed object architecture relies on a client-server model where the client sends a request and waits for a response from a server synchronously. This synchronous invocation model fits into transaction processing model we have thoroughly reviewed. However, the synchronous model has several limitations that are crucial for EAI. Mainly, the problems are related to communication between the client and server. With a synchronous model, when a communication failure occurs, the client receives an error message. Accordingly, the client must send the identical request to the server later. In some cases, the client might not want to retry, but would prefer to have someone send the request when communication is restored. This problem can be resolved by message queuing Let's examine Java Message Service (JMS), which is a standard API for message queuing systems. First, we will update our purchase order example to include JMS. Then, we will examine the EJB 2.0 Message-driven Bean Message Queuing with JMSWe could make our purchase order program more functional by assuming that there is an order management system instead of an order database. Figure 5.17 illustrates this extension including a message queue front-ending the order management system. POProcess puts order information in the queue, and proceeds to the next operation without blocking. On the other hand, the order management system asynchronously gets the information from the queue to record the order information. Figure 5.17. Application integration with message queue.Let's rewrite our purchase order example using JMS. Listing 5.23 is a modification of POProcessBean, namely, POProcessBeanJMS. Listing 5.23 POProcessBeanJMS Classpublic class POProcessBeanJMS implements SessionBean { public OrderData order(String shipId, String billId, String sku, int quantity) throws POProcessException { try { Product product = productHome.findByPrimaryKey(sku); if (quantity > product.getInStock()) { throw new POProcessException("Stock is not enough"); } product.setInStock(product.getInStock() - quantity); OrderData order = new OrderData("" + System.currentTimeMillis()); order.setBillTo(billId); order.setShipTo(shipId); order.setSKU(sku); order.setProductName(product.getName()); order.setQuantity(quantity); int total = quantity * product.getPrice(); order.setTotalPrice(total); queueConnectionFactory = (QueueConnectionFactory) jndiContext.lookup("QueueConnectionFactory"); queue = (Queue)jndiContext.lookup(queueName); queueConnection = queueConnectionFactory.createQueueConnection(); queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); queueSender = queueSession.createSender(queue); ObjectMessage message = queueSession.createObjectMessage(); message.setObject(order); queueSender.send(message); if (total > MAX_TOTAL) { throw new POProcessException("Exceed the max charge (" + MAX_TOTAL + ")"); } return order; } catch(POProcessException e) { mySessionContext.setRollbackOnly(); throw e; } catch(RemoteException e) { throw new EJBException("Fail in Order.order: " +e.getMessage()); } catch(Exception e) { throw new EJBException("Fail in Order.order: " +e.getMessage()); } } } Note that the entity bean Order is replaced by a Java class OrderData. The typical way of using JMS, as shown in bold in the program, is as follows:
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 Classpublic 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 BeanOne 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 Classpublic 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 TransportBecause 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 Classpublic class JMSSender extends BasicHandler { private void sendMessage(MessageContext msgContext, String messageTxt) throws AxisFault { BytesMessage msg; try { queueConnection = queueFactory.createQueueConnection(); queueSession = queueConnection.createQueueSession(false, 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 Classpublic 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 InternetIn 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 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 J2EE Security ModelSo 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:
Note that we will not discuss the third method because the client is not a browser, but a standalone application. Authorization in J2EEUsing 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 JAASYou 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):
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. |
![]() ![]() |