Web Services (version 4.2)

Requires Platform version 4.2 or earlier;
Not supported in version 4.5 or higher - for 4.5 Web Service support see Data Services

Web service is a software system designed to support interoperable machine-to-machine interaction over a network. With Nexaweb platform, you can invoke webservices from both the server side and the client side. Nexaweb leverages two aspects of using web services:

  1. The web services that will be used are not known at a development time.
  2. Use of the web services needs to take place on the client side, but the client can not have connectivity to the web service itself due to security concerns and firewall/network issues.

You can find more information from the API document in the com.nexaweb.server.webservices and com.nexaweb.client.webservices package.

Two ways of using webserivces

Since a web service is usually running on a remote machine and the data types used by this web service might or might not be known in advance, you can access the web service data two ways:

1. Strongly typed usage, when you already know the data types at the compile time, you can call the methods directly in a strongly typed fashion at your compile time. For example, if the api.google.com provides a spelling suggestion web service and the service returns a GoogleSearchPort object as a service port, you can write code by directly calling:

_googlePort.doSpellingSuggestion("mykey", "pirimaid"); 

to get a spelling suggestion for the word.

2. Reflection usage, when you don't know or care much on the data type at the complie time, but you know the methods you want to call. Then for the same spelling suggestion service example, you would write: 

Class[] argsType = {String.class, String.class};
Method getSpellingMethod = getMethod("doSpellingSuggestion", argsType); 
Object[] args = {"mykey", "pirimaid"}
String suggestion = 
     (String)getSpellingMethod .invoke(_googlePortObject, args); 

Configuring a web service through nexaweb-webservices.xml

Before configuring a webservice, you must know its Web Services Description Language (WSDL) document location. WSDL is an XML format for describing network services. A WSDL document is published by the web service provider. If you don't know how to get it, check with the web service provider. It's typically a url, like this one "http://api.google.com/GoogleSearch.wsdl". To make sure your WSDL url is correct, you should try to link to the url from your browser and, you should see an xml file.

The next step is to create a "nexaweb-webservices.xml" under your app's "WEB-INF" folder. You can add an entry like this:

<?xml version="1.0" encoding="UTF-8"?>
<web-services>
    <web-service xmlns="http://nexaweb.com/webservices"
      name="Google"
      scratchDir="{0}/WEB-INF/WebServices/{1}"
      wsdlUrl="http://api.google.com/GoogleSearch.wsdl"/>
</web-services> 


In this setting, you only need to modify two attributes for your particular web service:

  • name - the name given to the web service and the key, in the java code, used to obtain the web service port from the WebServiceBroker
  • wsdlUrl - the url to the WSDL document describing the service. This must be a fully qualified URL, valid as a java.net.URL object. Note that this attribute is mutually exclusive with the "wsdlPath" attribute, only one may be specified.
  • scratchDir - you don't have to modify this one, it's a java.text.MessageFormat string that will be used as an argument to a java.io.File object. This will in turn be used as a directory for WebService source and class files. The arguments passed to this MessageFormat are: {0} - The ServletContext.getRealPath("/")  {1} - The logical name of the web services

Another setting mentioned in the wsdlUrl is:

  • wsdlPath - the path to the WSDL document describing the service This path is relative to your web application context.  (e.g. - /WEB-INF/weather.wsdl). Keep in mind, it's mutually exclusive with wsdlUrl attribute.

Web service classes needed for compilation and runtime

Compilation time requirement.

When you choose the reflection usage, at the compilation time, you need only the classes required for developing a standard Nexaweb application. The web service data type will be discovered at runtime.

When you choose the strongly typed usage, you need a set of classes to compile your application. Nexaweb platform has automated most of the steps for you to generate these classes. However, you still need some manual steps to put them together.

The steps to pull out these classes are:

  1. Configure the "nexaweb-webservices.xml" and put the file under the WEB-INF folder.
  2. Deploy your application before writting any strongly-typed web service code.
  3. Launch your application, Nexaweb webservice servlet will automatically generate these classes in the folder you defined in the scratchDir.
  4. By default, when using the above defined nexaweb-webservices.xml, you will see a folder structure similar to the following (you need to have valid name and wsdlUrl first):
  5. The name you provide, in this case, 'Google' will be used as a folder name in which to put these classes.

WEB-INF/WebServices/Google/classes

/AxisClasses
/ClientClasses
/ServerClasses

The classes under the /ClientClasses are the ones required at the client compilation time. The classes under the /ServerClasses are the ones required at the server compilation time. Make sure these classes are in the classpath when you compile strongly-type usage codes using this web service.

Runtime requirement

The runtime requirements are the same for both the reflection usage and the strongly-typed usage. By default, everytime you launch an application with a valid nexaweb-webservices.xml, these classes will be generated once, and you don't need to explicitly put them into the runtime classpath. This is different from compilation requirement where you need to have the classes and put them into the classpath first before compiling the code. This guarantees you will always get up-to-date proxy classes and the data types at the runtime.

In the above strongly-typed compilation requirements, we talked about

/ClientClasses
/ServerClasses

they are also required at runtime regardless of the usage. There is another folder

/AxisClasses

that is also required at runtime. This is where Nexaweb uses the Axis library to generate the proxy classes for the web services support.

The classes listed in /AxisClasses and its dependency, the Axis libary, will be reserved and only loaded by the Nexaweb private classloader at the runtime. If you need to use other Axis libraries, you do not need to worry about any incompatibility issues.

Examples

The following web service sample codes are almost the same and fit running on the client side or the server side usage. There are only two differences to be noted.

1. To get the WebServiceBroker, on the server side, you can call:

//Get the broker through ServiceManager on the server side
WebServiceBroker broker = ServiceManager.getWebServiceBroker();

   On the client side, you can call:

//Get the broker through ClientSession on the client side
WebServiceBroker broker = clientSession.getWebServiceBroker();

2. When the code is running on the server side, you need to make an additional call to disover the web service.

// Discovers the web service, writes the Java classes, 
// compiles and loads the classes.
// This call is only available on the server side.
broker.createWebService( name, wsdlUrl );

Also, make sure the runtime required classes are generated in the appropriate client and server classpaths even if you don't have to configure them.

Strongly-type usage example

In strongly-type usage case, besides runtime requirement classes, make sure you compile your code with the client or server's compile time required classes in the compile paths.

//Get the broker first based on client or server side code
String wsdlUrl = "http://api.google.com/GoogleSearch.wsdl"
String name="GoogleWebService";

// Server side only call
// broker.createWebService(name, wsdlUrl);

// This call retrieves the Port on which the web service's
// methods are available
GoogleSearchPort googlePort = 
  (GoogleSearchPort)broker.getServicePort(name);
String pyramid = 
   googlePort.doSpellingSuggestion("myKey", "piramid"); 
// 'piramid' is intentionally spelled wrong here

In this example, the GoogleSearchPort is a strongly typed object, which is an instance of a class defined by the GoogleSearch service.

Reflection usage example

 

//Get the broker first based on client or server side code
String wsdlUrl = "http://api.google.com/GoogleSearch.wsdl"
String name="GoogleWebService";

// Server side only call
// broker.createWebService(name, wsdlUrl);

// This call retrieves the Port on which the web 
// service's methods are available
Object googlePort = broker.getServicePort(name);

// Now through reflection get the "doSpellingSuggestion" method
Method method = googlePort.getClass().getDeclaredMethod
    ("doSpellingSuggestion", new Class[]
    {String.class, String.class} );

// Invoke the method using java reflection supplying 
// your arguments
String pyramid = (String)method.invoke
      ( googlePort, new Object[]{"myKey", "piramid"});

 

Limitations

With the current framework, to compile the strongly-type application, a user still needs to manually start the application once and jar the classes in the /ClientClasses or /ServerClasses folder for future strongly-type code compilation. This will be addressed in the future release.