Feature Comparision of WSF/C and RogueWave's HydraExpress

Archived Content
This article is provided for historical perspective only, and may not reflect current conditions. Please refer to relevant product page for more up-to-date product information and resources.
  • By damitha nanda mangala kumarage
  • 15 Nov, 2008

Introduction

In a previous article, I compared the WSF/C stack with a competing open source stack called gSOAP. This time around, I am carrying out a feature comparision with a commercial competitor product called RogueWaves HydraExpress.

HydraExpress is a commercially available web services project for the C/C++ platform. WSF/C is an open source web services project that also supports C++ through a wrapper layer. It is been actively developed for about three years now.

 

Table of Contents

 

Architecture

HydraExpress runs on a software called Agent.  Agent is the container for a servlet engine. These servlets are actually C++ servlets implementing the Java servlet API. To configure the agent, you have a set of agent configuration XML files. To configure the servlet engine, you have web.xml. You can configure the connectors in the agent configuration, which are basically the interceptors of the web services requests. By default, it has three connectors called HTTP, HTTPS, and AJP13. Once the request is intercepted, it is passed to the agent specific handler chain, which is configured in the agent configuration files. Once in the servlet handler, it is passed through the servlet specific handler chain. These handlers are categorized as Transport, Request, Response and Fault Handlers. The purpose of these handlers is manipulating the SOAP headers. The handler chains are configured using service specific configuration files. That means for each service you need to configure its handler chain. Handlers can be re-used for each service. The AJP13 connector is used to integrate HydraExpress servlet engine with Apache2. On the server side, the service implementation acts as the turning point for handler chains, which are symmetric in the request and response paths. The order of the handlers can be configured on the server side and the client side. On the server side, the confguration is done dynamically, and on the client side it is done programatically. HydraExpress is extended using handlers. For example, WS security can be provided using handlers. However, I did not see any standard implementation of WS* specifications for handlers. Maybe it is intended to be implemented by the HydraExpress users. 

WSF/C is a web services platform, under Apache license, based on Axis2/C and its constituent products. Although it is a product of WSO2  all of its source is open source. The strength of WSF/C is that it is an integrated platform of various Apache2 C web services projects. It has a integrated build system and test platform which ease the burden of the need to download several products/versions and integrate them.

WSF/C is extensible through its modules to support various ws* specs. Sandesha2/C is the WS Reliable messaging implementation for WSF/C. Rampart/C is the web services security implementation. Savan/C is the WS Eventing implementation. It has various other implementations like WS Federation, WS Transaction, WS Enumeration and WS Transfer. Most of these projects are Apache projects of their own.

We can identify three generations in the history of Apache web services projects. Apache SOAP belongs to the first generation, which is proof of concept implementation. Axis belongs to the second generation. Axis is used widely for web services requirements. However, as web services evolved, there came the need for performance and scalability.  Axis2, which caters to these requirements, belong to the third generation of web services. Axis2 implements a wide variety of WS Specifications like Security, Reliability, and Eventing by using this scalable design.

WSF/C, which uses the C implementation of the Axis2 architecture called Axis2/C, belongs to the third generation of web services. The predecessor to Axis2/C is Axis C++ which has a similar architecture to Axis. So I can say that  Axis C++ belongs to the second generation of Apache web services. WSF/C architecture is based on Axis2 architecture.

The reason for moving from Axis/C++ to Axis2/C can be attributed to the following facts.

  • Axis/C++ architecture is not versatile enough to allow ws* implementations to be integrated into it. For example, there were difficulties implementing specifications like WS Reliable Messaging for Axis/C++. Axis2/C is designed with expansion in mind. New ws* specification implementations can be easily integrated into it as Axis2/C modules. It has very clever plugin design using modules that allow vertical expansion.
  • Axis2/C as an embedded platform for scripting languages - Axis2/C acts as the base implementation for popular scripting languages for supporting web services. Axis2/C is the base for very successful open source web services products for PHP, Ruby, Perl, and Python. There are browser plugins for Mozilla Firefox, Microsoft IIS and currently work is underway for integration with Google Chrome.
  • Supporting the C++ language in form of a wrapper layer. This approach is smarter than the other way around (supporting C language from Axis/C++). However, currently a wrapper layer exist only for the client side. A server side wrapper layer will be available soon.

Much of these design goals have been achieved in a very short time.

WSF/C is the base for web services implementations of  WSO2 for scripting languages, which are all open source. WSF/PHP, WSF/Ruby, WSF/Perl and WSF/Python are now popular in their respective platforms. This is the strongest area of WSF/C when compared with HydraExpress. WSF/PHP for example is very popular among PHP developers for providing and consuming web services.

Looking into HydraExpress, the impression I got is that its architecture and implementation are very close to Axis C++ rather than to Axis2/C. In fact there are striking similarities between Axis C++ and HydraExpress both in architecture and implementation. The move from Axis architecture to Axis2 architecture greatly facilitated the wide WS* adoption. So I suspect the seemingly obscure support for WS* in HydraExpress is due to its restricted architecture capabilities as with Axis C++.

In both WSF/C and HydraExpress there are software components called Handlers. They are used to add functionality to the base engine. For example, handlers are used to handle SOAP headers in the SOAP envelope.

Modules in WSF/C are logical containers of handlers. Handlers that provide a particular functionally together can be bundled as a module. Within the module configuration XML file, these handlers can be placed as they should appear in the final execution handler chain. Once the module is loaded, these handlers are added into another set of logical constructs called Phases. These phases can be global across services or specific to an operation of a service. The ultimate result of adding handlers to the phases through modules is that once the request comes for a service, it will go through a chain of handlers configured according to the rules defined in the module. However, in WSF/C you do not need to configure handlers for each service. Just engage the module to your service and you are done. There is a way you can engage a module globally so that the handlers of the module are available for all services globally.

HydraExpress can configure handlers through an XML file called <service_name>handlers.xml or client-handlers.xml, which restrict the configuration on a service/client basis. Compare this with the handlers configured through the modules in Axis2 architecture. It should be noted that HydraExpress handlers are configured in a similar way to Axis1 architecture. Hence the limitations that motivated the development of the Axis2 architecture could still be prevailing within the HydraExpress architecture.

In HydraExpress, first the message is intercepted by the configured transport. Then it goes through the in handler chain and finally arrives at the service implementation. If there is a return message, it passes through an out handler chain to the client using the same transport used for the incoming message. In and out message handler chains may or may not be symmetrical. The client side and the server side are not symmetric as in WSF/C. In other words, the WSF/C architecture does not differentiate the functionality of the server or client. In the HydraExpress Handler, ordering is done differently on the server side and the client side. On the server side, you specify handlers specific to a service. You have to do this for each service. On the client side, you need to configure the handlers programmatically (except the logging handler.)

Transports

As of version 3.5 HydraExpress supports transport HTTP, HTTPS and WebSphereMQ. These transports can be configured in the server-transports.xml on the server side and client-transports.xml on the client side. It is said in the documentation that new transports could be implemented and built separately and configured using these configuration files.

WSF/C also supports new transport plugins in addition to its existing transport support for http, https, tcp, udp, xmpp and amqp.

Fault Handling

WSF/C does a good job of fault handling using fault handler chains. Module defined handlers can be added into the fault phases as well to handle faults. For example, when we add reliable messaging handlers into the inflow, we add the reliable messaging in-handler into the user defined phase called RMPhase in the in-flow. At the same time, we put a fault handler into the RMPhase in the fault flow.The reliable messaging fault handler's task is to define the reliable messaging behavior when a fault occurs in the in-path. So when a fault occurs in the in-path the execution shifts to the fault flow. In HydraExpress, once a fault occurs, only the fault handler and no other handler can be invoked. That means it is difficult to configure fault handlers that handle faults for a particular functionality.

Deployment

HydraExpress uses command line tools to deploy your services. For example, after building the service, the make deploy command will deploy your service. Axis C++ which implemented Axis1 architecture used similar approaches. Each service needs to be specifically configured for deployment using deployment descriptors.

To deploy a service in WSF/C, you just  have to put it in a special folder called services in the WSF/C repository. The WSF/C repository is the deployment folder structure for WSF/C. New modules should be placed in a folder called Modules in the repository. When the server is loaded, the service and module are loaded from the repository locations into the main configuration. Both HydraExpress and WSF/C does not provide dynamic (hot) deployment/updates of services/handlers/modules. That means when a new service or handler/module implementation is added, the server needs to be restarted.

WS* Support

WSF/C by design can easily be extended in terms of WS* Support. To support additional specifications, a WSF/C module has to be written implementing that particular specification. After that it can be built separately and added into WSF/C as a shared module that is dynamically loaded.

As I understood from the HydraExpress documentation, they do not have in-built support for WS* specification implementations. WSF/C supports addressing by default.

Messaging Style

HydraExpress supports RPC style web services whereas WSF/C supports Document/Literal and RPC/Encoded styles. There is a long running debate as to which of the two implementations should be adopted. In the web services world Document/Literal implementations have gained more ground.

Service Discovery

Initially UDDI was one of three parts of web services. (The other two parts are SOAP and WSDL). It is the technology for publishing web services; but it was never popular among major vendors. Actually according to a recent InfoQ news article, the UDDI committee is closed. WSO2 has opted for its Registry technology over UDDI. I could not find any documentation on HydraExpress on its service discovery capabilities.

Tooling Support

HydraExpress and WSF/C both support code generation using Java specific tools. Both need JDK runtime for code generation. The WSF/C code generation and data binding tool is derived from the popular Axis2/Java Code generation and data binding tools which give it additional strength to be a reliable tool. HydraExpress seems to have a GUI toolkit for configuring web services. However I could not gather more information about this.

Code Generation and XML Binding

HydraExpress uses Xerces C++ XML parser. This again reminds me of good old days with Axis C++ where we provided a pluggable parser implementation with standard implementations with Xerces C++ and Expat.

Axis2/C has a very robust XML parsing mechanism called AXIOM. AXIOM uses Stax parser plugins for its underlying XML parser implementation. Its native XML parser is Guththila, which is also a part of the WFS/C stack. It can also be used with libxml2 parser. AXIOM has the special feature of differed parsing for optimized situations.

Attachments

HydraExpress supports attachments only through implementation of the SwA specification (i.e. MIME attachments). It does not provide MTOM support. WSF/C fully supports both DIME/MIME effectively.

REST Support

WSF/C fully support REST API, whereas I did not see any mention of REST support in HydraExpress documentation.

Services

Both HydraExpress and WSF/C code generation tools generate server side code very easily. In both, you can add your server implementation codes to the generated folder structure. Both generate build files when generating server code. However they have different approaches when deploying services. HydraExpress services can be run as stand alone services or within a C++ servlet engine container. You can run the (built) service executable by passing parameters to it as a stand alone server which runs only that service.

WSF/C also has the concept of a stand alone server, but it is not confined to one service. It has the concept of service/module repositories. Once you write your service (which involves writing your own business logic) you have to just build it and put it into a service folder in the repository. Now whatever the deployer you use, whether it is WSF/C stand alone server or the WSF/C apache module, the repository structure or configuration will not change. That is the repository is deployer independent. You can have any number of services (of course restricted by your system resources) in that repository. In the case of Apache, the WSF/C Apache2 module takes care of all of them.

I will demonstrate some server side code example for a Hello World service both for WSF/C and HydraExpress. What is essentially shown is the amount of work the service developer needs to do after generating server side skeletons.

HydraExpress

To generate server skeletons, execute the following.

rwsfgen project.xml

project.xml contains information such as the name of the WSDL file, name of the output directory, etc. This will generate both server skeletons and client stubs as well as build files within the output directory. You need to go into the server output directory and build the server.

    RWSF_DEFINE_MESSAGE_HANDLER(GreetingPortTypeImp)

    std::string
    GreetingPortTypeImp::sayHello(rwsf::CallInfo& callInfo, const std::string& hellorequest_in)
    {
      return std::string("Hello " + hellorequest_in);
    }
WSF/C

To generate the service,

java -classpath $AXIS2_CLASSPATH org.apache.axis2.wsdl.WSDL2C -uri $1 -ss -sd -u -o service

This will generate the service and build files in the service directory.

    adb_sayHelloResponse_t* axis2_skel_GreetingService_sayHello (const axutil_env_t *env  ,
                                          adb_sayHello_t* sayHello )
    {
        adb_sayHelloResponse_t * response = NULL;

        response = adb_sayHelloResponse_create(env);
        adb_sayHelloResponse_set_return(response, env, adb_sayHello_get_hellorequest(sayHello, env));

        return response;
    }

You can do this with even lesser code using Axis2/C WSDLC tools unwrapped mode option(-uw) as follows

java -classpath $AXIS2_CLASSPATH org.apache.axis2.wsdl.WSDL2C -uri $1 -ss -sd -uw -u -o service

The code generated is

    axis2_char_t* axis2_skel_GreetingService_sayHello (const axutil_env_t *env  ,
                                          axis2_char_t* sayHello )
    {
        return "Say Hello Response";
    }

You can easily see that the design of both implementations allows the service developer to simply concentrate on the business logic in the service, without worrying about the internal workings. In addition to the server side code, both tools generate service configuration files and build files. You have to just generate the server side and fill his business logic and build using the build file.

In WSF/C, copy the dll and service configuration file into a folder and copy that folder into the repository service folder. In HydraExpress you need to deploy it using make/nmake deploy, after building the service.

Clients

Both have tooling support for generating proxies. In both implementations, after generating the stubs, you need to implement the main function for the client.

HydraExpress

To generate client stubs, execute the following.

rwsfgen project.xml

project.xml contains information such as the name of the WSDL file, name of the output directory, etc. This will generate both server skeletons and client stubs as well as build files within the output directory. You need to go into the client output directory and build the client.

 

    void invoke_sayHello(GreetingBindingProxy& proxy)
    {
      std::string hellorequest_in("World!");
      std::string return_ret;
      rwsf::CallInfo  callInfo;

      try {
        return_ret = proxy.sayHello(callInfo, hellorequest_in);
        std::cout << "Server Response: " << return_ret << std::endl;
      } catch(const rwsf::SoapFaultException& e) {
        std::cout << "Fault Code: " << e.getFault().getFaultcode().asString() << std::endl;
        std::cout << "Fault String: " << e.getFault().getFaultstring() << std::endl;
      }
    }

    using rwsf::DefaultLogger;
    RWSF_DEFINE_STATIC_MESSAGE_HANDLER("RWSFClientLogger", DefaultLogger)

    int main(int argc, char* argv[])
    {
      // Instantiate GreetingBindingProxy.
      // If you need to override the URL given in the WSDL file for
      // the service, modify the constructor argument or pass in on
      // the command line

      rwsf::CString location;

      if (argc < 2) {
        location = "https://localhost:8090/helloworld/HelloWorld";
      }
      else if (argv[1][0]=='-' && argv[1][1]=='a') {
        location = "https://localhost:8013/helloworld/HelloWorld";
      }
      else if (argv[1][0]=='-' && argv[1][1]=='l') {
        location = "https://localhost:8090/helloworld/HelloWorld";
      }
      else {
        location = argv[1];
      }

      try {
        // initialize config files
        try {
          // default path from the bin directory
          rwsf::NamingContext::loadGlobal("../conf/client-objects.xml");
          rwsf::HandlerManager::loadConfiguration("../conf/client-handlers.xml");
          rwsf::TransportManager::initialize("../conf/client-transports.xml");
        }
        catch(...) {
          // default path from the app/client vcproj file
          rwsf::NamingContext::loadGlobal("../../conf/client-objects.xml");
          rwsf::HandlerManager::loadConfiguration("../../conf/client-handlers.xml");
          rwsf::TransportManager::initialize("../../conf/client-transports.xml");
        }

        GreetingBindingProxy proxy = GreetingBindingProxy::make(location);

        if(!proxy.isValid()) {
          std::cerr << "Unable to create proxy. " << "\nExiting" << std::endl;
          return 1;
        }

        invoke_sayHello(proxy);

      }
      catch (const rwsf::Exception& x) {
        logError("rwsf::Exception thrown", x.why());
        std::cerr << "rwsf::Exception thrown: "
                  << x.why() << std::endl;
        return 1;
      }
      catch(const std::exception& x) {
        logError("std::exception thrown", x.what());
        std::cerr << "std::exception thrown:" << std::endl
                  << x.what() << std::endl;
        return 1;
      }
      catch(...) {
        logError("Unknown exception thrown", "");
        std::cerr << "Unknown exception thrown" << std::endl;
        return 1;
      }
      return 0;
WSF/C

To generate the client stubs,

java -classpath $AXIS2_CLASSPATH org.apache.axis2.wsdl.WSDL2C -uri $1 -u -o client

This will generate client stubs and build files in the client directory.

    main(void)
    {
        axis2_char_t *endpoint_uri = "";
        axis2_char_t *client_home = NULL;
        axis2_stub_t *stub = NULL;
        adb_sayHello_t *hello = NULL;
        adb_sayHelloResponse_t *response = NULL;
        const axutil_env_t *env = NULL;

        env = axutil_env_create_all("Hello.log", AXIS2_LOG_LEVEL_TRACE);

        client_home = AXIS2_GETENV("AXIS2C_HOME");

        endpoint_uri = axutil_strdup(env, "https://localhost:9090/axis2/services/GreetingService");
        stub = axis2_stub_create_GreetingService(env, client_home, endpoint_uri);
        axis2_stub_populate_services_for_GreetingService(stub, env);
        hello = adb_sayHello_create(env);
        adb_sayHello_set_hellorequest(hello, env, "Hello World");
        response = axis2_stub_op_GreetingService_sayHello(stub, env, hello);
        if(response)
        {
            axis2_char_t *result = adb_sayHelloResponse_get_return(response, env);
            printf("result:%s\n", result);
        }
  }

Other

When it comes to interoperability, HydraExpress claims its interoperable with C++ and Java platforms. However, I could not find any strong claim on interoperablity testing with existing stacks like Axis2/Java Axis2/C, Microsoft WCF platforms, etc. WSF/C claims to be interoperable with populor Axis2/java and Microsoft WCF platforms.

Both have robust mechanisms for error handling and logging. HydraExpress seems to be providing good support for load balancing capabilities, which is still lacking in WSF/C. Both support asynchronous web services calls through client APIs.

When it comes to documentation support, the difference is what accompanies a typical open source product and commercially available product. HydraExpress comes with a set of extensive documentation which actually helped me to get a hands on experience of HydraExpress in no time. It has some tutorials and samples to demonstrate the concepts. From that point on you are on your own or you have to get commercially available support.

WSF/C has user guides and installation guides that are sufficient for getting started. Its real strengh is in the WSO2 OxygenTank Library where you can find many tutorials, articles, demonstrations, podcasts, knowledgebase documents, white papapers, webinars, and podcasts on WSF/C and web services in general. Perhaps this is the largest collection of information for web services available on the Internet. Also, you can always ask your questions on opensorce mailing lists and forums available for WSF/C and Axis2/C

Summary

I have compared the major features of  WSF/C and HydraExpress. Both stacks have thier own strengths and weaknesses. HydraExpress specifically advertises its capability as being an integration platform for legacy applications, which is naturally also true for WSF/C. WSF/C is strong in its robustness in design and extensibility and scalability. When it come to features, WSF/C has many more features than HydraExpress. Of course in C++ support HydraExpress is stronger than WSF/C. C++ support in WSF/C is still fast growing and it is only a matter of time before it could be used as a fully fledged C++ web services stack. This article is about feature comparisions and not performance comparisions. Perhaps I will take on a performance comparision in a future article.

Resources

  1. WSO2 WSF/C - WSO2 WSF/C is an Open Source framework for providing and consuming Web services
  2. Axis2/C- Axis2/C is an Apache Web Services Platform implemented in C language around which the WSO2 WSF/C is built.
  3. HydraExpress- is a Commercially available C++ web services stack.
  4. Complete sample used for this article.

Author

Damitha Kumarage, Senior Software Engineer at wso2, committer Apache Software Foundation, damitha at wso2 dot com

About Author

  • damitha nanda mangala kumarage
  • senior tech lead
  • wso2