進階自訂 > Info*Engine User's Guide (Info*Engine 使用指南) > Web Services Framework > Writing a Java-based Web Service Client
  
Writing a Java-based Web Service Client
The project directory (src_client) and the example Java source file src_client/org/myorg/MathClient.java were created in the step “Create a Project” in the Writing an Info*Engine-based Web Service section.
The MathClient.java source file is dependent upon source artifacts, which are generated from your deployed web service. Before actually being able to complete your client source, you must generate and compile these artifacts. As generated, MathClient.java compiles, but does nothing until you use it to invoke a web service method.
In order to get these artifacts, you must compile your empty client using the following commands:
% cd <Windchill>/prog_examples/jws/MyProject/src_client
% ant
The Apache Ant script also generates an executable JAR file of your application:
<Windchill>/prog_examples/jws/MyProject/dist_client/MathServiceClient.jar
However, since your main class does nothing, then executing the JAR also does nothing. Running the previous ant command processes the WSDL for your web service and generates Java source artifacts to the following:
<Windchill>/prog_examples/jws/MyProject/gensrc_client
This creates Java source code within the com.ptc.jws.service.org.myorg.mathservice package. To avoid Java code being generated into a package with a name derived from the service name space, you can use the jaxws.package property within the build.xml file to explicitly define which package you want the source code generated into.
Edit the client source code to complete your client:
1. In a text editor, open the following file:
<Windchill>/prog_examples/jws/MyProject/src_client/org/myorg/MathClient.java
The source looks something like:
package org.myorg;

// import the classes generated when compiling your client
//import com.ptc.jws.service.?.*;
import com.ptc.jws.client.handler.*;

public class MathClient
{
public static void main ( String [] args ) throws java.lang.Exception
{
// depending on your security requirements you may need to specify credentials up
// front, or on the command-line where most policies will prompt for them
//Credentials.setUsername ( "demo" );
//Credentials.setPassword ( "demo" );
// TODO implement your client /*
MathServiceImplService service = new MathServiceImplService();
MathServiceImpl port = service.getMathServiceImplPort ();
//invoke an action
//port.methodName ( <arguments> );
*/
}
}
2. Update the source to import the server-side web service artifacts, and invoke a method as follows:
package org.myorg;

// import the classes generated when compiling your client
import com.ptc.jws.service.org.myorg.mathservice.*;

public class MathClient
{
public static void main ( String [] args ) throws java.lang.Exception
{
int a = args.length > 0 ? Integer.parseInt ( args[0] ) : 0;
int b = args.length > 1 ? Integer.parseInt ( args[1] ) : 0;

MathServiceImplService service = new MathServiceImplService();
MathServiceImpl port = service.getMathServiceImplPort ();
System.out.printf ( "a+b=%d\n", port.add ( a, b ) );
System.out.printf ( "a-b=%d\n", port.subtract ( a, b ) );
System.out.printf ( "a*b=%d\n", port.multiply ( a, b ) );
System.out.printf ( "a/b=%f\n", port.divide ( a, b ) );
}
}
3. Recompile your client and update your executable JAR to include the updated classes:
% ant compile
% ant dist
4. Run your new web service client from the command line:
% java -jar ../dist_client/MathServiceClient.jar 10 20
Username:<password>
Password:<username>
a+b=30
a-b=-10
a*b=200
a/b=0.500000
Where <username> is the username and <password> is the password you have supplied. When running your client, you are prompted on the command line for credentials.
Client Callback Handlers
When creating the web service project, the -Dsecurity.policy=usernameAuthSymmetricKeys property was supplied. This instructed the framework to explicitly secure the web service with the security policy, which is described in Username Authentication with Symmetric Keys. If this property had not been explicitly provided, then the security policy would have defaulted to the value of the security.policy property as configured in <Windchill>/bin/adminTools/WebServices/security.properties.
When generating the client portion of the project, this policy causes a default client-side callback handler configuration to be used. This is specified in the handler.config property of the src_client/build.xml build script. To view the format of the handler.config property, run the ant usage command from within the src_client directory.
The com.ptc.jws.client.handler package also contains some basic callback handlers for your web service client to use for the supported security policies (these handler classes are automatically packaged for you when you build your client). You can choose to use these classes to provide security information for your web service clients, or you can choose to author your own by providing a class that implements javax.security.auth.callback.CallbackHandler and then providing that class as part of the handler.config property.
The default callback handler supplied for usernameAuthSymmetricKeys prompts for credentials on the command line. It can be configured to prompt the user for credentials using swing dialogs or to fetch the credentials from system properties. It only prompts for credentials once per thread, and reuses the credentials until you programatically clear them.
If you want to programmagically provide credentials, you should do so using the com.ptc.jws.client.handler.Credentials class using the setUsername and setPassword methods.
The web services framework makes use of two separate callback mechanisms:
The WSIT (Web Services Interoperability Technologies) mechanism uses the javax.security.auth.callback.CallbackHandler implementations.
These handlers are used for security policies other than webServerAuthenticated to gather the credentials or security tokens that are passed to the web service. If these implementations do not meet the needs of your application, you can implement your own and supply them using the handler.config property in the build.xml file.
The JAX-WS handler chain is essentially a list of Java classes typically implementing the following:
javax.xml.ws.handler.soap.SOAPHandler<javax.xml.ws.handler.soap.SOAPMessageContext>
Instead of implementing the client code, these handler classes can provide generic functionality and conditioning for SOAP interactions. The web services framework provides some basic handlers to handle details, such as supplying the URL to your web service and adding credentials to requests when web server authentication is used.
These handlers can also be written to perform additional functions, such as add headers to SOAP requests or handle faults in a generic fashion. You can tailor the handler chain of you client by changing the values of the handler.chain properties in the build.xml file. These properties are described in greater detail within the build.xml file.
Portable Web Service Clients
There are certain issues that must be addressed to allow a web service client to run on a client machine properly or to interact with multiple identical services hosts on separate Windchill instances. Security policy configuration is essentially hard-coded at compile time, requiring a new client to be reconfigured for each client host. Similarly, the address of the web service is fixed at compile time, and therefore writing a client that interacts with separate service instances requires the service endpoint to be provided programatically. To improve the portability of web service clients, the Web Services Framework uses the JAX-WS handler chain, and allows client JAR files to be reconfigured as needed.
Using Security Policies
When securing a web service with one of the supported security policies (other than web server authentication), a Java client needs access to its own keystore and truststore. Paths to these files (keystore and truststore) are configured for use by the build framework in the following:
<Windchill>/bin/adminTools/WebServices/client/security.properties
The paths to the keystore and truststore are absolute, and must be compiled into deployment descriptors packaged with your client JAR file in its META-INF directory.
If you compile a web service client from the same host where Windchill is running with the standard configuration, then these files are available to your client, but only on that host. Before redistributing your web service client to another host, you must do one of the following:
Update the client/security.properties file (or make a copy of it in your src_client directory and then update it) to contain paths to the location where these files exist on the new client host, and then rebuild your client.
Reconfigure the client JAR file for every host from which it is run. For more information, see the “Reconfiguring the Client JAR File” section below.
Compile a copy of the client for every host on which it is intended to run, with each containing the appropriate paths for the specific host. For more information, see the “Compiling a Copy of Your Client for Every Host” section below.
Reconfiguring the Client JAR File
After compiling and packaging your client, the dist_client directory of your project includes two JAR files: one containing your compiled client, and the webservices-support.jar file. This JAR file is executable and can be used to reconfigure your client as follows:
% java -jar webservices-support.jar
-clientJar <jar file> [-targetJar <jar file>] [-securityProperties
<properties file>] [-wsdl <service wsdl>]
If -targetJar is not specified, then -clientJar is overwritten. You must also specify -wsdl or -securityProperties, or both.
To reconfigure the paths to the truststore and keystore locations on your client, copy the security.properties file to the client host and run the utility with the -securityProperties argument. This can also be used to reconfigure the default URL to your web service. Alternatively, you can supply the URL to your web service using a system property, or write your own JAX-WS handler to provide the URL.
* 
The file paths to the truststore and keystore locations within the property file must be absolute and cannot contain other property references.
When reconfiguring a client JAR in this way, you also need to supply additional information about what callback handlers your client should to use. If you do not supply this information, then your reconfigured client cannot function unless it is programmatically supplying the information normally supplied by callback handlers. Specifically, this includes the classes required to gather user credentials or perform other general processing through the JAX-WS handler chain.
Additional properties you might want to set are:
handler.config
handler.chain.authentication
handler.chain.extras
handler.chain.url
handler.chain.authentication
* 
For descriptions of these properties, run the ant usage command from within your src_client project directory.
For an existing client JAR, the configuration is supplied in the security.properties file. At build time this configuration is typically found within your src_client/build.xml Ant script.
If you are reconfiguring only the paths to truststores and keystores, then you should check the value of the handler.config property in your src_client/build.xml script. Supply this property in the security.properties file when reconfiguring your client JAR.
If you are reconfiguring your client JAR because your web service security policy has changed, then you might need to change the handler configuration of your client. For example:
#web service security.policy=userNameAuthSymmetricKeys
handler.config=usernameHandler:com.ptc.jws.client.handler.
UsernamePasswordCallbackHandler,passwordHandler:com.ptc.jws.client.handler.
UsernamePasswordCallbackHandler
#web service security.policy=samlsv
handler.config=samlHandler:com.ptc.jws.client.handler.SamlCallbackHandler
* 
These properties would be in addition to the com.ptc.jws.client. handler package.
If you are reconfiguring a client to a web service that is secured by web server authentication (security.policy=webServerAuthenticated) then you must supply the system property requires.authentication=true when running the command. A security.properties file is only necessary if you want to specify your own JAX-WS handler chain configuration. For example:
% java -D requires.authentication=true -clientJar <client jar> -wsdl <service wsdl>
In this case the default value for handler.chain.authentication is automatically used.
Compiling a Copy of Your Client for Every Host
Another option is to compile a copy of your client for every host it is intended to run on, with each containing the appropriate paths for the specific host.
For example:
% cd <Windchill>/prog_examples/jws/MathService/src_client
% cp <Windchill>/bin/adminTools/WebServices/client/security.properties .
Update the local copy of security.properties as necessary for the individual client. This ensures that these security properties take precedence over the common properties found in <Windchill>/bin/adminTools/WebServices/ client/security.properties.
Dynamically Specifying a Web Service URL
When creating a Java-based web service client, the HTTP connection information is determined from your Windchill configuration. When building the JAR for your web service client, the framework stores a local copy of the Web Service Definition Language (WSDL) to your web service and references that WSDL from a catalog file. This allows your client to avoid having to access the WSDL over the network at runtime.
By default, the web services framework configures your JAX-WS handler chain to include a class that imposes the URL to your server based on the Windchill configuration. The default implementation is com.ptc.jws.client.handler.WebServiceURLHandler, which can be overridden in build.xml using the handler.chain.url property. You should therefore not need to specify this information to run your client.
Your client can use the wt.webservice.url system property to override the web server URL, or you can supply the URL programmatically using the setWebServiceURL(java.net.URL url) method on the com.ptc.jws.client.handler.WebServiceURLHandler class.
Alternatively, you can override the handler.chain.url property with your own implementation to supply this URL. Doing this requires that you set the javax.xml.ws.BindingProvider.ENDPOINT_ADDRESS_PROPERTY within the instance of javax.xml.ws.handler.soap.SOAPMessageContext given to your handler implementation.
Web Server Authenticated Services and Clients
Using the standard security policies (such as SAML Sender Vouches or Username Authentication with Symmetric Keys) means that your web service servlet is deployed in a manner that is unprotected by web server authentication. In these cases it is the responsibility of the web service, not the web server, to enforce authentication.
You can also deploy your servlet behind web server authentication. In order to do this, use the webServerAuthenticated security policy when deploying, as documented in:
<Windchill>/bin/adminTools/WebServices/security.properties
The tooling automatically updates the protected resource configuration within <Windchill>/apacheConf (provided you are using a project to build and deploy the service). If running, these changes are propagated to your local Apache configuration, which should simply be restarted. If you are using a web server other than Apache, or your Apache is not located on the same host as Windchill, you must propagate these changes manually to your web server configuration.
By default, the JAX-WS handler chain is configured to contain a handler implementation to impose user credentials in outgoing requests for your web service client. These credentials can be supplied programmatically using the setUsername(String user) and setPassword(String password) methods on the com.ptc.jws.client.handler.Credentials class. Alternatively, credentials can be supplied on the wt.webservice.user and wt.webservice.password system properties.
You can also override the handler implementation using the handler.chain.authentication property within your build.xml file. If you implement your own handler, you must set the javax.xml.ws.BindingProvider.USERNAME_PROPERTY and javax.xml.ws.BindingProvider.PASSWORD_PROPERTY properties within the javax.xml.ws.handler.soap.SOAPMessageContext object supplied to your handler implementation.
* 
If you undeploy a web service that is protected by web server authentication, the tooling does not automatically update your web server configuration to remove the previously protected resource. You must reconfigure your web server manually.