Thursday, April 10, 2014

Host a Soap Web Service on Google App Engine with JAX-WS

We are about to release a great addon for JDeveloper that can access a SOAP web service. For demonstration purposes we want to have a publicly available web service that anyone can use. Having this web service hosted on Google App Engine has two major benefits: it is free and is accessible for anyone on the internet 24x7.

We wanted to implement a simple Java (JAX-WS) webservice on Google App Engine, but unfortunately this is not fully supported. All the javax.xml.* classes are available on Google App Engine, but not the com.sun.xml.ws.* classes that are normally used to implement a JAX-WS service. But with a little bit of custom code we can get a JAX-WS service to run on Google App Engine as can be seen in the SoapUI screenshot. You can download the public WSDL at https://redheap-jaxws.appspot.com/HelloWorldService.wsdl
SoapUI test invoking HelloWorld service on Google App Engine

You can use the normal JAX-WS annotations in your service class and use JAXB to marshal and unmarshal the request and responses. This is all very similar to a JAX-WS service on a JEE container. The thing you need extra is a custom HttpServlet that handles the HTTP POST, unmarshals the request payload to a java object using JAXB, invoke the actual web service class, marshal the web service class response back to XML and send it to the client.

This post describes all the steps to create a project using maven and complete it in JDeveloper 12c as well as deploying it to a local and remote server. If you prefer other build tools, like Apache ANT, or other Java IDE's you can still use similar steps but you might need to adjust them for your environment. The key part is the custom servlet which is the same for each setup.

Monday, March 31, 2014

Managed Bean changes should mark their ADF Scope dirty in a HA cluster

We're starting development on a new ADF application and the plan is to run this in a high-available weblogic cluster. The documentation clearly states it is the responsibility of the developer to make ADF aware of any changes to managed beans in an ADF scope with a lifespan longer than one request. This means it is up to you to notify ADF of each change in a viewScope or pageFlowScope bean with the following code:
Map viewScope = ADFContext.getCurrent().getViewScope();
ControllerContext.getInstance().markScopeDirty(viewScope);

That's not too difficult but it's a matter of time before a developer forgets about this. That would mean the ADF scope is not marked dirty and the changed managed bean is not replicated to the other nodes in the cluster. We wanted to implement a check (at least during development) that developers do not forget about this. JSF PhaseListener to the rescue!

Full source code is at the end of this posting, but I'll explain the vital parts first. We've create a JSF PhaseListener that listens to each JSF phase transition:
public PhaseId getPhaseId() {
    return PhaseId.ANY_PHASE;
}

In the beforePhase method for the RESTORE_VIEW phase we retrieve the viewScope and pageFlowScope maps. Next, we serialize these and calculate a MD5 hash. These hashes are store in the requestScope

In the afterPhase method for the RENDER_RESPONSE phase we calculate the same MD5 digests and compare these with the ones stored at the beginning of the request. We know we're in trouble when the digests changed and the developer has not invoked ControllerContext.markScopeDirty. When this happens we simple log an exception to the console without actually throwing it. This is more of a development/debugging tool and shouldn't actually abort JSF processing as that would also cancel any other PhaseListeners. We don't want to make things worse.

You probably want this enabled during development all the time. However, there is a performance overhead in serializing the viewScope and pageFlowScope twice per request and calculating a MD5 digest. It might be a good idea to disable this in production. That's why we opted to use the ADF logging framework for this. First, you can set the log levels that will be used for the output through web.xml context-parameters. By default, these are set to WARNING to ensure all logging is enabled in a default development environment. In production you want to use deployment plans to override this to something like FINE or FINEST. Once you know the logging level that is being used, you can even enable/disable these checks in a deployed application by tweaking the log levels of your weblogic container. The JSF PhaseListener is smart enough to not even perform the serialization and digest calculation of logging levels are setup so that logging doesn't occur. This means you could even leave the loggers in there for production so you could still enable them when cluster replication issues occur.

The demo workspace includes a singe page application to demonstrate the DirtyScopePhaseListener. Simply run that page and press the button marked "change viewState without marking dirty". This will log an error in the console that neatly explains the internal state of myViewScopeBean in the ADF viewScope was changed:

Hopefully this JSF PhaseListener can be a valuable tool for anyone building a ADF application intended to run on a session-replicating cluster.

As always you can download the full sample application or browse the subversion repository to look at the source code. If you want to have a quick look at the solution start with the com.redheap.dirtyscope.DirtyScopePhaseListener phase listener and the com.redheap.dirtyscope.ADFScopeChecker class that does all the digest calculating and checking.

Update: The sample code is broken. It only looks at the pageFlowScope and viewScope of the unbounded taskflow and does not consider any state in bounded taskflows and viewScopes running in regions. I am working on an improved version and will post a new blog entry once that is finished.

Monday, February 24, 2014

ADFLogger JAX-WS SoapHandler to log request, reponse and faults

Lately I see a lot of ADF projects consuming SOAP web services. This is typically done by creating a JAX-WS Proxy in JDeveloper and invoking this proxy from java beans exposed through the Bean Data Control or through programmatic ADF Business Components. This post will show how to instrument your JAX-WS proxy so it can log the SOAP request, payload and potential fault to an ADFLogger. This can be a very valuable tool during development and when diagnosing production issues.

Let's start with the final result, the weblogic console when invoking a web service that returns a soap fault. The nice thing is that it not only logs the fault but also the request that caused it:
SOAP request and response logged when receiving SOAP fault
When you crank up the log level you can even see all requests and responses that complete successful. As I described earlier this also allows for performance analysis with the Log Analyzer. This breaks down your entire request and our LoggingSoapHandler times the milliseconds it took to invoke the web service.
Log Analyzer showing this web service call took 5 msecs
This magic is performed by a JAX-WS SoapHandler. It can be registered with a JAX-WS proxy and has access to the web service request and response messages. Handlers can even change these, but in this example all we do is logging to the ADFLogger. You can setup handlers when creating the web service proxy or by right clicking an existing one and changing its properties.
Add LoggingSoapHandler as a Handler on the JAX-WS Proxy
You can get the full source code for the com.redheap.soaplog.LoggingSoapHandler class so you can add it to your own project or library. The embedded documentation is rather elaborate but I'll also explain the most important bits here.

Friday, January 3, 2014

Configuring ADF Faces for development

This post will describe how to configure your ADF Faces project for development through web.xml context parameters as well as enabling debug mode in trinidad-config.xml. It will also show how to override these settings for production deployment with a deployment plan even though the setting in trinidad-config.xml cannot be altered directly with a deployment plan.

More background information on all ADF Faces configuration parameters can be found in the appendix of the Web User Interface Developer's Guide. The ones we want to change during development are:
  • org.apache.myfaces.trinidad.CHECK_FILE_MODIFICATION to true to check for source files being modified on disk while the application is running and reloading them. Be sure to clear your browser cache after changing this value to clear out any old cached versions.
  • org.apache.myfaces.trinidad.resource.DEBUG to true to enable resource debugging and prevent the client from caching resources (eg javascript libraries, images, CSS, etc)
  • org.apache.myfaces.trinidad.DISABLE_CONTENT_COMPRESSION to true to disable CSS content compression and use human-readable CSS class names for skinning
  • org.apache.myfaces.trinidad.DEBUG_JAVASCRIPT to true to non-obfuscated javascript
  • oracle.adf.view.rich.LOGGER_LEVEL to FINE to enable client side javascript logging. Other allowed values are SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, and ALL
  • oracle.adf.view.rich.ASSERT_ENABLED to true to enable client-side javascript assertions