Web architecture using MVC style, Part 2: Building a web services MVC architecture

Transform any implementation of the MVC pattern into a web service

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
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
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.

  1. Get the service type from the JavaServer Page.
    serviceType = request.getParameter(serviceType);
  2. Call the corresponding formbean.
    IFormBean

    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));
  3. Call the formbean processClientRequest(HttpServletRequest request) method.
    IformBean.processClientRequest(HttpServletRequest request)
  4. Get the servicesCount from the Navigator class.
    int Count = Navigator.getServicesCount(serviceType)
  5. Create a temporary storage space (that is,Vector storeResults) to store all the results received from
    requestHandlers

    .
  6. 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);
  7. Get the Services object based on count and service type from the Navigator class.
    Services services = Navigator.getservices(serviceType,count);
  8. Call the requestHandler processRequest(Services service) method and pass the services object to it.
    String tempdata = requestHandler.processRequest(services,IformBean)
  9. Store the results obtained in the storeResults vector.
    storeResults.addElement(tempdata);
  10. 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.
  11. Check if DynamicLookup is enabled from the Navigator class.
    boolean flag = Navigator.getdynamicLookUp(serviceType)
  12. 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);
  13. 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)
  14. 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
A SOAP client communicating with a SOAP server

Here is some of the logic for the static client:

  1. Create and initialize a new org.apache.soap.rpc.Call object.
    Call call = new Call();
  2. Set the target URN, method name, and parameters of the first service.
    call.setTargetObjectURI(serviceUrn );
    call.setMethodName(methodName );
  3. 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);
  4. Set the target URL of the first service.
    Response resp =null;
    URL url =new URL (serviceImplementation);
  5. Invoke the corresponding service.
    Resp =call.invoke(serviceImplementation, serviceUrn);
    Parameter result=resp.getReturnValue();
  6. 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
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.

  1. Create an instance of the UDDI proxy.
    UDDIProxy proxy =newUDDIProxy();
  2. A location vector is required to store the location of each service obtained from UDDI.
    Vector locationVecor = new Vector(1,1)
  3. 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)
  4. A results vector is required to store results obtained by invoking services obtained from UDDI.
    Vector servicesVector = new Vector(1,1)
  5. 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);
  6. Find the business entity associated with the serviceType.
    BusinessList businessList = proxy.find_business(serviceType,null,0);
    BusinessInfos bis =businessList.getBusinessInfos();
    Vector v2 =bis.getBusinessInfoVector();
  7. 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();
  8. 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);
  9. Collect the access points from the binding template AccessPoint.
    accessPoint = bindingTemplate.getAccessPoint();
  10. Add the access point to your location vector.
    locationVecor.addElement(accessPoint.getText());
  11. 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())); }}}}
  12. 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

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into SOA and web services on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and web services
ArticleID=11657
ArticleTitle=Web architecture using MVC style, Part 2: Building a web services MVC architecture
publish-date=04012002