16.4. Web Services Clients in Geronimo

A web services client typically begins with WSDL, and from there creates the service endpoint and client service interfaces. Then, in order to deploy the service in a J2EE server, a JAX-RPC mapping file is created. With that input, the service can be added to JNDI for an EJB or a web application.

[Tip]Tip

Once again, Geronimo does not require client "stubs" or implementation code; the classes necessary to hook the interfaces up to the remote service will be generated under the covers.

16.4.1. Adding a Web Service Reference to a J2EE Component

The configuration process begins in the web.xml for a web application, or ejb-jar.xml for an EJB. In either case, a service-ref element is added for each web service. The XML is the same for both web applications and EJBs, the only difference is that a service reference is added at the top level of a web application, but scoped to a single EJB in an EJB JAR.

A service-ref typically looks like this:

<web-app xmlns:ger="geronimo-book:reviews"
   ...
  <service-ref>
    <service-ref-name>service/ProductReviews</service-ref-name>
    <service-interface>
      reviews.client.ProductReviewsService
    </service-interface>
    <wsdl-file>WEB-INF/ProductReviews.wsdl</wsdl-file>
    <jaxrpc-mapping-file>
      WEB-INF/ProductReviewsMapping.xml
    </jaxrpc-mapping-file>
    <service-qname>ger:ProductReviewsService</service-qname>
  </service-ref>

The elements here are:

service-ref-name

The service will be located in JNDI at java:comp/env/ plus the value of the service ref name (here, java:comp/env/service/ProductReviews)

service-interface

The fully-qualified class name of the client service interface (not the service endpoint interface)

wsdl-file

The location of the WSDL file, relative to the root of the WAR or EJB JAR

jaxrpc-mapping-file

The location of the JAX-RPC mapping file, relative to the root of the WAR or EJB JAR

service-qname

If there is more than one service element in the WSDL file, this is used to select the one that this reference points to. It must include a namespace prefix that refers to the correct namespace for the WSDL content, which means an xmlns attribute must be added for that namespace in one of the enclosing elements, associating a prefix with that namespace, and then the prefix must be used in the value here.

16.4.2. Customizing the Service Reference

The standard service-ref element is sufficient to contact the remote web service under normal circumstances. However, there are some cases where it's necessary to add additional settings to the Geronimo deployment plan for the service reference:

  • The URL in the WSDL to contact the service is not correct

  • The service in the WSDL includes multiple ports, and the same service-interface is used for more than one of them in the JAX-RPC mapping file, so it's not clear from the service-ref which port is targeted.

  • The WSDL is incomplete, and does not have a service element at all (but does have at least one binding).

  • The service requires authentication, but a user's Geronimo login will not be correct for the service.

The Geronimo deployment plan can select a port and/or binding, provide a URL to the service, and identify additional credentials configured for a Geronimo user that should be used to authenticate to the service. The specific syntax used to complete a service-ref in the Geronimo plan is described in more detail in Section 11.3.4.5, “Web Service References” and Section 12.3.6.7, “Web Service References”.

For example, a block used to override the URI specified in the WSDL for the service-ref above might look like this:

<service-ref>
  <service-ref-name>service/ProductReviews</service-ref-name>
  <port>
    <port-name>ProductReviews</port-name>
    <protocol>http</protocol>
    <host>server.domain.com</host>
    <port>80</port>
    <uri>/new/path/to/ProductReviews</uri>
  </port>
</service-ref>

16.4.3. Authenticating to a Web Service

The Geronimo web service client infrastructure is capable of authenticating to a remote web service that requires it. However, Geronimo does not save a user's password by default, so it does not have enough information to pass a username and password to the remote service. For this to work, the calling application must use a security realm specially configured to save the user's username and password, and then the Geronimo deployment plan for the service-ref must describe how to find those credentials.

16.4.3.1. Setting up the Security Realm

To store the username and password, an additional login module must be added to the Geronimo security realm. (For more details on configuring security realms and login modules, see Chapter 9, Security Configuration [DRAFT (1.0-pre)].) The settings for this login module are:

Table 16.1. Web Service: Login Module to Save Username & Password

Login Module Class:org.apache.geronimo.security.jaas.NamedUPCredentialLoginModule
Configuration Options:org.apache.geronimo.jaas.NamedUPCredentialLoginModule.Name (set the value for this option to a name to store the credentials under, and the web service will use the same name to pick the credentials it wants)
Control Flag:REQUIRED
Server Side:true

Currently this module cannot be added through the security realm wizard in the Console, though you can create a new security realm, select Other as the type, and then manually enter in the settings for both the main login module and this one. Alternately, you can write a security realm deployment plan like the one in Example 16.5, “Security Realm Plan for a Web Service Client” and deploy that using the normal command-line deployment tool.

Example 16.5. Security Realm Plan for a Web Service Client

This plan uses the standard Geronimo properties login module, and adds the login module described above in addition.

<configuration configId="MyRealm"
        xmlns="http://geronimo.apache.org/xml/ns/deployment-1.0">
  <gbean name="MyRealm"
 class="org.apache.geronimo.security.realm.GenericSecurityRealm">
    <attribute name="realmName">MyRealm</attribute>
    <reference name="ServerInfo">
      <gbean-name>geronimo.server:J2EEApplication=null,
        J2EEModule=geronimo/j2ee-system/1.0/car,
        J2EEServer=geronimo,j2eeType=GBean,name=ServerInfo
      </gbean-name>
    </reference>
    <reference name="LoginService">
      <gbean-name>geronimo.server:J2EEApplication=null,
        J2EEModule=geronimo/j2ee-security/1.0/car,
        J2EEServer=geronimo,j2eeType=JaasLoginService,
        name=JaasLoginService
      </gbean-name>
    </reference>
    <xml-reference name="LoginModuleConfiguration">
      <log:login-config
   xmlns:log="http://geronimo.apache.org/xml/ns/loginconfig-1.0">
        <log:login-module control-flag="REQUIRED"
                   server-side="true" wrap-principals="false">
          <log:login-domain-name>
            MainDomain
          </log:login-domain-name>
          <log:login-module-class>
            org.apache.geronimo.security.realm.providers.
                                       PropertiesFileLoginModule
          </log:login-module-class>
          <log:option name="usersURI">
            var/security/users.properties
          </log:option>
          <log:option name="groupsURI">
            var/security/groups.properties
          </log:option>
        </log:login-module>
        <log:login-module control-flag="REQUIRED"
                   server-side="true" wrap-principals="false">
          <log:login-domain-name>
            NamedDomain
          </log:login-domain-name>
          <log:login-module-class>
   org.apache.geronimo.security.jaas.NamedUPCredentialLoginModule
          </log:login-module-class>
          <log:option
name="org.apache.geronimo.jaas.NamedUPCredentialLoginModule.Name"
                     >
            WebServices
         </log:option>
        </log:login-module>
      </log:login-config>
    </xml-reference>
  </gbean>
</configuration>

Note that the GBean names and class names in this example were split across multiple lines to fit the page, and will need to be combined again to deploy properly.

16.4.3.2. Setting up the service-ref

The Geronimo deployment plan for the Web or EJB module must include a block that adds the security settings to the service-ref. However, in the current schema, at least the uri is required, so a service-ref block in the Geronimo deployment plan might look like this:

<service-ref>
  <service-ref-name>service/ProductReviews</service-ref-name>
  <port>
    <uri>/path/to/ProductReviews</uri>
    <credentials-name>WebServices</credentials-name>
  </port>
</service-ref>

Note that the credentials-name specified here must match the login module option org.apache.geronimo.jaas.NamedUPCredentialLoginModule.Name for the new login module in the security realm, and of course that security realm must be configured for the user logging in to the application so their credentials are saved and can be reused when invoking the web service.

16.4.4. Packaging and Deployment

In order for a web service client to work, the WAR or EJB JAR must contain:

  • The client service interface, packaged with the rest of the web or EJB classes

  • The service endpoint interface, packaged with the rest of the web or EJB classes

  • The WSDL file, in the WAR or EJB JAR at the location specified in the service-ref

  • The JAX-RPC mapping file, in the WAR or EJB JAR at the location specified in the service-ref

Beyond that, there are no particular packaging or deployment issues -- the WAR or EJB JAR can be deployed like normal, either standalone or as part of an EAR.

16.4.5. Accessing the Service

A J2EE component can look up the client service interface in JNDI (at the location configured in the service-ref), use that to get an instance of the service endpoint interface, and use that to communicate with the service. For example, based on the configuration above:

Context ctx = new InitialContext();
Object obj = ctx.lookup("java:comp/env/service/ProductReviews");
ProductReviewsService service = (ProductReviewsService) obj;
ProductReviews port = service.getProductReviews();
String[] reviewers = port.getReviewers(productId);
...