Current economic conditions have created pressure to reduce the costs associated with developing and maintaining enterprise applications. As such, many organizations are turning to cloud computing technologies such as the
Force.com platform from Salesforce.com, to lower costs and increase value.
If you haven't heard of it, Force.com, launched in 2007, lets you build and deliver apps in the cloud, and includes database, user interface, logic, workflow, mobile and security functionality -– all backed by a multi-tenant kernel currently powering 150K applications for more than 1.5 million users.
As more organizations begin the process of moving their critical apps to the cloud they may decide to maintain a subset of their infrastructure on-premise due to the large investments made in this infrastructure and for security reasons, whether due to institutional paranoia or legitimate regulatory requirements. New integration patterns have emerged to enable many applications to migrate to the cloud while leveraging existing infrastructure.
This article demonstrates how to build a mashup that seamlessly and securely integrates data and services sourced from on-premise infrastructure into a cloud application. By leveraging this pattern an organization can realize the manifold benefits of cloud sourcing an application whilst leveraging sensitive data and existing functionality available in on-premise infrastructure. As an illustrative example, an on-premise service built in Java and web-service enabled with Apache Axis is seamlessly invoked from within a Force.com application.
An Integration Architecture
A cloud-based application built on the Force.com platform may need to access sensitive data and invoke critical business logic available only in the company's on-premise infrastructure. Considering the traditional three-tier architecture, the entire presentation layer can reside in the cloud. The business logic layer too resides in the cloud with the exception of those critical services developed previously by the organization. Likewise, the data layer resides in the cloud and handles the bulk of the data used by the application. When sensitive data is needed the application accesses additional data services that reside on-premise utilizing integration technologies. The architecture is shown in the diagram below.
As you can see, most of the app and functionality sits on Force.com, with some data and functions residing on an intranet. The end-user accesses the Force.com application, which in turn makes secure callouts to the on-premise solution.
This isn't the only way to integrate Force.com with Java, but it's illustrative of the general technique. See the Additional Integration Scenarios for other possibilities.
The Integration Mashup
To illustrate the integration capabilities of the Force.com platform, an example from the Wealth Management industry is shown. A large Wall Street bank wishes to migrate its Wealth Management CRM application to the cloud using the Force.com platform. Due to the sensitive nature of the customer's account balance information, the organization decides this information must remain under their control at all times within their self-managed on-premise infrastructure. The chosen architecture cloud-sources the bulk of the application on the Force.com platform and uses a mashup to seamlessly and securely integrate account balance information as needed from the organization's on-premise infrastructure.
The bank has an enterprise class account balance service built in Java that (in simplified form) returns the current balance given an account number. The bank's robust Service Oriented Architecture (SOA) surfaces this service so that it may be consumed from the Web using the standard SOAP protocol and securely authenticates the consumer to ensures the user has the rights to access this sensitive information. Apache Axis is used to Web Service enable this Java service. This can be done quite securely, for example by leveraging two-way SSL and restricting incoming IP ranges to those of Force.com.
The Wealth Management application displays the account balance by invoking the Account Balance Web Service in real-time with each render of the account page.
The Force.com platform uses the common Model-View-Controller (MVC) pattern to display content to the user. The View uses Visualforce markup to format the page. The Controller contains the business logic used to interact with the user. For this application, an Apex Code controller extension is used to invoke the external Web Service to retrieve the current account balance. The Model in this case is a combination of Force.com standard and custom objects (Force.com terminology for a rich database-like structure).
Java and Web Service Hosting
We're going to assume the Java web service is hosted on the intranet, on the Apache Axis web services stack. Lets look at this in a little more detail.
The Java Account Balance service, sitting on the intranet, has the following signature:
<pre><code>public java.lang.String getAccountBalance
(java.lang.String accountNumber)
This service returns the accountBalance for the given accountNumber, returning "Invalid Account Number" if the accountNumber is invalid. This is obviously a simplication, but illustrates the point. This service accesses an on-premise relational database to retrieve the current balance, but the details of this service aren't shown here as they are not central to this integration use-case.
In order for our cloud based Wealth Management application to consume this on-premise service it must be made available as a web service. The Apache Axis project is a very popular and mature package used to surface a Java method as a Web Service that can be invoked by any consumer with access to this on-premise server. Axis provides a Java2WSDL function that produces a standards compliant WSDL file from any given Java class file. To produce a WSDL file for our account balance service, execute the following at the command-line:
Java2WSDL AccountService.java
Here AccountService is the name of the class that contains the getAccountBalance() method. Axis will produce a number of files that are used to Web Service enable our getAccountService method. Of most interest to our integration use case is the Web Service Description Language (WSDL) file produced called AccountService.wsdl. The WSDL file will look something like this (I've cut bits out):
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:tns2="http://AccountService" targetNamespace="http://AccountService">
<!-- WSDL scheme type removed -->
<wsdl:message name="getAccountBalanceRequest">
<wsdl:part name="getAccountBalanceRequest" element="tns2:getAccountBalance"/>
</wsdl:message>
<wsdl:message name="getAccountBalanceResponse">
<wsdl:part name="return" element="tns2:getAccountBalanceResponse"/>
</wsdl:message>
<wsdl:portType name="AccountServicePortType">
<wsdl:operation name="getAccountBalance">
<wsdl:input message="tns2:getAccountBalanceRequest"/>
<wsdl:output message="tns2:getAccountBalanceResponse"/>
</wsdl:operation>
</wsdl:portType>
<!--wsdl binding removed -->
<wsdl:service name="AccountService">
<wsdl:port name="AccountServicePort" binding="tns2:AccountServiceBinding">
<soap:address location="https://aptaria.com:9081/AccountService/services/AccountServicePort"/>
</wsdl:port>
</wsdl:service>
Note that this WSDL identifies that the AccountService has one Web Service: getAccountBalance that takes an accountNumber String and returns an accountBalance String. Note also that the location of the AccountService is at an external domain: aptaria.com. This external on-premise server hosts our getBalanceService.
Now that our AccountService has been established in our on-premise infrastructure and the getAccountBalance method has been Web Service enabled (surfaced), we can now concentrate on integrating this critical functionality into our Force.com Wealth Management application.
Force.com and Web Service Invocation
In order to display to the user the current balance for an account we must configure our Wealth Management application to perform a callout to an external Web Service whenever the account page is rendered on Force.com. This section looks at how to configure Force.com to invoke external web services, and how to use the tooling to automatically generate the code to invoke the web service.
First we must enable the Force.com network security settings to allow our application to invoke outbound Web Service calls. As this is sensitive information we want to ensure that only our trusted on-premise infrastructure interfaces with our cloud based application. The Force.com platform can be configured to restrict all outbound Web Service calls to a particular IP range. This greatly reduces the risk of interfacing with a counterfeit or malicious AccountService.
Once you have identified the range of IP addresses at which the AccountService will be available, go to the Force.com Setup menu in your org (Force.com terminology for their cloud based application environment) and navigate to Administrative Setup : Security Controls : Network Access. From this page you can enter the Starting and Ending IP address of the secure AccountService.
Next we must identify the external Web Service to our application. We do this by uploading the generated WSDL into the Force.com platform. Once loaded, the external Web Service can be invoked by any Apex class (Apex is name of the Force.com platform programming language). To load the generated WSDL go to the Force.com Setup menu in your org and navigate to App Setup: Apex Classes. From this page select the Generate from WSDL button and then provide the location of the WSDL file generated above, and then press the Parse WSDL button.
Once the WSDL file has been loaded you will notice a new Apex class appears in the Org: AccountService. The generated class will look something like this:
//Generated by wsdl2apex
public class AccountService{
public class getAccountBalance_element {
/* snip */
}
public class getAccountBalanceResponse_element {
/* snip */
}
public class AccountServicePort {
public String endpoint_x = 'https://aptaria.com:9081/AccountService/services/AccountServicePort';
public String getAccountBalance(String accountNumber) {
/* snip */
}
}
}
This class was completely auto generated by the Force.com platform when our AccountService WSDL was loaded. Notice that the endpoint_x variable identifies the URL address of our AccountService. The beauty of WSDL2Apex is that we don't need to concern ourselves with the details of this code. The platform handles the dirty work of invoking our getAccountBalance Web Service for us. All we need to do is call the public method getAccountBalance and pass in an accountNumber String.
The Force.com Application User Interface
Now that our AccountService is available and the platform is aware of how to invoke it as a Web Service we can update our Force.com Financial Account screen to invoke the service with each render of the page. This section looks at how to use the markup language to display the data.