 | Level: Introductory Naveen Balani (naveenb@webifysolutions.com), Technical Architect, Webify Solutions
01 Apr 2002 This second part of a two-part series will focus on how to implement a Web services architecture using any Model-View-Controller (MVC) pattern. This article focuses on how to access static and dynamic Web services using SOAP and UDDI APIs, along with the design implementation of the components that makes up your Web services architecture.
In the previous article in this series, you constructed an existing MVC pattern; now you can apply a Web services architecture on top of it. The key components you need to implement are the static services
navigator file, the SOAP client, the UDDI client, the services utility, and the interaction
with the MVC pattern, as you can see in Figure 1 below. Figure 1. Key components of the Web services architecture

To provide an implementation, I have designed a sample MVC pattern with
a Web service architecture applied to it. I will provide an implementation
based on the architecture depicted in Figure 2. This architecture is dynamically
invoked using a static services mapping navigator file. The implementation
primarily shows you how Web services can be called using various APIs and
how it can be applied to your existing MVC framework. Figure 2. Sample Web services architecture

Implementing the services manager
The services manager is
the servlet, which interacts with the client. It creates an instance of
the services controller and delegates the request/response parameters to
it. During initialization, it loads the static services navigation
file and populates the Navigator class.
Implementing the Navigator class
The Navigator
class is a static class whose responsibility is to parse your static navigation
services file. Part of this file is shown in the listing below:
<service type="CheapestAirFare" serviceCount="N"
formbean="packagename.className"
staticrequestHandler="packagename.className"
dynamicrequestHandler="packagename.className"
serviceimplemenation1="http://airservice.com/rrpcrouter"
serviceimplemenation1urn1="urn:fare"
methodName1 ="getRate"
serviceimplemenationN= " " . serviceimplemenation1urnN=" "
methodNameN="getCheapestRate"
dynamicLookup="Yes" >
|
The Navigator class parses the navigation file and, based
on
serviceCount, populates a vector of size N counting objects
of services. The object service class consists of three variables and accessors
to the variables, namely
serviceimplemenation, serviceimplemenationurn,
and the methodName. The Navigator class also populates
the formbean, package name, serviceCount, and dynamicLookup,
and adds the variables to the same vector. Finally, the vector object
is put into a hashmap with the service type as key (cheapestAirFare)
and vector as an object. The Navigator class thus has the following methods:
-
ParseNavigationFile(pathofNavigationFile): Parses the navigation
file and populates the hashmap.
-
get/set ServicesCount(serviceType): Gets the servicesCount
(number of static services registered) associated with serviceType. The
set method for each variable is set during parsing.
-
get/set formBean(serviceType): Gets the formBean associated
with serviceType.
-
get/set staticRequestHandler(serviceType): Gets the RequestHandler
class associated with serviceType for static services.
-
get/set dynamicRequestHandler(serviceType): Gets the RequestHandler
class associated with serviceType for dynamic services.
-
get services(serviceType,count): Gets the corresponding service
object from a vector based on the element at which it is stored. First, based
on serviceType, you get the corresponding vector object from the hashmap; then,
using count as an index to the vector, you get the corresponding services object.
-
get/set dynamicLookUp(serviceType): Gets the dynamicLookUp
entry associated with serviceType.
All the above setter methods are populated when the static
services mapping navigator file is parsed and getters are called by the
services controller, which controls the whole flow dynamically.
Implementing the ServicesController
The ServicesController
class acts as an application controller, routing incoming client requests
to appropriate request handlers and formbeans. These handlers interact
with SOAP services statically as well as dynamically and coordinate view
production via JavaServer Pages. The controller subsystem is responsible for:
-
Calling the appropriate formbean based
on the
Navigator class.
-
Routing incoming client requests to
appropriate request handler code based on the
Navigator class.
-
Providing required model data for
the presentation layer by consolidating responses from request handlers.
-
Handling exceptions in a uniform way.
Let's walk step by step through the logic for your services controller.
- Get the service type from the JavaServer Page.
serviceType = request.getParameter(serviceType);
|
- Call the corresponding formbean.
is a Java interface class consisting of a processClientRequest (HttpServletRequest
request) method, which all your formbeans extend.
IFormBean IformBean = (IFormBean) class.forname(Navigator.getformBean(serviceType));
|
- Call the formbean
processClientRequest(HttpServletRequest
request) method.
IformBean.processClientRequest(HttpServletRequest request)
|
- Get the
servicesCount from the Navigator
class.
int Count = Navigator.getServicesCount(serviceType)
|
- Create a temporary storage space (that is,
Vector storeResults) to store all the results received from .
- For each service count, call the request handler.
IStaticRequestHandler is an Java interface class consisting of a processRequest(Services service,IFormBean iformBean) method, which
all the RequestHandlers extend.
while(count > 0)
{
IStaticRequestHandler requestHandler = (IStaticRequestHandler)
class.forname(Navigator.getstaticRequestHandler(serviceType);
|
- Get the
Services object based on count and service type from the Navigator class.
Services services = Navigator.getservices(serviceType,count);
|
- Call the
requestHandler processRequest(Services
service) method and pass the services object to it.
String tempdata = requestHandler.processRequest(services,IformBean)
|
- Store the results obtained in the
storeResults vector.
storeResults.addElement(tempdata);
|
- Decrement the count and end the
while loop. Now you have the results of all static services
invoked by the requestHandlers in the storeResults vector.
- Check if
DynamicLookup is enabled from the
Navigator class.
boolean flag = Navigator.getdynamicLookUp(serviceType)
|
- If it is enabled, then look up your dynamic
request handler class from the
Navigator class. IDynamicRequestHandler is a Java interface class consisting of a processRequest(String serviceType,IFormBean IformBean) method, which all your dynamic request handlers extend.
IDynamicRequestHandler dynamicrequestHandler = (IDynamicRequestHandler)
class.forname(Navigator.getdynamicRequestHandler(serviceType);
|
- Call the
processRequest(serviceType) method and get back the data obtained by calling SOAP services looked up in the UDDI registry.
Vector dynamic = dynamicrequestHandler.processRequest(serviceType,IformBean)
|
- Put the vectors (static and dynamic) in the
HttpRequest attribute and call the appropriate JSP based on serviceType. The corresponding
JSP page takes the data from the HTTP requestattribute and displays the data
to the user.
getServletContext().getRequestDispatcher
("/servicetype.jsp").forward(request,response);
|
 |
Implementing the FormBean
The FormBean retrieves
the user-entered query from the HttpServlet request parameter.
The services controller refers to the Navigator class's getformBean(serviceType) method
for instantiating the corresponding formBean, as shown in step 2 of the
logic above. After getting the formBean instance, the processClientRequest()
method is executed, which populates the user queries from HTTP request parameters.
For instance, for a cheapestAirFare service, the processClientRequest(HttpServletRequsr
request) method of the cheapestAirFare class would be:
String country1 = request.getParameter("Country1");
String country2 = request.getParameter("Country2");
|
Implementing of the static RequestHandler
The
execute method of the static request handler, as shown in step 8 of the
listing above, accepts the services object and formBean as input parameters. The
job of each request handler is to call the SOAP client, pass the services
object methods, and get back the result, like this:
String result = SOAPClient.process(services.getServiceImplemenation
(),services.getServiceImplemenationUrn(),services.getMethodName,IformBean);
|
Implementation of the SOAP client
The job of each SOAP
client is to send a query to a SOAP server and get back the results of that query. Figure 3 shows how a SOAP client communicates with a SOAP server.
All the required parameters, like methodName, targetObject,
and the location of the service, you get from requestHandler (via
the
Navigator class). Figure 3. A SOAP client communicating with a SOAP server

Here is some of the logic for the static client:
- Create and initialize a new
org.apache.soap.rpc.Call object.
- Set the target URN, method name, and parameters of the first service.
call.setTargetObjectURI(serviceUrn );
call.setMethodName(methodName );
|
- Populate the parameter to be passed to the SOAP server.
Vector params =new Vector();
Parameter country1Param = new Parameter( "country1",String.class,country1,
,Constants.NS_URI_SOAP_ENC);
params.addElement(formBean.getCountry1());
Parameter country2Param = new Parameter(
"country2",String.class,country2,Constants.NS_URI_SOAP_ENC);
params.addElement(formBean.getCountry2());
call.setParams(params);
|
- Set the target URL of the first service.
Response resp =null;
URL url =new URL (serviceImplementation);
|
- Invoke the corresponding service.
Resp =call.invoke(serviceImplementation, serviceUrn);
Parameter result=resp.getReturnValue();
|
- Get the result object from the SOAP server.
String farerate = (String ) result.getValue();
|
Implementing the dynamic request handler
The job of each dynamic
request handler is to call the UDDI client's processRequest(serviceType,IformBean)
method, pass serviceType and
formBean to it, and get
back the results:
//Call The UDDI Client
Vector results = UDDIClient.processDyanmicRequest(serviceType,IformBean);
|
Implementing the UDDIClient
UDDIClient communicates
with the UDDI registry to find out whether a particularserviceType
is available or not. It uses UDDI APIs to interact with the UDDI registry,
as shown in Figure 4. Figure 4. serviceType interacting with the UDDI registry via UDDI APIs

The listing below contains the
logic for using the UDDI APIs to search for a particular serviceType
in a UDDI directory. Once you have this serviceType, you use it to obtain the location(acessPoints) of the service and the WSDL document associated with that service.
- Create an instance of the UDDI proxy.
UDDIProxy proxy =newUDDIProxy();
|
- A location vector is required to store the location of each service obtained from UDDI.
Vector locationVecor = new Vector(1,1)
|
- A WSDL location vector is required to store the location of WSDL documents for each service obtained from UDDI.
Vector wsdlVector = new Vector(1,1)
|
- A results vector is required to store results obtained by invoking services obtained from UDDI.
Vector servicesVector = new Vector(1,1)
|
- Set the inquiry and publish APIs.
String inquiryAPI ="http:/ibm.com/services/uddi/publishap";
String publishAPI ="http:/ibm.com/services/uddi/publishapi";
proxy.setInquiryURL(inquiryAPI);
proxy.setPublishURL(publishAPI);
|
- Find the business entity associated with the
serviceType.
BusinessList businessList = proxy.find_business(serviceType,null,0);
BusinessInfos bis =businessList.getBusinessInfos();
Vector v2 =bis.getBusinessInfoVector();
|
- Find the business services associated with the business entity. For example, find all service providers providing the
cheapestAirFare service.
for (int i2 =0;i2 < v2.size();i2++){
BusinessInfo businessInfo = (BusinessInfo)v2.elementAt(i2);
ServiceInfos serviceInfos = businessInfo.getServiceInfos();
Vector v3 =serviceInfos.getServiceInfoVector();
|
- Find the binding detail associated with each service.
for (int i3 =0;i3 < v3.size();i3++){
ServiceInfo si =(ServiceInfo)v3.elementAt(i3);
String skey =si.getServiceKey();
BindingDetail bindingDetail = proxy.find_binding(null,skey,null,0);
Vector v4 =bindingDetail.getBindingTemplateVector();
for (int i4 =0;i4 < v4.size();i4++){
BindingTemplate bindingTemplate =(BindingTemplate)v4.elementAt(i4);
|
- Collect the access points from the binding template
AccessPoint.
accessPoint = bindingTemplate.getAccessPoint();
|
- Add the access point to your location vector.
locationVecor.addElement(accessPoint.getText());
|
- Get the WSDL document for each service.
TModelInstanceDetails tid =bt.getTModelInstanceDetails();
Vector v5 =tid.getTModelInstanceInfoVector();
for (int i5 =0;i5 < v5.size();i5++){
TModelInstanceInfo tii = TModelInstanceInfo)v5.elementAt(i5);
InstanceDetails inst =tii.getInstanceDetails();
OverviewDoc od =inst.getOverviewDoc();
OverviewURL ou =od.getOverviewURL();
wsdlVector.addElement(ou.getText())); }}}}
|
- Call the dynamic service utility method for providing mapping to the correct service utility classes to invoke.
for(int int i5 =0;i5 <locationVecor.size();i5++)
{
IServiceUtility serviceUtility = (IServiceUtility)
DynamicServiceReistry.locate(locationVecor.elmentat(i5),wsdlVector(i5));
String result= serviceUtility.processDynamicRequest(formbean);
servicesVector.addElement(i5,result);
}
//Return servicesVector
|
 |
Implementing the DynamicServiceRegistry
The DynamicServiceRegistry class is the mapper
class, which gives us the correct serviceUtility to invoke based
on the location of a service and its WSDL name. The listing below shows how the code works.
public IServiceUtility locate(String location,String wsdl) {
if(location.equals("http://location1/service/rpcrouter") &&
wsdl.equals("http://location/wsdl/cheapest-airface.wsdl"))
//Invoke Corresponding service utility class
IServiceUtility serviceUtility = (IServiceUtility)
class.forname("classname.packagename"+dynamicService1));
//Similarly for remaining services
else
// log all new services found to provide implementation of newly services obtained
// at a later stage
{
Log.newService('New Service Found At' +location + "WSDL Document " + wsdl);
}
|
Implementing the ServicesUtility
Each service utility class
extends the IServiceUtility class, and implements the processDynamicRequest(formBean).
For each dynamic service obtained, the corresponding services utility class
is invoked. Each service utility class has it own implementation, since
the URN name and method name each needs to invoke will be unique. For a
new dynamic service that has been added, you could use a tool such as WebSphere
Application Developer Studio that can dynamically generate a SOAP client
based on a WSDL file obtained; or, the SOAP client can be coded by referring
to a WSDL document, which will contain the method name to invoke and the
URN of the Web service. After discovering the newly added service, the
IDynamicServiceRegistry
class can be updated to add an entry for the newly found service and corresponding
service utility classes can be coded. Thus, serviceUtility classes
will call the dynamic SOAP client for each service; the dynamic client
performs the same job that the static SOAP client discussed above does,
and gives back the result to the request handler.
 |
Conclusion
This completes the sample implementation of this architecture. Your implementation
will differ, depending on own your MVC pattern, but the logic determining
how you access static and dynamic services at the same time will remain
the same. I hope the sample outlined here helps you build your own implementations. I would be interested in hearing from you regarding this article. Please
feel free to contact me at naveen_balani@syntelinc.com.
Resources -
To learn more about Web services, see the Web services architectural overview.
-
The developerWorks series "Web services architect" builds a strong foundation in Web services skills.
-
To learn more about SOAP, see the SOAP
specification.
-
The developerWorks article "Myths and misunderstandings surrounding SOAP" might also be of interest.
-
The UDDI.org technical white paper also has a lot of information about
UDDI
(in PDF format).
-
The
role of private UDDI nodes in Web services
is described in a series
of developerWorks articles; here is part one of that series.
-
The MVC pattern is used to separate logic from interface, and separate
both from methods. It comes originally from Smalltalk, but is useful many
other places as well, as Steve
Burbeck explains in this article.
-
More on MVC.
-
If you are familiar with Java
Swing, you are already familiar with MVC.
-
The WebSphere
Application Server utilizes both MVP and MVC patterns.
-
The Patterns Home Page has
information about all aspects of software patterns and pattern languages.
-
Wiki also has
a lot of information on patterns.
-
The classic work on patterns is
A
Pattern Language: Towns, Buildings, Construction, Christopher Alexander
et al. (Oxford University Press, 1977).
About the author
Rate this page
|  |