Professional Documents
Culture Documents
Web Services
Prev Next
package org.jboss.chap12.hello;
That is our web service implementation. In addition to this, we need a service endpoint
class that defines the interface of the web service. That is shown here as the Hello
interface.
package org.jboss.chap12.hello;
import java.rmi.Remote;
import java.rmi.RemoteException;
The service endpoint interface is declared Remote and the methods must throw
RemoteException. Beyond this, it is a simple expression of the interface to our web
service. This is all the code we need to write to expose a J2EE web service. Deploying it,
however, does require a few additional deployment descriptors.
<servlet>
<servlet-name>HelloWorldServlet</servlet-name>
<servlet-
class>org.jboss.chap12.hello.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorldServlet</servlet-name>
<url-pattern>/Hello</url-pattern>
</servlet-mapping>
</web-app>
The URL pattern in the servlet mapping is the only externally visible configuration
element. It controls what URL the web service lives at. This will be primarily noticed as
the location of the WSDL file for this service.
The web.xml file doesn't contain any web service related configuration. A new
deployment descriptor, webservices.xml, is needed to instruct JBoss to treat this
servlet as a web service and not as a normal servlet. But before we see that, we'll need
two additional configuration files, a WSDL file and a JAX-RPC mapping file. Both of
these files can be generated using the wscompile tool that ships as part of the Java Web
Services Developer Pack (WSDP).
This generates a WSDL file and a JAX-RPC mapping file based on the supplied
config.xml and the corresponding classes found on the classpath. The config.xml
file for the hello web service is shown below.
<configuration xmlns="http://java.sun.com/xml/ns/jax-
rpc/ri/config">
<service name="HelloService"
targetNamespace="http://hello.chap12.jboss.or
g/"
typeNamespace="http://hello.chap12.jboss.org/
types"
packageName="org.jboss.chap12.hello">
<interface name="org.jboss.chap12.hello.Hello"/>
</service>
</configuration>
The service element defines the interface our web service provides. The following
attributes are required:
Additionally, we need an interface element that tells wscompile what the Java
interface for the webservice is. This interface declares the operations that the web service
provides.
The WSDL file that wscompile generated for our config.xml file is shown below. Note
that the SOAP address isn't provided in the WSDL file. JBoss will insert the correct URL
for the WSDL when it deploys the web service.
We also asked wscompile to generate a JAX-RPC mapping file. This is shown below.
Once the extra files are generated, we need to bundle them up in a webservices.xml
file. This file links to our WSDL file with the wsdl-file element and to the mapping
file using the jaxrpc-mapping-file element.
In addition to this, a port-component element is needed that maps a port in the WSDL file
to a particular service implementation. For our JSE, this is done with a servlet-link
inside the service-impl-bean element. The servlet link must be the same as the name
of the pseudo-servlet we declared in the web.xml file.
<webservices xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://www.ibm.com/webservices/xsd/j2ee_web_services_1_1.x
sd" version="1.1">
<webservice-description>
<webservice-description-
name>HelloService</webservice-description-name>
<wsdl-file>WEB-INF/wsdl/HelloService.wsdl</wsdl-
file>
<jaxrpc-mapping-file>WEB-INF/mapping.xml</jaxrpc-
mapping-file>
<port-component>
<port-component-name>Hello</port-component-
name>
<wsdl-port>HelloPort</wsdl-port>
<service-endpoint-
interface>org.jboss.chap12.hello.Hello</service-endpoint-
interface>
<service-impl-bean>
<servlet-link>HelloWorldServlet</servlet-
link>
</service-impl-bean>
</port-component>
</webservice-description>
</webservices>
With these completed we can deploy the WAR file containing our web service. All the
deployment descriptors go in the WEB-INF directory, as shown in Figure 12.1, “The
structure of hello-servlet.war”. It's important to note that the WSDL file is required to be
in the wsdl subdirectory.
To deploy and test the hello web service, run the following from the examples directory:
Note the URL the JBoss publishes the WSDL file at. Our web application name is
hello-servlet and we mapped the servlet to /Hello in the web.xml file so the web
service is mappend to /hello-servlet/Hello. The ?wsdl query returns the WSDL
file.
If you aren't sure what the URL of the WSDL file will be, JBoss provides a way to list the
web services available on the system at /ws4ee/services. Figure 12.2, “The web
services list” shows a view of the services list.
The services list shows all of the deployed web services along with the name of the
deployment unit and a link to the WSDL file for that service.
package org.jboss.chap12.hello;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
This is a very trivial session bean. Session beans normally require a home interface and
either a local or remote interface. However, it is possible to omit them if the session bean
is only serving as a web services endpoint. However, we do still need the Hello service
endpoint interface that we used in the JSE example.
The ejb-jar.xml file is very standard for a session bean. The normal session bean
parameters are explained in Chapter 5, EJBs on JBoss. The only new element is the
service-endpoint element, which declares the service endpoint interface for the web
service.
<webservices xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://www.ibm.com/webservices/xsd/j2ee_web_services_1_1\.
xsd" version="1.1">
<webservice-description>
<webservice-description-
name>HelloService</webservice-description-name>
<wsdl-file>META-INF/wsdl/HelloService.wsdl</wsdl-
file>
<jaxrpc-mapping-file>META-INF/mapping.xml</jaxrpc-
mapping-file>
<port-component>
<port-component-name>Hello</port-component-
name>
<wsdl-port>HelloPort</wsdl-port>
<service-endpoint-
interface>org.jboss.chap12.hello.Hello</service-endpoint-
interface>
<service-impl-bean>
<ejb-link>HelloBean</ejb-link>
</service-impl-bean>
</port-component>
</webservice-description>
</webservices>
The first difference is that the WSDL file should be in the META-INF/wsdl directory
instead of the WEB-INF/wsdl directory. The second difference is that the service-
impl-bean element contains an ejb-link that refers to the ejb-name of the session
bean. The WSDL file and JAX-RPC mapping files remain unchanged from the previous
example.
To package and deploy the application, run the following command in the examples
directory:
The test program run here is the same as with the servlet example, except that we use a
different URL for the WSDL. JBoss composes the WSDL using the base name of the EJB
JAR file and the name of the service interface. However, as with all web services in
JBoss, you can use the http://localhost:8080/ws4ee/services service view
shown in Figure 12.2, “The web services list” to verify the deployed URL of the WSDL.
The full JAX-RPC programming model is available to J2EE applications and clients. We
won't cover the full range of client programming techniques, but we swill look briefly at
the client we've used so far to test the web services we've deployed. The client, shown in
the following listing, illustrates the dynamic proxy invocation mechanism.
package org.jboss.chap12.client;
import org.jboss.chap12.hello.Hello;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
import javax.xml.namespace.QName;
import java.net.URL;
ServiceFactory factory =
ServiceFactory.newInstance();
Service service =
factory.createService(url, qname);
System.out.println("hello.hello(" + argument +
")");
System.out.println("output:" +
hello.hello(argument));
}
}
This JAX-RPC client uses the Hello service endpoint interface and creates a dynamic
proxy to speak to the service advertised by the WSDL at the URL that is passed in as a
command line argument. For illustrative purposes, we'll show another variation of web
services invocation that doesn't use the service endpoint interface. This is known as the
Dynamic Invocation Interface (DII). Using DII, it is possible to refer to a specific port
and operation by name. Think of it as reflection for web services. The client code is
shown in the following listing.
package org.jboss.chap12.client;
import org.jboss.chap12.hello.Hello;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
import javax.xml.rpc.Call;
import javax.xml.namespace.QName;
import java.net.URL;
String ns =
"http://hello.chap12.jboss.org/";
QName qname = new QName(ns, "HelloService");
QName port = new QName(ns, "HelloPort");
QName operation = new QName(ns, "hello");
ServiceFactory factory =
ServiceFactory.newInstance();
Service service =
factory.createService(url, qname);
Call call = service.createCall(port,
operation);
System.out.println("hello.hello(" + argument +
")");
System.out.println("output:" + call.invoke(new
Object[] {argument}));
}
}
The following two commands can be used to run DII client against both the JSE and EJB
web services we have created.
The JAX-RPC examples in Section 12.3.1, “A JAX-RPC client” all required manual
configuration of the WSDL URL and knowledge of the XML nature of the web services
in question. This can be a configuration nightmare, but if your code is a J2EE component
there is another option. J2EE components can declare service references and look up
JAX-RPC Service objects in JNDI without needing to hardcode any web service
references in the code.
To show how this works, let's first look at a session bean that needs to make a call to the
hello web service:
package org.jboss.chap12.example;
import javax.ejb.*;
import javax.naming.*;
import java.rmi.RemoteException;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceException;
import org.jboss.chap12.hello.Hello;
} catch (ServiceException e) {
throw new EJBException(e);
} catch (RemoteException e) {
throw new EJBException(e);
}
}
ExampleBean invokes the hello web service in its doWork method. We've used the
dynamic proxy invocation method here, but any of the JAX-RPC supported invocation
methods would be fine. The interesting point here is that the bean has obtained the
Service reference from a JNDI lookup in its ENC.
Web service references are declared using a service-ref element in inside an ejb-
jar.xml file.
Figure 12.3. The service-ref content model
• service-ref-name: This is the JNDI name that the service object will be bound under in
the bean's ENC. It is relative to java:comp/env/.
• service-interface: This is the name of JAX-RPC service interface the client will use.
Normally this is javax.xml.rpc.Service, but it's possible to provide your own
service class.
• wsdl-file: This is the location of the WSDL file. The WSDL file should be under META-
INF/wsdl.
• jaxrpc-mapping-file: This is the location of the JAX-RPC mapping file.
• service-qname: This element specifies the name of the service in the web services file. It
is only mandatory if the WSDL file defines multiple services. The value must by a
QName, which means it needs to be a namespace qualified value such as
ns:ServiceName where ns is an XML namespace valid at the scope of the service-
qname element.
• port-component-ref: This element provides the mapping between a service endpoint
interface and a port in a web service.
• handler: This allows the specification of handlers, which act like filters or interceptors
on the current request.
The following service-ref declares a reference to the hello web service for the
Example session bean.
<session>
<ejb-name>Example</ejb-name>
<home>org.jboss.chap12.example.ExampleHome</home>
<remote>org.jboss.chap12.example.Example</remote>
<ejb-class>org.jboss.chap12.example.ExampleBean</ejb-
class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
<service-ref>
<service-ref-name>services/hello</service-ref-
name>
<service-interface>javax.xml.rpc.Service</service-
interface>
<wsdl-file>META-INF/wsdl/hello.wsdl</wsdl-file>
<jaxrpc-mapping-file>META-INF/mapping.xml</jaxrpc-
mapping-file>
<service-qname
xmlns:hello="http://hello.chap12.jboss.org">hello:HelloSer
vice</service-qname>
</service-ref>
</session>
This instructs the EJB deployer to make a Service object available for the bean in JNDI
under the name java:comp/env/services/hello that talks to our hello web service.
The session bean can then invoke normal web services operations on the service.
Since most of the web services configuration options are completely standard, there's
little need to go into great depths here. However, JBoss does provide several additional
web services configuration options through the service-ref element in the
jboss.xml deployment descriptor. The content model for the service-ref element is
shown in Figure 12.4, “The jboss.xml service-ref content model”.
Since the WSDL file generated by wscompile doesn't contain the SOAP address of our
web service, we'll use the WSDL override feature to dynamically download the correct
WSDL file from the server. While this might not be the best technique to use in a
production application, it does illustrate the WSDL override functionality very well. The
following jboss.xml file links the published URL for the hello-servlet version of
the hello web service..
The service-ref element is not limited to the ejb-jar.xml file. It's available to any
J2EE component. A service reference can be placed in the web.xml file for use by web
tier components or in the application-client.xml file for use by J2EE client
applications.
Prev Up Next
Chapter 11. The CMP Engine Home Chapter 13. Hibernate