Tuesday 25 August 2009

Are your libraries targeted to the correct WLS managed server?

Recently we upgraded our Oracle WebLogic Server's from 10.3 to 10.3.1, and coincidentally migrated a JDeveloper ADF application 11g to 11gR1. ADF applications require a set of libraries that must be deployed to WLS before the ADF application can run, of which we completed successfully, or so we thought. This post documents a little trap for new players when configuring WLS and deployed applications.

On deploying our upgraded ADF 11gR1 application to our WLS 10.3.1 server with the updated ADF libraries, we hit an error on deployment from JDev. The logs showed the following results:
[08:54:26 AM] ----  Deployment started.  ----
[08:54:26 AM] Target platform is (Weblogic 10.3).
[08:54:39 AM] Entering Target Selection Dialog
[08:54:55 AM] Retrieving existing application information
[08:54:55 AM] Running dependency analysis...
[08:54:55 AM] Building...
[08:54:59 AM] Deploying 4 profiles...
[08:54:59 AM] Wrote Archive Module to C:\JDeveloper\mywork\CR123\trunk\CommonViewController\deploy\CommonViewController.jar
[08:54:59 AM] Wrote Archive Module to C:\JDeveloper\mywork\CR123\trunk\CommonModel\deploy\CommonModel.jar
[08:54:59 AM] Wrote Web Application Module to C:\JDeveloper\mywork\CR123\trunk\ViewController\deploy\App_ViewController.war
[08:55:00 AM] Wrote Enterprise Application Module to C:\JDeveloper\mywork\CR123\trunk\deploy\App_application1.ear
[08:55:04 AM] Deploying Application...
[08:55:06 AM] [Deployer:149191]Operation 'deploy' on application 'App_application1' is initializing on 'ADFServer'
[08:55:06 AM] [Deployer:149193]Operation 'deploy' on application 'App_application1' has failed on 'ADFServer'
[08:55:06 AM] [Deployer:149034]An exception occurred for task [Deployer:149026]deploy application App_application1 on ADFServer.: [J2EE:160149]Error while processing library references. Unresolved application library references, defined in weblogic-application.xml: [Extension-Name: adf.oracle.domain, exact-match: false], [Extension-Name: oracle.jsp.next, exact-match: false]..
[08:55:06 AM] Weblogic Server Exception: weblogic.management.DeploymentException: [J2EE:160149]Error while processing library references. Unresolved application library references, defined in weblogic-application.xml: [Extension-Name: adf.oracle.domain, exact-match: false], [Extension-Name: oracle.jsp.next, exact-match: false].
[08:55:06 AM] See server logs or server console for more details.
[08:55:06 AM] weblogic.management.DeploymentException: [J2EE:160149]Error while processing library references. Unresolved application library references, defined in weblogic-application.xml: [Extension-Name: adf.oracle.domain, exact-match: false], [Extension-Name: oracle.jsp.next, exact-match: false].
[08:55:06 AM] #### Deployment incomplete. ####
[08:55:06 AM] Deployment Failed
The last set of errors reveals that the server can't find the libraries that the deployed application are dependent on. To highlight them:
[08:55:06 AM] Weblogic Server Exception: weblogic.management.DeploymentException: [J2EE:160149]Error while processing library references. Unresolved application library references, defined in weblogic-application.xml: [Extension-Name: adf.oracle.domain, exact-match: false], [Extension-Name: oracle.jsp.next, exact-match: false].
[08:55:06 AM] See server logs or server console for more details.
[08:55:06 AM] weblogic.management.DeploymentException: [J2EE:160149]Error while processing library references. Unresolved application library references, defined in weblogic-application.xml: [Extension-Name: adf.oracle.domain, exact-match: false], [Extension-Name: oracle.jsp.next, exact-match: false].
Note how WLS is stating it can't find adf.oracle.domain nor oracle.jsp.next.

This confused us because we could actually see them installed under the deployments tab in the WLS console. However the error in the end was a simple one on our part.

On installing the updated ADF libraries we installed them into the WLS AdminServer managed server. Yet on deploying our application, we chose to deploy the application to a separate WLS managed server called ADFServer (seen in the logs). For the application to find the ADF libraries, they needed to be installed into the ADFServer as well.

To fix this, one option is to head to the WLS console, locate the libraries in the Deployment node, and on selecting each library, under the Targets tab, ensure to allocate the libraries to the correct managed server. Alternatively your other option is to deploy your application to the WLS managed server where the libraries are targeted/installed.

Tuesday 18 August 2009

One-Way SSL with JAX-WS using JDeveloper 11gR1 and WLS 10.3.1

A while back Gerard Davison blogged some simple examples of using WS-Security Policies. Gerard's specific example dealt with the WLS policy Wssp1.2-2007-Wss1.1-UsernameToken-Plain-X509-Basic256.xml. As Gerard notes the said policy (further documented in the WLS 10.3.1 doco here) implements user name tokens, encryption of the tokens and signing of the whole SOAP payload.

The following post strips back Gerard's example to instead to consider the steps in setting up and testing One-Way SSL for a JAX-WS web service generated via JDeveloper 11gR1 and installed in WLS 10.3.1, using the WLS policy Wssp1.2-2007-Https.xml.

Assumptions

This article assumes the reader has the following basic knowledge:

* HTTPS/SSL
* Digital certificates and trusted/certificate authorities (CAs)
* Oracle's WebLogic Server, WLS managed servers and the WLS console

One-Way SSL vs Two-Way SSL

For those not familiar with either, Oracle's WLS documentation has a good explanation of the implementation of and differences between One-Way SSL and Two-Way SSL in the Understanding Security for Oracle WebLogic Server manual.

Steps

To implement a One-Way SSL example we'll run through the following steps:

1) Create a basic JAX-WS web service with JDeveloper 11gR1
2) Generate the digital certificates required for the WLS server
3) Modify the web service to use the Wssp1.2-2007-Https.xml WLS policy
4) Deploy the running web service to WLS
5) Test the running web service via JDeveloper's HTTP Analyzer
6) Test the running web service via SoapUI
7) Test the running web service via a JAX-WS client
8) Inspect the web service packets on the wire to verify the traffic is indeed encrypted

1) Create a basic JAX-WS web service with JDeveloper 11gR1

This step is documented in a previous blog post Creating JAX-WS web services via a WSDL in JDev 11g. There are also a number of viewlet demonstrations available from Oracle's OTN which show how to construct the WSDL in a drag'n'drop fashion.

The resulting web service we'll demonstrate here is a very simple one. It is comprised of the following solutions:

OneWaySSLExample.xsd

targetNamespace="http://www.sagecomputing.com.au" elementFormDefault="qualified">


The inputElement and the outputElement will constitute the incoming and outgoing payloads of a simple HelloWorld web service.

OneWaySSLExample.wsdl

xmlns:tns="urn:OneWaySSLExample.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:wsca="http://www.sagecomputing.com.au">



































The overall web service comprises of a single operation accepting the inputElement and outputElement strings as specified in the XSD.

OneWaySSLPortTypeImpl.java
package au.com.sagecomputing.ws;

import javax.jws.WebService;

import javax.xml.ws.BindingType;
import javax.xml.ws.soap.SOAPBinding;

@WebService(serviceName = "OneWaySSLService",
targetNamespace = "urn:OneWaySSLExample.wsdl",
portName = "OneWaySSLPortTypePort",
endpointInterface = "au.com.sagecomputing.ws.OneWaySSLPortType",
wsdlLocation = "/WEB-INF/wsdl/OneWaySSLExample.wsdl")
@BindingType(SOAPBinding.SOAP12HTTP_BINDING)
public class OneWaySSLPortTypeImpl {

public String oneWaySSLOperation(String part) {
return "Hello " + part;
}
}
A very basic JAX-WS web service accepting the inputElement String and returning the outputElement String prefixed with "Hello ".

Example request SOAP payload



Chris



Example response SOAP payload



Hello Chris

The overall application/project structure will look as follows in JDeveloper's Application Navigator:


2) Generate the digital certificates required for the WLS server

In order for a client to undertake a SSL connection with our web service on the WLS server, the WLS server must be configured with a valid digital certificate.

Again note from the Oracle documentation how One-Way SSL works at runtime:

With one-way SSL authentication, the target (the server) is required to present a digital certificate to the initiator (the client) to prove its identity. The client performs two checks to validate the digital certificate:

1. The client verifies that the certificate is trusted (meaning, it was issued by the client's trusted CA), is valid (not expired), and satisfies the other certificate constraints.
2. The client checks that the certificate Subject's common name (CN) field value matches the host name of the server to which the client is trying to connect

If both of the above checks return true, the SSL connection is established.


In this section we consider the digital certificates required for the WLS server.

WLS is an interesting application server in that it keeps two separate Java keystores, 1 for storing the digital certificates for such actions as SSL, and another which is typically used for storing CA digital certificates. The former is referred to as the identity keystore, the later the trust keystore.

The WLS manual Securing Oracle WebLogic Server section 11 Configuring Identity and Trust has a detailed explanation of this setup.

By default WLS comes with demonstration identity and trust keystores containing demonstration digital certificates. As the WLS documentation takes great pains to explain these are for development purposes only and should never be used in a production environment. For the purposes of this blog post if you're testing One-Way SSL in a development environment you can in fact skip this entire step as the demonstration WLS keystores will suffice.

To check that the demonstration keystores are currently installed login to your WLS console, select your server, and under the Configurations -> Keystores tab you'll see the following entries:


Your entries for the file locations of the keystore will be different from my example here dependent on where you installed WLS.

However using the demonstration keystores avoids the whole learning exercise of configuring your own custom digital certificates in WLS which is an important lesson. The following describes those steps in detail, as based off Gerard's original post.

To install our own digital certificate we followed these general steps:

a) Open a command prompt and set the WLS environment
b) Generate our own trusted certificate authority digital certificate
c) Store the private key and digital certificate and import into the identity keystore
d) Store the same digital certificate into the trust keystore.
e) Configure the new keystores in WLS's identity and trust keystore

The following describes those steps in detail. In order to do this we've used WLS utilities to do as much of the work as possible.

a) Open a command prompt and set the WLS environment

Under Windows open a command prompt on the same machine as where WLS is installed, create a temporary directory in your favourite place and cd to that directory, and run your WLS server's setDomainEnv.cmd command. Something like:

"C:\\setDomainEnv.cmd"

Once run ensure you're still in your new directory.

b) Generate our own trusted certificate authority digital certificate
java utils.CertGen -certfile ServerCACert -keyfile ServerCAKey -keyfilepass ServerCAKey -selfsigned -e somebody@xxxx.com.au -ou FOR-DEVELOPMENT-ONLY -o XXXX -l PERTH -s WA -c AU


This generates 4 files: ServerCACert.der, ServerCACert.pem, ServerCAKey.der, ServerCAKey.pem

The utils.CertGen utility is useful for development purposes, but as per the WLS documentation, should not be used for production purposes. Alternatively OpenSSL could be used instead.

Note the use of selfsigned flag. This implies this digital certificate will be used both as the CA in the trust keystore and the served digital certificate in the identity keystore. This is not what we'd do for a production environment using commercial Certificate Authorities, but is sufficient for demonstration purposes in this post.

More information on:

* the WLS CertGen utility can be found here.
* .der vs .pem files can be found here and here.
* WLS provides two utilities der2pem and pem2der can be used to convert between the two file types.

Under Windows you can double click on the ServerCACert.der file to show its contents:


If you have access to the openSSL command line tool you can use it to query the certificate we just created:
openssl x509 -text -inform der -in ServerCACert.der

Certificate:
Data:
Version: 3 (0x2)
Serial Number:
0d:a9:d1:4a:0f:0b:b2:61:13:90:89:f5:40:4d:4f:e2
Signature Algorithm: md5WithRSAEncryption
Issuer: C=AU, ST=WA, L=PERTH, O=SAGECOMPUTING, OU=FOR-DEVELOPMENT-ONLY, CN=/emailAddress=somebody@sagecomputing.com.au
Validity
Not Before: Jul 9 07:06:49 2009 GMT
Not After : Jul 10 07:06:49 2029 GMT
Subject: C=AU, ST=WA, L=PERTH, O=SAGECOMPUTING, OU=FOR-DEVELOPMENT-ONLY, CN=/emailAddress=somebody@sagecomputing.com.au
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:df:cb:6c:ed:86:75:4c:5b:66:cd:aa:3d:34:8f:

73:f6:9c:b5:ed:82:9c:c3:15
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:1
Signature Algorithm: md5WithRSAEncryption
b7:fa:1b:8f:c4:ee:af:6b:1d:f0:dc:f4:cf:35:20:f1:df:eb:

0c:fe
-----BEGIN CERTIFICATE-----
MIIC8zCCAlygAwIBAgIQDanRSg8LsmETkIn1QE1P4jANBgkqhkiG9w0BAQQFADCB

i7Pd63d03mWkI85tvsr5Q+40yitOL5JnLsbyHSrM+1aK8kkY7Qz+
-----END CERTIFICATE-----


This identifies information that maybe useful later if we make a mistake, such as the encryption algorithm used (RSA), the size of the keys (1024bit), the serial number of the certificate (a hex number).

c) Store the private key and the digital certificate in the identity keystore

java utils.ImportPrivateKey -certfile ServerCACert.der -keyfile ServerCAKey.der -keyfilepass ServerCAKey -keystore ServerIdentity.jks -storepass ServerCAKey -alias identity -keypass ServerCAKey


d) Store the same digital certificate into the trust keystore
Import the certificate generated in step b into a trust keystore.

keytool -import -v -trustcacerts -alias identity -file ServerCACert.der -keystore ServerTrust.jks -storepass ServerTrustStorePass


e) Configure the new keystores in WLS's identity and trust keystore

To configure the keystores in WLS enter the WLS console, select the managed server you're interested in, then make the following changes under the following tabs:

Configuration tab -> General subtab

SSL Listed Port Enabled = checkbox
SSL Listen Port = 7102 (and different from the Listen Port)

Configuration tab -> Keystores subtab

Keystores = Custom Identity and Custom Trust
Custom Identity Keystore = \ServerIdentity.jks, such as c:\temp\ServerIdentity.jks
Custom Identity Keystore Type = jks
Custom Identity Keystore Passphrase = ServerCAKey
Confirm Custom Identity Keystore Passphrase = ServerCAKey

Custom Trust Keystore = \ServerTrust.jks, such as c:\temp\ServerTrust.jks
Custom Trust Keystore Type = jks
Custom Trust Keystore Passphrase = ServerTrustStorePass
Confirm Custom Trust Keystore Passphrase = ServerTrustStorePass

Configuration tab -> SSL subtab

Identify and Trust Locations = Keystores
Private key alias = identity
Private Key Passphrase = ServerCAKey
Confirm Private Key Passphrase = ServerCAKey

Then save.

After this restart your WLS server and you should see similar messages to the following in the WLS logs:
    


Alternatively is you see the following messages you have made a mistake in your configuration:
10/07/2009 4:08:30 PM WST>     
<10/07/2009 4:08:30 PM WST>
<10/07/2009 4:08:30 PM WST>


3) Modify the web service to use the Wssp1.2-2007-Https.xml WLS policy

This can be done in a number of ways in JDeveloper, the easiest of which for this blog post at least is just to insert the @Policy annotation into the JAX-WS endpoint as follows:

(Note if you're using earlier versions of JDeveloper or Eclipse, this mechanism wont work, you must manually add the policies to the WSDL).
package au.com.sagecomputing.ws;

import javax.jws.WebService;

import javax.xml.ws.BindingType;
import javax.xml.ws.soap.SOAPBinding;

import weblogic.jws.Policy;

@WebService(serviceName = "OneWaySSLService",
targetNamespace = "urn:OneWaySSLExample.wsdl",
portName = "OneWaySSLPortTypePort",
endpointInterface = "au.com.sagecomputing.ws.OneWaySSLPortType",
wsdlLocation = "/WEB-INF/wsdl/OneWaySSLExample.wsdl")
@BindingType(SOAPBinding.SOAP12HTTP_BINDING)
@Policy(uri = "policy:Wssp1.2-2007-Https.xml")
public class OneWaySSLPortTypeImpl {

public String oneWaySSLOperation(String part) {
return "Hello " + part;
}
}
4) Deploy the running web service to WLS

Within JDeveloper to deploy and run from the integrated WLS, it's simply a case of right clicking on the JAX-WS file and selecting Run.

If you click on the hyperlink provided in the log window, this will open the HTTP Analyzer. From the HTTP Analyzer you can open the WSDL at the top of the window:



































Note on deployment to WLS you can see that the Wssp1.2-2007-Https.xml policy has been added to the binding to enforce One-Way SSL, and in addition the service address now runs from HTTPS, not HTTP, on the now enabled SSL port.

5) Test the running web service via JDeveloper's HTTP Analyzer

JDeveloper out of the box includes HTTP Analyzer for testing your web services. It's particularly useful as you don't have to leave the confines of your IDE to test your web services.

In order to run the HTTP Analyzer with SSL'ed web service traffic, you need to make some changes to the configuration of JDeveloper. Selecting the Tools->Preferences menu option, followed by Https and Truststore Settings, you can configure the Client and Server keystores HTTP Analyzer needs to run with SSL.

If you followed my exact instructions on setting up a selfsigned CA into the WLS identity and trust keystores, you need to enter the following options in the Preferences Https and Trusting Settings page:

Client Trusted Certificate Keystore: c:\temp\ServerTrust.jks
Client Trusted Keystore Password: ServerTrustStorePass

Server Keystore: c:\temp\ServerIdentity.jks
Server Keystore Password: ServerCAKey
Server Private Key Password: ServerCAKey

When you run your web service you can access the HTTP Analyzer by clicking on the URL of your served web service in the JDev IDE log window, among other methods.


This presents the following HTTP Analyzer screens:


In the top of the screen you'll see the HTTP Analyzer has formed a dummy request for you to send out based on the web service's WSDL. In my example picture I've filled out the part field and pressed Send Request, of which you can see the reply from the web service on the right hand side.

At the bottom of the screen you can the individual request/responses that were generated in order to service the request.

6) Test the running web service via SoapUI

SoapUI is a popular web service testing tool. I wanted to show how to configure it here to show similar results to the HTTP Analyzer. The following steps were built with SoapUI v3.0.

a) Create a new Project via File -> New soapUI Project
b) In the New SoapUI Project dialog, enter a custom project name, then your WSDL, leave the rest of the fields as default.


c) In the Project list expand your new project to the last Request 1 node, and double click it.
d) This will open the Request 1 window, showing on the left handside the outgoing request payload, where you can modify the inputElement XML element with your name.
e) Pressing the green arrow executes the request against the webservice, you'll now hopefully see the SOAP response on the right handside of the window.
f) Note at the bottom right of the right handside of the window you have the text SSL Info. Clicking on this shows another sub-window with the SSL certificate information that was swapped with the WLS server to undertake the SSL communications.


7) Test the running web service via a JAX-WS client

Assuming under JDeveloper you know how to create a Java Proxy for the deployed web service, you'll end up with the following code:
import clientexamples.SSLUtilities;

import javax.xml.ws.WebServiceRef;

public class OneWaySSLPortTypePortClient
{
@WebServiceRef
private static OneWaySSLService oneWaySSLService;

public static void main(String [] args)
{
oneWaySSLService = new OneWaySSLService();
OneWaySSLPortType oneWaySSLPortType = oneWaySSLService.getOneWaySSLPortTypePort();

SSLUtilities.trustAllHttpsCertificates();

System.out.println(oneWaySSLPortType.oneWaySSLOperation("Chris"));
}
}
Note SSLUtilities is a handy class written by Srgjan Srepfler that includes a number of methods for handling and modifying the default SSL behaviour. In our case in writing a simple test client we're not overly concerned about trusting the server's CA, so we can use SSUtilities.trustAllHttpsCertificates to stop the required checking.

8) Inspect the web service packets on the wire to verify the traffic is indeed encrypted

What neither JDeveloper's HTTP Analyzer nor SoapUI can do is actually confirm for you that the traffic on the network was actually encrypted. To check this we can use a wire sniffing tool called WireShark.

Warning: at some sites using wire sniffing tools like WireShark can be a dismissible offence because you can see private data on the network. Be careful to check your organisation policies before doing this.

Note if you're running the JAX-WS web services via the integrated WLS on the same localhost as SoapUI, you're most likely running through the localhost address. For various technical reasons WireShark cannot sniff packets through localhost or the MS loopback adapter in Windows. Instead we must separate our WLS and SoapUI installations, and place them on different hosts. Let's call them Box1 and Box2, with WLS and SoapUI installed respectively

Once you have both up and running, determine the IP address of Box2. Let's say that IP address was: 101.102.103.104

a) Start WireShark. In the filter box top left enter: ip.addr == 101.102.103.104
b) Select the filter Apply button.
c) Select the Capture -> Interfaces
d) Select the Start button for your ethernet card
e) WireShark is now sitting listening for traffic from the other ip.address of Box2.

f) Now in SoapUI execute the request.
g)In WireShark you should see the incoming requests:


As WireShark works at the network level it sees the individual packets, several of which will comprise the request/response between SoapUI and WLS, effectively an incredible amount of detail. You can select each packet and look at the data contained within in the bottom window of the display. This window shows the data in both hex and raw text, so you'll need to carefully look to see the data contained within. Obviously if the traffic is encrypted you wont see much meaning at all which is what we want! To see the unencrypted traffic, remove the policy from your web service, redeploy it and run the same scenario again.

Thanks

I must aim my very strong thanks to Gerard Davison from Oracle UK with assistance with this article, Gerard's help has been invaluable. Any mistakes in this post are of course mine however, of which I'm sure there will be a few in such a long post.

Tuesday 11 August 2009

JDev/ADF – the importance of getting PS_TXN and PS_TXN_SEQ correct

This is a revisit post about two important database objects for ADF, the database objects PS_TXN and PS_TXN_SEQ. The table and sequence are used by ADF to serialize user session state to the database. An old Oracle OTN whitepaper gives the low-down on these 2 objects.

Without these database objects your application can't scale effectively to multiple users, you'll see some bizarre and wonderful behaviour as ADF chokes on not having the ability to serialize to the database objects. However it's not an ADF problem, the manuals clearly state that you need to grant specific privileges to the database user or create the database objects beforehand.

I know now of 2 projects where serious problems occurred because the database wasn't configured correctly to accept the objects, and found another blog post detailing the same issue.

Pascal Alma's blog post can be found here.

In the 1st project, the developers overlooked giving privileges to the ADF database user schema to create the table and sequence, and didn't undertake load/stress tests to see how the application performed with more than one user. As soon as the application hit production with multiple users, ADF attempted to serialize to the database objects, and the system started hitting a huge array of issues. The worst bit was some of the errors were real red herrings making the problem hard to diagnose. However after much time with Oracle Support assistance the problem was solved. This destroyed the developers' faith in ADF and the users' faith in the developers and new ADF system.

The 2nd project is one I'm involved in currently. We were creating new database schemas for the ADF user and for some reason we didn't grant the create sequence privilege, but did grant the create table priv. Luckily I stress tested the app and found the problem fairly early on (with Steve Muench's kind help). However it did take a full 8 hours to debug, so I thought worth documenting here to help others.

What I'd thought I document is what errors you'll see in the WLS logs for JDev 11g build 5188 and JDev 11gR1 build 5407. I don't have an earlier version of JDev to test what happens but Pascal's blog post from above may assist.

Under JDev 11g build 5188 you'll see the following WLS log entries:

First it'll throw errors that it can't retrieve user session state:
SEVERE: Could not find saved view state for token -505abe38
11/08/2009 14:29:29 org.apache.myfaces.trinidadinternal.application.StateManagerImpl restoreView
SEVERE: Could not find saved view state for token -505abe38
11/08/2009 14:29:29 org.apache.myfaces.trinidadinternal.application.StateManagerImpl restoreView
SEVERE: Could not find saved view state for token -505abe38
11/08/2009 14:29:29 org.apache.myfaces.trinidadinternal.application.StateManagerImpl restoreView
At a later point in the logs you'll see exceptions thrown, but they're not very meaningful:
WARNING: ADFc: Error while opening JDBC connection.
oracle.jbo.DMLException: JBO-26061: Error while opening JDBC connection.
at oracle.jbo.server.ConnectionPool.createConnection(ConnectionPool.java:253)
at oracle.jbo.server.ConnectionPool.instantiateResource(ConnectionPool.java:168)
at oracle.jbo.pool.ResourcePool.createResource(ResourcePool.java:546)
at oracle.jbo.pool.ResourcePool.useResource(ResourcePool.java:327)
Further in the logs you may see the following TNS Listener issue (though this may just be particular to my Oracle XE setup):
Caused by: java.sql.SQLException: Listener refused the connection with the following error:
ORA-12519, TNS:no appropriate service handler found
The Connection descriptor used by the client was:
localhost:1521:xe
at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70)
at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:116)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:177)
And you may see NullPointerExceptions dependent on what ADF was attempting to do with the database connection at the time:
Caused by: java.lang.NullPointerException
at oracle.adf.model.binding.DCIteratorBinding.initSourceRSI(DCIteratorBinding.java:1735)
at oracle.adf.model.binding.DCIteratorBinding.callInitSourceRSI(DCIteratorBinding.java:1625)
... 75 more
Under JDev 11gR1 build 5407 gives you a more meaningful error message:

Again, first you'll see errors that it can't retrieve user session state:
SEVERE: Could not find saved view state for token -ce0efchp5
11/08/2009 2:35:31 PM org.apache.myfaces.trinidadinternal.application.StateManagerImpl restoreView
SEVERE: Could not find saved view state for token -ce0efchp7
11/08/2009 2:35:31 PM org.apache.myfaces.trinidadinternal.application.StateManagerImpl restoreView
SEVERE: Could not find saved view state for token -ce0efchp7
11/08/2009 2:35:31 PM org.apache.myfaces.trinidadinternal.application.StateManagerImpl restoreView
But then you'll see a much more meaningful message that ADF can't create the required objects:
oracle.jbo.PCollException: JBO-28006: Could not create persistence table PS_TXN_seq
at oracle.jbo.PCollException.throwException(PCollException.java:36)
at oracle.jbo.pcoll.OraclePersistManager.createTable(OraclePersistManager.java:908)
at oracle.jbo.pcoll.OraclePersistManager.queryNextCollectionId(OraclePersistManager.java:1444)
And further down:
Caused by: java.sql.SQLSyntaxErrorException: ORA-01031: insufficient privileges
at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:91)
at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:133)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:206)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:455)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:413)
Hopefully in Googling these error messages and landing on this page, you'll be able to work out how to correctly configure the database objects to avoid these issues.

Friday 7 August 2009

SoapUI for web service testing

A popular tool for web service testing is SoapUI. The following blog post describes how to use it for testing a simple web service, as well as setting up a series of tests and even load/stress testing. Without a doubt similar documentation is available on the SoapUI website; my post gives my spin on the product that maybe useful to others.

In this post we'll look at:

1) A simple web service example
2) Creating a simple test in SoapUI
3) Creating a test suite
4) Loast/stress testing your web services

Our web service

The web service we'll use here for testing is a simple Hello World example. It is comprised of the following solutions:

HelloWorldExample.xsd

xmlns="http://www.sagecomputing.com.au"
targetNamespace="http://www.sagecomputing.com.au" elementFormDefault="qualified">


The inputElement and the outputElement will constitute the incoming and outgoing payloads of a simple HelloWorld web service.

HelloWorldExample.wsdl

xmlns:tns="urn: HelloWorldExample.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:wsca="http://www.sagecomputing.com.au">


































Finally the web service is served at the following address:

http://www.sagecomputing.com.au:7101/SoapUIWebServiceExample /HelloWorldPortTypePort

...and the WSDL at this location...

http://www.sagecomputing.com.au:7101/SoapUIWebServiceExample /HelloWorldPortTypePort?WSDL

Starting SoapUI 3.0

On starting SoapUI 3.0 you'll see this screen:


Note in the left navigator the Projects node.

Creating your first web service test

We want to test the web service we recently created. To do follow these steps:

Right click on the Projects node and select New soapUI Project from the context menu. This will display the New soapUI Project dialog.

We'll enter an arbitrary Project Name. For the Initial WSDL/WADL we enter the complete URL of our web service's WSDL:


Leave the default check boxes, where Create Requests is checked, and the rest unchecked.

On completing the dialog the navigator will now look as follows:


Note how SoapUI has created the project, a node to represent the WSDL binding, a node to represent the WSDL operations (one in this case), and a dummy request.

If you double click on the request, this shows where SoapUI begins to sing:


The new window shows a potential request to send to your web service. You'll note thanks to the WSDLs and XSDs defined within the web service, SoapUI has automatically created a dummy payload with the required XML structure. We could overtype the inputElement's value, and then press the green arrow button to send the request to the web service, seeing this result:


The beauty of SoapUI is its taken care of virtually everything but the actual data values for you. Network communications, formation of the SOAP payloads, and even validating the XML structures. For the developer this is a boon as you can test one of your web services to see what's happening without writing any client side code.

Creating a test suite

The previous steps were good for one of adlibbed tests on our web service, but what if you wanted to create a series of tests, replay them, and add assertions based around the results? SoapUI offers the Test Suite.

In the navigator right click the dummy request (Request 1) and select Add to Test Case. In the Create Test Suite dialog, and the Create Test Case dialog, accept the default names. In the Add Request to Test Case dialog accept the defaults as following:


On accepting the dialog you'll have the following structure in the navigator and a new window for the Test Suite:


From the navigator you can guess that from the Test Suite you can create a number of Test Cases, with a sequenced set of Step Tests made up of requests. In our example the request has been copied from our previous dummy request:


Also unlike our original dummy request, with the test request open, looking at the bottom of the window we have an Assertions option, of which when we click on it (the word Assertion) we see the following:


An Assertion is a test to run against the web service response to ensure we get the result we require. The current Assertion SOAP Response – UNKNOWN is simply saying we should get a valid SOAP response. We could alternative add another Assertion to ensure the result is not a SOAP Fault by selecting the Add button then the "Not a SOAP Fault" option:


Once we've set up our tests and assertions, we want to run them. We return to the test case in the project navigator, open it and select the green arrow button to run the complete test suite. Assuming all things go well, we should see the following result:


If one of our assertions on our test case fails we'll see the following result:


Load/stress testing your web services

While running a test suite of tests can prove your web services are functionally correct, they don't tell you:

a) What's the maximum transactions per second (ie. load testing)
b) Does your program fail under multiple requests (ie. stress testing)

Load and stress testing are an integral part of ensuring your application will work on hitting productions.

Strictly speaking load and stress testing are proving different things, but for the remainder of this post I'll assume they're one and the same as they use the same facilities in SoapUI.

You'll have noted in the project navigator under the Test Suite an additional node Load Tests was created:


Right clicking on the Load Tests node, select New Load Test, accepting the default name in the New Load Test dialog, you'll see the Load Test window:


The easiest thing to do to understand this screen is just hit the green arrow. So what's happening?:


In the above picture you can see that the web service is being called multiple times. The process bar tells you the percentage completeness of the tests. The Limit field is the number of seconds the test will run for. The Threads is the number of threads (essentially simulated users) that SoapUI will spawn to send requests to the web service. Finally the Test Delay is the milliseconds between each response and next requests.

On completion of the test you'll see the collated statistics in the table:


Different figures are useful in assessing the performance of your web services, including:

Min and max shows you how fast and how slow your web service could process a request and send a response. Typically your worst time is on startup as the server initializes the web services.

Tps – the average transactions per second, which gives you a rough idea of the concurrent sessions you can support (remembering that at startup you will service less, but once the server is initialized generally you can support more)

Err – number of errors detected such as SOAP Faults.

Now an average of 6.71 transaction per second doesn't look that healthy. In this case it's SoapUI that's throttling your web services as the number of threads and the delay between requests means your web services can't fly, they're just not receiving enough work to do. If we change the numbers, increasing the threads, and reducing the delay as per the following screen shot we see we can really put our servers under some pressure:


(Nice bit about this screenshot is we're using an Oracle WebLogic Server behind the scenes, a fairly expensive server all round, but it certainly cranks along with this simplistic test case).