Retired Document
Important: This document may not represent best practices for current development. Links to downloads and other resources may no longer be valid.
Developing Web Service Applications
You can publish as Web service operations the public methods of any class that contains a no-argument constructor. Also, methods that correspond to document-style operations, must return an org.w3c.dom.Document
. You can find documentation for these classes at http://xml.apache.org/axis
, and http://www.w3.org
respectively.
This chapter contains the following sections:
Providing a Web Service
As a companion to this document, in projects/Calculator
, you find the Calculator project. It's a simple WebObjects application project used to build an application that serves a Web service called Calculator. The service provides four operations: add
, subtract
, multiply
, and divide
. The operations take two parameters of type double
and return a value of type double
. The Calculator.java
class, the workhorse of the Calculator Web service, is listed in Listing 3-1
.
Listing 3-1
Calculator.java
class in Calculator project
public class Calculator extends Object { |
public static double add(double addend1, double addend2) { |
double sum = addend1 + addend2; |
return sum; |
} |
public static double subtract(double minuend, double subtrahend) { |
double difference = minuend - subtrahend; |
return difference; |
} |
public static double multiply(double multiplicand1, double multiplicand2) { |
double product = multiplicand1 * multiplicand2; |
return product; |
} |
public static double divide(double dividend, double divisor) { |
double quotient = dividend / divisor; |
return quotient; |
} |
} |
To provide a Web service based on Calculator.java
the Application object registers Calculator.java
as a Web service with the following method invocation:
WOWebServiceRegistrar.registerWebService(Calculator.class, true); |
The WOWebServiceRegistrar
class (com.webobjects.webservices.appserver
) provides methods to register and unregister classes as Web services, set a security delegate, register XSLT (Extensible Stylesheet Language Transformations) scripts for operations, and so on.
To become a Web service provider, build and run the Calculator application. To view the WSDL document for the Web service, point your Web browser to http://localhost:4210/WebObjects/Calculator.woa/ws/Calculator?wsdl
.
Consuming a Web Service
The companion project Calculator_Client, located in project/Calculator_Client
, contains the source files used to create the Calculator_Client application, which consumes the Calculator Web service described in Providing a Web Service
. Its main class is CalculatorClient.java
, shown in Listing 3-2
.
Listing 3-2
CalculatorClient.java
class in Calculator_Client project
import java.net.*; |
import java.util.Enumeration; |
import com.webobjects.foundation.*; |
import com.webobjects.webservices.client.*; |
public class CalculatorClient extends Object { |
/** |
* Object through which the Web service's operations are invoked. |
*/ |
private WOWebServiceClient _serviceClient = null; |
/** |
* Address for the Web service's WSDL document. |
*/ |
private String _service_address = |
"http://localhost:4210/cgi-bin/WebObjects/Calculator.woa/ws/Calculator?wsdl"; |
/** |
*/ |
public CalculatorClient() { |
super(); |
} |
/** |
* Obtains the Web service's operation names. |
* @return the Web service's operation names. |
*/ |
public NSArray operations() { |
NSArray operations = (serviceClient().operationsDictionaryForService(serviceName())).allValues(); |
NSMutableArray operation_names = new NSMutableArray(); |
Enumeration operations_enumerator = operations.objectEnumerator(); |
while (operations_enumerator.hasMoreElements()) { |
WOClientOperation operation = (WOClientOperation)operations_enumerator.nextElement(); |
operation_names.addObject((String)operation.name()); |
} |
return operation_names; |
} |
/** |
* Invokes the Web service's operations. |
* @param operation operation to invoke; |
* @param arguments argument list; |
* @return value returned by the operation. |
*/ |
public Double invoke(String operation, Object[] arguments) {// 1 |
Object result = serviceClient().invoke(serviceName(), operation, arguments); |
return (Double)result; |
} |
/** |
* Obtains the Web service name. |
* Normally one WSDL file describes one Web service, |
* but it could describe one or more services. |
* @return Web service name. |
*/ |
public String serviceName() {// 2 |
return (String)serviceClient().serviceNames().objectAtIndex(0); |
} |
/** |
* Obtains an WOWebServiceClient through which service operations are invoked. |
* @return Web service–client object. |
*/ |
private WOWebServiceClient serviceClient() { |
if (_serviceClient == null) { |
_serviceClient = clientFromAddress(_service_address); |
} |
return _serviceClient; |
} |
/** |
* Obtains a Web service–client object through which |
* service operations can be invoked. |
* @return Web service–client object. |
*/ |
private static WOWebServiceClient clientFromAddress(String address) { |
WOWebServiceClient service_client = null; |
// Create the Web service's URL. |
URL url; |
try { |
url = new URL(address); |
} |
catch (MalformedURLException e) { |
url = null; |
} |
// Get a service-client object. |
service_client = new WOWebServiceClient(url);// 3 |
return service_client; |
} |
} |
The following list highlights some aspects of CalculatorClient.java
.
-
The
invoke
method defines as parameters the operation name and its arguments. It uses theinvoke
method of WOWebServiceClient to invoke the Web service operation. -
The
serviceName
method returns the name of the first Web service in the list of Web services defined by the WSDL document used to create the WOWebServiceClient object. Most WSDL documents define one Web service, but a WSDL document can define more than one Web service. -
The WOWebServiceClient class (
com.webobjects.webservices.client
) provides a one-argument constructor that takes a URL (java.net
) object that points to a WSDL document. Therefore, to create a WOWebServiceClient you must create a URL object from the URL (Uniform Resource Locator) of the appropriate WSDL document.
Build and run the Calculator_Client application. Your Web browser should show a page like the one shown in Figure 3-1
. If your Web browser didn't launch, launch it and connect to http://localhost:4210/cgi-bin/WebObjects/Calculator_Client.woa
.
Using Sessions in Web Services
Using sessions during Web service consumption is simple. You get a session from one Web service and share it with other Web services served from the same application. For example, you can develop an application that provides several related Web services. A practical way to share information among the services is to store shared data in a session object.
The Session project, in projects/Session
, showcases a simple Web service application that provides two Web services: LogIn and AccessData. The LogIn service accepts user data and stores in a session. To give the AccessData service access to the information recorded by LogIn, its session is set to the one used by LogIn.
The Session_Client project, in projects/Session_Client
, implements a Web service client that consumes LogIn and AccessData. It sets user name and password properties through LogIn and retrieves them through AccessData. Listing 3-3
shows the logic behind this process.
Listing 3-3 Session_Client project—Application.java
file
import com.webobjects.appserver.*; |
import com.webobjects.foundation.*; |
import com.webobjects.webservices.client.*; |
public class Application extends WOApplication { |
public static void main(String argv[]) { |
WOApplication.main(argv, Application.class); |
} |
public Application() { |
super(); |
System.out.println("Welcome to " + this.name() + "!"); |
// Create the service client used to consume |
// both LogInService and AccessDataService. |
SecurityClient securityClient = new SecurityClient(); |
// Log in as Susana with the password anasus. |
securityClient.logIn("Susana", "anasus"); |
// Get session from LogInService. |
WOWebService.SessionInfo sessionInfo = securityClient.logInSessionInfo(); |
// Set AccessDataService's session to the one obtained from LogInService. |
securityClient.setAccessDataSessionInfo(sessionInfo); |
// Get values of properties stored in session created by LogInService. |
String userName = securityClient.userName(); |
String userPassword = securityClient.userPassword(); |
// Print the properties' values. |
System.out.println(); |
System.out.println("************************************************"); |
System.out.println("User name from AccessDataService: " + userName); |
System.out.println("User password from AccessDataService: " + userPassword); |
System.out.println("************************************************"); |
System.out.println(); |
} |
} |
Listing 3-4 shows the SessionClient class in the Session_Client project.
Listing 3-4 Session_Client project—SessionClient.java
file
import java.net.*; |
import com.webobjects.appserver.*; |
import com.webobjects.foundation.*; |
import com.webobjects.webservices.client.*; |
/** |
* Used to consume the LogIn and AccessData Web services. |
*/ |
public class SecurityClient extends Object { |
private WOWebServiceClient _logInClient = null; |
private WOWebServiceClient _accessDataClient = null; |
private final String LogInServiceAddress = "http://localhost:4220/cgi-bin/WebObjects/Security.woa/ws/LogIn?wsdl"; |
private final String AccessDataServiceAddress = "http://localhost:4220/cgi-bin/WebObjects/Security.woa/ws/AccessData?wsdl"; |
private final String LogInService = "LogIn"; |
private final String AccessDataService = "AccessData"; |
public SecurityClient() { |
super(); |
} |
/** |
* Invokes the setUserInfo operation of the LogIn Web service. |
*/ |
public void logIn(String name, String password) { |
Object[] arguments = { name, password }; |
logInClient().invoke(LogInService, "setUserInfo", arguments); |
} |
/** |
* Invokes the userName operation of the AccessData Web service. |
* @return user name stored in shared session object. |
*/ |
public String userName() { |
Object result = accessDataClient().invoke(AccessDataService, "userName", null); |
return (String)result; |
} |
/** |
* Invokes the userPassword operation of the AccessData Web service. |
* @return user password stored in shared session object. |
*/ |
public String userPassword() { |
Object result = accessDataClient().invoke(AccessDataService, "userPassword", null); |
return (String)result; |
} |
/** |
* Obtains a Web service client through which LogIn operations are invoked. |
* @return a Web service client for LogIn. |
*/ |
protected WOWebServiceClient logInClient() { |
if (_logInClient == null) { |
_logInClient = clientFromAddress(LogInServiceAddress); |
} |
return _logInClient; |
} |
/** |
* Obtains a Web service client through which AccessData operations are invoked. |
* @return a Web service client for AccessData. |
*/ |
protected WOWebServiceClient accessDataClient() { |
if (_accessDataClient == null) { |
_accessDataClient = clientFromAddress(AccessDataServiceAddress); |
} |
return _accessDataClient; |
} |
/** |
* Obtains session information from LogInService. |
* @return session information from LogInService. |
*/ |
public WOWebService.SessionInfo logInSessionInfo() { |
return logInClient().sessionInfoForServiceNamed(LogInService); |
} |
/** |
* Sets the session used by AccessDataService. |
*/ |
public void setAccessDataSessionInfo(WOWebService.SessionInfo sessionInfo) { |
accessDataClient().setSessionInfoForServiceNamed(sessionInfo, AccessDataService); |
} |
/** |
* Obtains a Web service client through which |
* service operations are invoked. |
* @return Web service client object. |
*/ |
private WOWebServiceClient clientFromAddress(String address) { |
WOWebServiceClient service_client = null; |
// Create the Web service's URL. |
URL url; |
try { |
url = new URL(address); |
} |
catch (MalformedURLException e) { |
url = null; |
} |
// Get a service-client object. |
service_client = new WOWebServiceClient(url); |
return service_client; |
} |
} |
Listing 3-5 shows the LogIn class in the Session project.
Listing 3-5 Session project—LogIn.java file
import org.apache.axis.MessageContext; |
import com.webobjects.appserver.*; |
import com.webobjects.foundation.*; |
/** |
* Implements the LogIn Web service. |
*/ |
public class LogIn { |
public static final String USER_NAME = "userName"; |
public static final String USER_PASSWORD = "userPassword"; |
/** |
* Sets a user's name and password properties in a session. |
*/ |
public void setUserInfo(String userName, String userPassword) { |
WOSession session = serviceSession(); |
session.setObjectForKey(userName, USER_NAME); |
session.setObjectForKey(userPassword, USER_PASSWORD); |
} |
/** |
* Retrieves the session from the current context. |
* @return current context's session. |
*/ |
private WOSession serviceSession() { |
WOContext context = (WOContext)MessageContext.getCurrentContext().getProperty("com.webobjects.appserver.WOContext"); |
WOSession session = context.session(); |
return session; |
} |
} |
Listing 3-6 shows the AccessData class in the Session project.
Listing 3-6 Session project—AccessData.java
file
import org.apache.axis.MessageContext; |
import com.webobjects.appserver.*; |
import com.webobjects.foundation.*; |
/** |
* Implements the AccessData Web service. |
*/ |
public class AccessData { |
/** |
* Obtains the value of the USER_NAME property from the session. |
* @return user name. |
*/ |
public String userName() { |
String userName = null; |
WOSession session = serviceSession(); |
if (session != null) { |
userName = (String)session.objectForKey(LogIn.USER_NAME); |
} |
return userName; |
} |
/** |
* Obtains the value of the USER_PASSWORD property from the session. |
* @return user password. |
*/ |
public String userPassword() { |
String userPassword = null; |
WOSession session = serviceSession(); |
if (session != null) { |
userPassword = (String)session.objectForKey(LogIn.USER_PASSWORD); |
} |
return userPassword; |
} |
/** |
* Retrieves the session from the current context. |
* @return current context's session. |
*/ |
private WOSession serviceSession() { |
WOContext context = (WOContext)MessageContext.getCurrentContext().getProperty( |
"com.webobjects.appserver.WOContext"); |
WOSession session = context.session(); |
return session; |
} |
} |
Accessing the WOContext Object
Sometimes you may need to access the context (com.webobjects.appserver.WOContext
) of an HTTP request. For example, you can use the WOContext object to store data you want to share between methods or classes as an operation is processed. To access the WOContext object associated with an operation's invocation, use the code in Listing 3-7
.
Listing 3-7 Accessing the WOContext object from a Web service class
import com.webobjects.appserver.WOContext; |
import org.apache.axis.MessageContext; |
... |
MessageContext message_context = MessageContext.getCurrentContext(); |
WOContext context = (WOContext)message_context.getProperty("com.webobjects.appserver.WOContext"); |
Adding Security to Web Services
You can add security processing to Web services by creating a security delegate class that implements methods of the WOSecurityDelegate
interface in the com.webobjects.webservices.support
package. These methods are
-
processClientRequest
: Invoked by consumer applications before sending a request to the provider. -
processClientResponse
: Invoked by consumer applications before processing a response from the provider. -
processServerRequest
: Invoked by provider applications before processing a request from a consumer. -
processServerResponse
: Invoked by provider applications before sending a response to a consumer. -
onFaultClientRequest
: Invoked by consumer applications when a processing exception occurs while generating a request. -
onFaultClientResponse
: Invoked by consumer applications when a processing exception occurs while processing a server response. -
onFaultServerRequest
: Invoked by provider applications when a processing exception occurs while processing a consumer request. -
onFaultServerResponse
: Invoked by provider applications when a processing exception occurs while generating a response.
The projects Security
and Security_Client
in projects/Security
and projects/Security_Client
, respectively, show how the methods of a security-delegate class are invoked before and after an operation is executed.
Web Service Deployment Descriptors
Under Axis, Web services are deployed using XML-based files known as Web service deployment descriptors (WSDD). The Resources group of Web service application projects contains one or two of these files, named client.wsdd
and server.wsdd
. Application projects that only provide Web services have the server.wsdd
file, while projects that consume services contain both.
Listing 3-8
shows the server.wsdd
file of a Web service provider project.
Listing 3-8 The server.wsdd
file of a Web service provider project
<?xml version="1.0" encoding="UTF-8"?> |
<deployment |
xmlns="http://xml.apache.org/axis/wsdd/" |
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> |
<globalConfiguration> |
<parameter name="sendMultiRefs" value="true"/> |
<parameter name="sendXsiTypes" value="true"/> |
<parameter name="sendXMLDeclaration" value="true"/> |
<requestFlow> |
<handler type="java:com.webobjects.webservices.support._private.WOSecurityHandler"/> |
<handler type="java:com.webobjects.appserver._private.WOServerSessionHandler"/> |
</requestFlow> |
<responseFlow> |
<handler type="java:com.webobjects.appserver._private.WOServerSessionHandler"/> |
<handler type="java:com.webobjects.webservices.support._private.WOSecurityHandler"/> |
</responseFlow> |
</globalConfiguration> |
<handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/> |
<handler name="HTTPActionHandler" type="java:org.apache.axis.handlers.http.HTTPActionHandler"/> |
<handler name="RPCDispatcher" type="java:org.apache.axis.providers.java.RPCProvider"/> |
<handler name="MsgDispatcher" type="java:org.apache.axis.providers.java.MsgProvider"/> |
<transport name="http"> |
<requestFlow> |
<handler type="HTTPActionHandler"/> |
<handler type="URLMapper"/> |
</requestFlow> |
</transport> |
</deployment> |
Listing 3-9 shows the client.wsdd file of a Web service consumer project.
Listing 3-9 The client.wsdd
file of a Web service consumer project
<?xml version="1.0" encoding="UTF-8"?> |
<deployment |
xmlns="http://xml.apache.org/axis/wsdd/" |
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> |
<globalConfiguration> |
<parameter name="sendMultiRefs" value="true"/> |
<parameter name="sendXsiTypes" value="true"/> |
<parameter name="sendXMLDeclaration" value="true"/> |
<requestFlow> |
<handler type="java:com.webobjects.webservices.support._private.WOSecurityHandler"/> |
<handler type="java:com.webobjects.webservices.client._private.WOClientSessionHandler"/> |
</requestFlow> |
<responseFlow> |
<handler type="java:com.webobjects.webservices.client._private.WOClientSessionHandler"/> |
<handler type="java:com.webobjects.webservices.support._private.WOSecurityHandler"/> |
</responseFlow> |
</globalConfiguration> |
<transport name="http" pivot="java:org.apache.axis.transport.http.HTTPSender"/> |
<transport name="https" pivot="java:org.apache.axis.transport.http.HTTPSender"/> |
<transport name="local" pivot="java:org.apache.axis.transport.local.LocalSender"/> |
</deployment> |
You can edit the server.wsdd
and the client.wsdd
files to add handlers or to add Web services that have static WSDL documents. However, you must not remove any of the handlers defined in those files by default. Also, you should consult the Axis documentation before making any changes to the WSDD files.
Adding Web Service Support to Existing Projects
To add Web service–provider support to an existing project, you have to add the JavaWebServiceSupport
framework to it. To add Web service–client support, you need to add the JavaWebServiceSupport and JavaWebServiceClient
frameworks. The frameworks are located in /System/Library/Frameworks
($NEXT_ROOT/Library/Frameworks
on Windows).
Copyright © 2002, 2007 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2007-07-11