The sample application for this solutions catalog entry is a swing client that provides a GUI to send a purchase order document to the String Purchase Order Web service. Here is a screenshot of the application:
This application is
written with the Netbeans[TM]
IDE 4.1. The primary class in the application is MainWindow
,
which is implemented as a Swing frame. It uses a delegate class POServiceBD
to invoke web services.
This application can be run stand-alone as well as with Java Web
Start. The Java Web Start enabled version of this application is
included in a Web application contained in webstart-client.war
.
POServiceBD
.
// import stub classes
import
com.sun.j2ee.blueprints.stringposervice.StringPurchaseOrderService_Impl;
import com.sun.j2ee.blueprints.stringposervice.StringPurchaseOrderServiceSEI;
// ... other contents of the class file
// Using stubs
StringPurchaseOrderService_Impl svcimpl = new StringPurchaseOrderService_Impl();
StringPurchaseOrderServiceSEI poservice = svcimpl.getStringPurchaseOrderServiceSEIPort();
((Stub)poservice)._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, serviceUrl);
String result = poservice.submitPO(xmlDocStr);
Code Example 1: Using Stubs to Invoke a Web Service
// import classes for service endpoint interface
import com.sun.j2ee.blueprints.stringposervice_wrapped.StringPurchaseOrderServiceSEI;
import com.sun.j2ee.blueprints.stringposervice_wrapped.SubmitPO;
import com.sun.j2ee.blueprints.stringposervice_wrapped.SubmitPOResponse;
// ... other contents of the class file
// Using dynamic proxy
ServiceFactory sf = ServiceFactory.newInstance();
URL wsdlURL = new URL(serviceUrl + "?WSDL");
QName serviceQname = new QName(NS_BODY, "StringPurchaseOrderService");
Service s = sf.createService(wsdlURL, serviceQname);
QName portQname = new QName(NS_BODY, "StringPurchaseOrderServiceSEIPort");
StringPurchaseOrderServiceSEI port =
(StringPurchaseOrderServiceSEI) s.getPort(portQname, StringPurchaseOrderServiceSEI.class);
SubmitPO param = new SubmitPO(xmlDocStr);
SubmitPOResponse response = port.submitPO(param);
String result = response.getResult();
Code Example 2: Using Dynamic Proxy to Invoke a Web Service
SubmitPO
is generated from the service WSDL,
however it needed to be rewritten to workaround a bug in the JAX-RPC
compiler where it names one of the private fields (String_1
) differently (string_1
instead of String_1
). This bug results in the SubmiPO
class becoming unusable for use with dynamic proxies or DII. // import classes for service endpoint interface
import com.sun.j2ee.blueprints.stringposervice_wrapped.StringPurchaseOrderServiceSEI;
import com.sun.j2ee.blueprints.stringposervice_wrapped.SubmitPO;
import com.sun.j2ee.blueprints.stringposervice_wrapped.SubmitPOResponse;
// ... other contents of the class file
// Using DII
ServiceFactory sf = ServiceFactory.newInstance();
URL wsdlURL = new URL(serviceUrl + "?WSDL");
QName serviceQname = new QName(NS_BODY, "StringPurchaseOrderService");
Service s = sf.createService(wsdlURL, serviceQname);
QName portQname = new QName(NS_BODY, "StringPurchaseOrderServiceSEIPort");
Call call = s.createCall(portQname);
call.setTargetEndpointAddress(serviceUrl);
call.setProperty(Call.SOAPACTION_USE_PROPERTY, new Boolean(true));
call.setProperty(Call.SOAPACTION_URI_PROPERTY,"");
// For WS-I compliant document-literal, need to set the encoding style
// to literal by specifying "" as the encoding style,
// and by setting the operation style to document
String ENCODING_STYLE_PROPERTY = "javax.xml.rpc.encodingstyle.namespace.uri";
String URI_ENCODING = "";
call.setProperty(ENCODING_STYLE_PROPERTY, URI_ENCODING);
call.setProperty(Call.OPERATION_STYLE_PROPERTY, "document");
// Note that the operation name need not be set by calling
// call.setOperationName(new QName(NS_BODY, "submitPO"));
// This is because the SOAP binding used by the Web service is document, not rpc.
// The types for the request parameter and return value are defined in the
// WSDL file itself, so their qnames are defined with the namespace of the body
QName requestQname = new QName(NS_BODY, "submitPO");
QName responseQname = new QName(NS_BODY, "submitPOResponse");
// Define the type of the return value for the DII call.
// SubmitPOResponse must match the wrapped type sent by the Web service.
call.setReturnType(responseQname, SubmitPOResponse.class);
// Define the type of the method parameter for the DII call.
// In the WSDL file, the name of the message part for submitPO is "parameters"
// Hence the request parameter is defined in this way.
call.addParameter("parameters", requestQname, SubmitPO.class, ParameterMode.IN);
SubmitPO param = new SubmitPO(xmlDocStr);
Object[] params = {param};
// Invoke the DII call
SubmitPOResponse response = (SubmitPOResponse) call.invoke(params);
String result = response.getResult();
Code Example 3: Using DII to Invoke a Web Service
lib/
directory of the J2EE SDK
installation. All of these Jar files need to be signed by the same
certificate. We sign the Jar files using the s1as
certificate present in the keystore of the default domain (domain1
) of the J2EE SDK. Code Example 4 presents an ant build.xml
fragment illustrating how the Jar files are signed: <!-- use the keystore present in the default domain of the J2EE SDK -->
<property name="keystore.location" value="${j2ee.home}/domains/domain1/config/keystore.jks"/>
<!-- we are using the default password used for the
keystore. This value should be changed if the keystore password has
been changed for the J2EE SDK -->
<property name="keystore.password" value="changeit"/>
<property name="key.alias" value="s1as"/>
<!-- sign application jar -->
<signjar
jar="${war.build.dir}/swing-client.jar"
signedjar="${war.build.dir}/swing-client-signed.jar"
alias="${key.alias}" keystore="${keystore.location}"
storepass="${keystore.password}"/>
<property name="jaxrpc-webstart-support.dir" value="${war.build.dir}/jws-support"/>
<!-- sign JAXRPC runtime jars -->
<signjar
jar="${j2ee.home}/lib/j2ee.jar"
signedjar="${jaxrpc-webstart-support.dir}/j2ee.jar"
alias="${key.alias}" keystore="${keystore.location}"
storepass="${keystore.password}"/>
<signjar jar="${j2ee.home}/lib/jaxrpc-api.jar"
signedjar="${jaxrpc-webstart-support.dir}/jaxrpc-api.jar"
alias="${key.alias}" keystore="${keystore.location}"
storepass="${keystore.password}"/>
<!-- ..... sign other jar files in the same way -->
Code Example 4: Ant Build Fragment for Signing Jar Files
jnlp
element needs a codebase attribute
which is a URL where the application jar files are available. We would
like the codebase to be discovered dynamically to match the URL
where the application war module was deployed. Similarly, the Swing
client needs to dynamically determine the URL where the String Purchase
Order Web Service is running. This can be done by generating the JNLP
descriptor through a JSP file bundled in the application war module.application/x-java-jnlp-file
so that the Java Web Start gets invoked correctly. This can be done by using a JSP page directive as illustrated in Code Example 5: <%@ page contentType="application/x-java-jnlp-file" info="Swing Client JNLP" %>
Code Example 5: Using contentType Page Directive for JNLP Descriptors
http
or https
),
the server name, the server port, and the context path where the
application jar files are available. The server port need not be
specified if it is 80 for http
and 443 for https
. Code Example 6 presents a JSP code fragment that calculates the codebase: <%
StringBuffer serverurl = new StringBuffer();
serverurl.append(!request.isSecure() ? "http://" : "https://");
serverurl.append(request.getServerName());
if (request.getServerPort() != (!request.isSecure() ? 80 : 443))
{
serverurl.append(':');
serverurl.append(request.getServerPort());
}
serverurl.append('/');
String codebase = serverurl + request.getContextPath() + '/';
%>
<?xml version="1.0" encoding="UTF-8"?>
<%-- JNLP File for launching Swing Client with JavaWebStart --%>
<jnlp spec="1.0+" codebase="<%=codebase%>" href="swing-client.jnlp">
Code Example 6: Dynamically Generating the Codebase
<%
String serviceurl = serverurl + "webservice/StringPurchaseOrderService";
%>
<!-- ... other JNLP descriptor contents -->
<resources>
<!-- ... other resource delcarations -->
<property name="stringwebservice.url" value="<%=serviceurl%>"/>
</resources>
Code Example 7: Passing a System Property to a Java Web Start Application
stringwebservice.url
property to set the Web service URL as shown in Code Example 8. String serviceurl = System.getProperty("stringwebservice.url");
if (serviceurl != null) {
serviceUrlTextField.setText(serviceurl);
}
Code Example 8: Retrieving a System Property in a Java Web Start Application
index.html
) of the Web
application provides a link to launch the Swing application through
Java Web
Start. This link does not directly refer to the JSP file that
generates the JNLP descriptor. Instead, it links to a virtual URL swing-client.jnlp
which is mapped to the JSP file.This is done to ensure that the browser gets the .jnlp
extension for the JNLP file to handle the case where a browser uses
file extension to invoke Java Web Start. This is done by using a servlet-mapping
element as shown in Code Example 9: <!-- map the JNLP JSP as a servlet since only servlets can have servlet-mapings -->
<servlet>
<servlet-name>jnlp-gen</servlet-name>
<jsp-file>swing-client-jnlp.jsp</jsp-file>
</servlet>
<!-- map the virtual URL /swing-client.jnlp to the JSP file -->
<servlet-mapping>
<servlet-name>jnlp-gen</servlet-name>
<url-pattern>/swing-client.jnlp</url-pattern>
</servlet-mapping>
Code Example 9: Mapping the JSP File Generating the JNLP Descriptor to .jnlp Extension