You are on page 1of 16

Enterprise Integration Using Dependency Injection

Page 1 of 16

Table of Content
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. Introduction..................................................................................................................... 3 IOC Design Pattern ......................................................................................................... 3 How Multipart HTTP requests are resolved. .................................................................. 4 File Upload Using Spring Frame work........................................................................... 4 File Validations:.............................................................................................................. 8 Data Validations: ............................................................................................................ 8 Handling Referential Data .............................................................................................. 9 Performance Considerations: ........................................................................................ 10 All or None processing/Grouping of Data .................................................................... 10 Batch States............................................................................................................... 10 Delegate Discovery Using Type 2 Dependency Injection........................................ 10 Setting up Spring (Detailed) ..................................................................................... 11 Testing File Upload Controller ................................................................................. 15 Sequence Diagram .................................................................................................... 16

Page 2 of 16

1 Introduction
Enterprise Application Integration (EAI) is a rapidly growing segment in enterprise computing. Multiple forces are driving this trend. Many of them center on rapidly changing business needs and opportunities driven by the Internet, merger/acquisitions, competition, regulation, and deregulation. Increased attention on Customer Relationship Management (CRM) and supply chain integration in many industries is driving the demand for intra- and inters enterprise system integration. Rapidly integrating applications across an enterprise is becoming more and more imperative to staying competitive in todays marketplace. A large portion of IT budgets is spent on integrating applications: bridging heterogeneous computing environments, connecting new and legacy applications, and linking internal and external resources. Information systems in most companies are a mixture of computing platforms, software applications, data schemas, and business processes. The mainframe in one location cant communicate instantaneously with workstations in another. The Accounts Receivable system may not have the same data schema as the CRM system. For example, when customer service representatives need to access customer information, they must access separate data stored in a CRM database and then open a financial application that is completely disconnected.

2 Dependency Injection Design Pattern


Dependency Injection (earlier known as Inversion of control or IOC) technique solves the EAI problem and applies to large EAI projects very well. There are three main benefits of IOC

The classess are more resuable It easier to test the classes It's easier to assemble systems and configure.

The problem with small working applications that become large is that static-method entanglement does not scale. One part of a system that's otherwise fairly self-contained statically accesses another part of the system and cannot be instantiated without invoking methods in the latter. Thus it can't easily be isolated for unit testing. What's more, it can't be developed as an independent component. Components that are developed separately can have their own development teams and may well be part of a larger design. These components will have their own source control directory and can be developed against mock implementations of their dependent components. All this will help overall development become faster, in terms of both the team's efficiency and the build time.

File processing handling will not handled as part of this design. That would be handled separately. The scope is to cover the client side design in as de-coupled a fashion as possible.

Page 3 of 16

3 Using Spring Framework for Dependency Injection


This articles demonstrates how spring framework can be used for EAI, using a very simple example of uploading a file to a server. File upload functionality will be provided through the web interface. Following would be the features. The articles starts with providing some preliminaries on what components involved in a file upload operation then later goes into the implementation details on such a system, using spring framework.

1. How Multipart HTTP requests are resolved.


Servlet containers provide implementations for HTTPServletRequest, for instance tomcat provide CoyoteRequest as the implementation for HTTPServletRequest. Default Encoding for fileType is ISO-5589-1 Following code shows how the content type is resolved to multipart in an HTTPServletRequest
public static final boolean isMultipartContent(HttpServletRequest req) { if (!"post".equals(req.getMethod().toLowerCase())) { return false; } String contentType = req.getContentType(); if (contentType == null) { return false; } if (contentType.toLowerCase().startsWith(MULTIPART)) { return true; } return false; }

2. File Upload Using Spring Frame work


Spring has built-in multipart support to handle fileuploads in web applications. The design for the multipart support is done with pluggable MultipartResolver objects, defined in the org.springframework.web.multipart package. Out of the box, Spring provides MultipartResolvers for use with Commons FileUpload (http://jakarta.apache.org/commons/fileupload) and COS FileUpload (http://www.servlets.com/cos). How uploading files is supported will be described in the rest of this document. By default, no multipart handling will be done by Spring, as some developers will want to handle multiparts themselves. You will have to enable it yourself by adding a multipart resolver to the web application's context. After you have done that, each request will be inspected to see if it contains a multipart. If no multipart is found, the request will continue as expected. However, if a multipart is found in the request, the MultipartResolver that has been declared in your context will be used. After that, the multipart attribute in your request will be treated like any other attribute. The Commons FileUpload package makes it easy to add robust, high-performance, file upload capability to servlets and web applications. FileUpload parses HTTP requests that conforms to RFC 1867, "Form-based File Upload in HTML". That is, if an HTTP request is submitted using the POST method, and with a content Page 4 of 16

type of "multipart/form-data", then FileUpload can parse that request, and make the results available in a manner easily used by the caller. Generally, there are following components in a spring based web application 1) Multipart resolver configuration: There would be three resolver a. CommonsMultipartResolver: This will be used for handling files via the Jakarta commons framework. This has a max size limit of 1 MB.

b. CosMultipartResolver: This will be used for handling files OReilly (COS) package.. This has no documented max size limit. The max size limit would need to be tested.

c. epCabViewResolver: This will be developed by the epcab development. This would not have any size limitations. This configuration will be done in the action-servlet.xml file, as follows Page 5 of 16

<!-- Configure the multipart resolver for Jakarata Commons: Jan 25 2006 > <bean class="org.spfw.web.servlet.multipart.commons.CommonsMultipartResolver"> <!-- maximum file size is 1 Megabyte --> <property name="maxUploadSize"><value>1048576</value></property> </bean>

2) Controller for uploading the file: The controller will be part of a package called com.epcab.controllers.fileupload named FileUploadController. This controller will extend from org.springframework.web.servlet.mvc.AbstractController.

3) The actual form to upload the file (fileupload.jsp): On the client side, the client's browser must support form-based upload. Most modern browsers do, but there's no guarantee. For example, <FORM ENCTYPE='multipart/form-data' method='POST' action='/myservlet'> <INPUT TYPE='file' NAME='mptest'> <INPUT TYPE='submit' VALUE='upload'> </FORM> The input type <INPUT TYPE='file' brings up a button for a file select box on the browser together with a text field that takes the file name once selected. The servlet can use the GET method parameters to decide what to do with the upload while the POST body of the request contains the file data to parse. When the user clicks the "Upload" button, the client browser locates the local file and sends it using HTTP POST, encoded using the MIME-type multipart/form-data. When it reaches the

Page 6 of 16

servlet, the servlet must process the POST data in order to extract the encoded file. This is in format RFC 1867. The fileUploadBean will be used for handling the uploaded files. The fileType parameter of the fileUploadedBean will be used for determining the type of a particular type for example EOJ files will be determined by say fileType of EOJ_FILE_TYPE. A fileType needs to be added to system to support a new file Type. 4) Upload Lifecycle of a File: Following are the stages in the lifecycle of an Upload. Most of the states are self-explanatory.

Lifecycle States

Upload File

Preview File

Edit File

Submit File

View Errors

View Success

5) Lifecycle Views: An abstract class AbstractFinder will resolve the lifecycle view. There would a concrete implementation for each of the lifecycle state views. As shown below.

Page 7 of 16

If a new file state is needed based on new business requirements then this design can be easily extended by adding a new ViewFinder class.

3. File Validations:
There are following two aspects to file validations 1) Identifying the error: There would be two components of the design. A custom parser for each application context (file type), there would be one-to-one mapping between the application context and file types and similarly one custom validator for each file type. 2) Displaying this error: The errors will be displayed using custom jstl tags for each type or context in which the file is uploading. A tag library will be created for the epcab project.

Activity Diagram
File File Upload Controller Parse File

Client

Errors Error Page Generate Error View Validate File

No Errors Staging Service

4. Data Validations:
There are two types of data. Self Contained Data: In this case, you have a set of self-contained data with respect to a specific rule. By self contained I mean that all the data elements refer to the data with in that set as an example take the case, when a cab driver is uploading the data about the services it performed, into the system of the cab company using a file. This file has one row for each service performed. Let's say you have rule that would say the trip charges couldnt exceed, the service fee plus tolls. Now the data with respect to this rule is self contained. I would call these rules as Self Contained Rules Page 8 of 16

Referential Data: When in order to apply a rule more data is needed from an external system or a database, such rules are called Non- Self Contained Rules. Taking the previous example if the rule says that the service needs to have been performed against a valid reservation number, then in order to execute the rule a lookup needs to be made into the database to get the list of valid reservation numbers. In this case the data in the file itself is not sufficient to execute the rule. While executing such rules we need to take extreme care, as these rules can be very performance extensive. For each record, there could be multiple data base calls going back and forth.

5. Handling Referential Data


There can be three possible sources of referential data 1) Coming from a database connectible via JDBC: An example of such a case can be the vendor invoice number, which might be stored into another database table, in order to validate a file record for valid file record the following parameterized query would need to be written Select count (*) from Vendors_Invoices where vendor_invoice_id = <tripRecord.vendor_invoice_id> In this the rule will fail validation, if the count is zero, the rejection message would be something like The invoice has been reject, as the vendor invoice number is invalid The rules engine needs to be able to support, query based rules. The structure of a rule in the rules definition file would look like as follows <rule> <rule_type>DATABASE_BASED</rule_type> <rule_data_source>epcab_data_source</rule_data_source> <rule_condition> Select count (*) from Vendors_Invoices where vendor_invoice_id = <tripRecord.vendor_invoice_id> </rule_condition> <rule_result> The vendor invoice number <tripRecord.vendor_invoice_id> is not found. <rule_result> </rule> 2) Coming from a service: The external service could be accessible via service interface. 3) Coming from a legacy system: This type of data is accessible through an enterprise adapter.

Page 9 of 16

6. Performance Considerations:
The files can sometimes be very big, for example a file may contains say 10,000 records and if each records processing takes even a fraction of a second the overall processing time can be a few minutes or may be more than that. In that case the user would need to be notified of the incremental status and should have the option of canceling the processing. The possible options for incrementally displaying the data to the user are - Use HTML refreshes: This option works and can give the incremental status updates to the user, but has bandwidth overhead. Every time entire page is re-rendered on the server side taking - Use xmtHTTPObject: using this object the data from the server can be obtained incrementally and rendered in the browser.

7. All or None processing/Grouping of Data


Sometimes, the file / batch can contain logically related data spanned over a few rows. For example a trip cost might consist of a sub-trips, the total cost for a trip might consist of sum of costs for each sub-trip. In the file, each trip might be a separate line item. In such scenarios, the user should be able to specify how to group the data. The user of the system might want to the system should be able to commit that data at the group level.

8. Batch States
Each file submitted to the system will be accepted as a batch by the system. A unique batch number identify each batch will. Each batch will go through the following states Validating: After the submission of a batch the batch data will first be validated. All errors will be incrementally notified to the user. Submitting: During processing the data will be sent to the appropriate service for processing. The incremental progress will be retrieved and sent back to the client. Any errors. User will have the option of canceling the submission at any stage; any uncommitted transaction will be rolled back.

9. Delegate Discovery Using Type 2 Dependency Injection


The delegate discovery from the presentation tier will make use of the dependency injection feature available in the spring framework. This has the following benefits De-couples the presentation tier from the business layers. The delegate and hence the underlying business layer can be developed independent of the presentation and vice-versa.

Following are the steps involved injecting the business delegate into the controller Page 10 of 16

1. Identify the business delegate class, in this case the business delegate class is com.epcab.delegates.StagingDelegate. 2. Modify the action-servlet class to add a property to the fileUploadForm bean.
<bean id="fileUploadForm" class="com.epcab.controllers.FileUploadController"> <property name="sessionForm"><value>true</value></property> <property name="commandName"><value>fileUpload</value></property> <property name="commandClass"><value>com.epcab.commands.FileUpload</value></property> <property name="validator"><ref bean="fileUploadValidator"/></property> <property name="formView"><value>fileupload</value></property> <property name="successView"><value>hello.htm</value></property> <property name="delegateClass"><value>com.epcab.delegates.StagingDelegate</value></property> </bean>

10. Setting up Spring (Detailed)


Following steps are involved to setup the FileUpload functionality in the epcab development framework. 1) Adding org.spfw.web.servlet.multipart.commons.CommonsMultipartResolver to the classpath: As we will configure spring to use Jakarta CommonsMultipartResolver, this would at runtime need to find this file in the classpath. Same applies also to Cos library too, cos library, can be downloaded from www.servlets.com 2) Create the form in action-servlet.xml
<bean id="fileUploadValidator" class="com.epcab.validators.fileUploadValidator"/> <bean id="fileUploadForm" class="com.epcab.controllers.fileUploadController"> <property name="sessionForm"><value>true</value></property> <property name="commandName"><value>fileUploadCommand</value></property> <property name="commandClass"><value>com.epcab.command.fileUpload</value></property> <property name="validator"><ref bean="priceIncreaseValidator"/></property> <property name="formView"><value>fileUploadView</value></property> <property name="successView"><value>hello.htm</value></property> </bean>

3) Create the command file


/* * Created on Jan 26, 2006 * * TODO To change the template for this generated file go to * Window - Preferences - Java - Code Style - Code Templates */ package com.epcab.commands; /** * @author Carey * * TODO To change the template for this generated type comment go to * Window - Preferences - Java - Code Style - Code Templates */ public class FileUploadCommand { private byte[] file;

Page 11 of 16

/** * @return Returns the file. */ public byte[] getFile() { return file; } /** * @param file The file to set. */ public void setFile(byte[] file) { this.file = file; } }

4) Create the validator file


package com.epcab.validators; import java.io.Serializable; import org.springframework.validation.Validator; import org.springframework.validation.Errors; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class FileUploadValidator implements Validator { private int DEFAULT_MIN_PERCENTAGE = 0; private int DEFAULT_MAX_PERCENTAGE = 50; private int minPercentage = DEFAULT_MIN_PERCENTAGE; private int maxPercentage = DEFAULT_MAX_PERCENTAGE; /** Logger for this class and subclasses */ protected final Log logger = LogFactory.getLog(getClass()); public boolean supports(Class clazz) { return clazz.equals(PriceIncrease.class); } public void validate(Object obj, Errors errors) { PriceIncrease pi = (PriceIncrease) obj; if (pi == null) { errors.rejectValue("percentage", "error.not-specified", null, "Value required."); } else { logger.info("Validating with " + pi + ": " + pi.getPercentage()); if (pi.getPercentage() > maxPercentage) { errors.rejectValue("percentage", "error.too-high", new Object[] {new Integer(maxPercentage)}, "Value too high."); } if (pi.getPercentage() <= minPercentage) { errors.rejectValue("percentage", "error.too-low", new Object[] {new Integer(minPercentage)}, "Value too low."); } } } public void setMinPercentage(int i) { minPercentage = i; } public int getMinPercentage() { return minPercentage; } public void setMaxPercentage(int i) { maxPercentage = i; } public int getMaxPercentage() {

Page 12 of 16

return maxPercentage; } }

5) Specify the form view:


<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/hello.htm">springappController</prop> <prop key="/priceincrease.htm">priceIncreaseForm</prop> <prop key="/upload.form">fileuploadController</prop> <prop key="/fileupload.htm">prefileuploadController</prop> <prop key="/fileUploadView.htm">fileUploadForm</prop> </props> </property> </bean>

6) FileUploadController Sample Code:


package com.epcab.controllers.fileupload; import org.springframework.web.servlet.mvc.SimpleFormController; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.view.RedirectView; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Map; import java.util.HashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import bus.Product; import bus.ProductManager; import bus.PriceIncrease; public class FileUploadController extends SimpleFormController { /** Logger for this class and subclasses */ protected final Log logger = LogFactory.getLog(getClass()); private ProductManager prodMan; public ModelAndView onSubmit(Object command) throws ServletException { int increase = ((PriceIncrease) command).getPercentage(); logger.info("Increasing prices by " + increase + "%."); prodMan.increasePrice(increase); String now = (new java.util.Date()).toString(); logger.info("returning from PriceIncreaseForm view to " + getSuccessView()); return new ModelAndView(new RedirectView(getSuccessView())); } protected Object formBackingObject(HttpServletRequest request) throws ServletException { PriceIncrease priceIncrease = new PriceIncrease(); priceIncrease.setPercentage(20);

Page 13 of 16

return priceIncrease; } public void setProductManager(ProductManager pm) { prodMan = pm; } public ProductManager getProductManager() { return prodMan; } } 1) Modify the supports method in the validator class

import com.epcab.commands.fileUpload; public class FileUploadValidator implements Validator { private int DEFAULT_MIN_PERCENTAGE = 0; private int DEFAULT_MAX_PERCENTAGE = 50; private int minPercentage = DEFAULT_MIN_PERCENTAGE; private int maxPercentage = DEFAULT_MAX_PERCENTAGE; /** Logger for this class and subclasses */ protected final Log logger = LogFactory.getLog(getClass()); public boolean supports(Class clazz) { return clazz.equals(fileUpload.class); }

7) Override formBackingObject Method: This function is used to return and object that can be used by the View form. This is not needed in the case of a File Upload operation. But this can be used for populating a value object with some contextual information Say as follows
PriceIncrease priceIncrease = new PriceIncrease(); priceIncrease.setPercentage(20); // For file upload just return a new object. protected Object formBackingObject(HttpServletRequest request) throws ServletException { return new Object(); }

2) Write the JSP page corresponding to the submission. Add a title using fmt tag.
<html> <head> <title><fmt:message key="title"/></title> </head> <body> <h1>Please upload a file</h1> <form method="post" action="upload.form" enctype="multipart/form-data"> <input type="file" name="file"/> <input type="submit"/> </form> </body> </html>

Page 14 of 16

3) Add messages to support tags.


title=SpringApp heading=Hello :: SpringApp greeting=Greetings, it is now priceincrease.heading=Price Increase :: SpringApp error.not-specified=Percentage not specified!!! error.too-low=You have to specify a percentage higher than {0}! error.too-high=Don't be greedy - you can't raise prices by more than {0}%! required=Entry required. typeMismatch=Invalid data. typeMismatch.percentage=That is not a number!!! fileUploadTitle=Upload a file please

11. Testing File Upload Controller


File Upload testing will be focuses around mocked objects. The recent attention to Extreme Programming (XP) has spilled over onto one of its most portable practices: unit testing and testfirst design. As software shops have adopted XP's practices, many developers have seen the increase in quality and speed that comes from having a comprehensive unit-test suite. But writing good unit tests takes time and effort. Because each unit cooperates with others, writing a unit test can involve a significant amount of setup code. This makes tests more expensive, and in certain cases (such as code that acts as a client to a remote system) such tests can be almost impossible to implement. In XP, unit tests complement integration and acceptance tests. These latter two test types may be undertaken by a separate team or as a separate activity. But unit tests are written simultaneously with the code to be tested. Facing the pressure of an impending deadline and a headacheinducing unit test, it is tempting to write a haphazard test or not bother with the test at all. Because XP relies on positive motivation and self-sustaining practices, it's in the best interest of the XP process (and the project!) to keep the tests focused and easy to write. Mock objects can help to solve this dilemma. Mock object tests replace domain dependencies with mock implementations used only for testing. This strategy does, however, present a technical challenge in certain situations, such as unit testing on remote systems. AspectJ, an aspect-oriented extension to the Java language, can take unit testing the rest of the way by allowing us to substitute test-only behavior in areas where traditional object-oriented techniques would fail. The following steps will be involved in testing the file upload process using spring framework. Add a Test File Upload Controller Add a MockCommonsResolver Add a MockFileItem

Page 15 of 16

12.Sequence Diagram

Figure 1 File Upload Model

Page 16 of 16

You might also like