by admin
I was working on a problem, where the JPA provider of WebLogic 11g (EclipseLink) was being destroyed when an OptimisticLockException being thrown by EclipseLink was being wrapped in a MessageException to be thrown by LiveCycle Data Services (or BlazeDS).
After some investigation and debugging the MessageException.cause property, which is set through Throwable.initCause(), showed the following object graph. As detailed below, when using EclipseLink, it has it’s own OptimisticLockException, which is then wrapped by the JPA version and thrown:
- MessageException (id=104)
- cause EJBException (id=124)
- cause javax.persistence.OptimisticLockException (id=130)
- cause org.eclipse.persistence.exceptions.OptimisticLockException (id=137)
Cause and Effect
When this MessageException is thrown by the MessageBroker, it travels up the stack and eventually gets serialized to be transferred across to the Flex client. Somewhere in this serialization, the JPA session seems to get destroyed and any subsequent requests to the server from the client get the following error in the FaultEvent to the Flex client:
- javax.ejb.EJBTransactionRolledbackException : EJB Exception: ; nested exception is: java.lang.NullPointerException; nested exception is: java.lang.NullPointerException
Looking at the stack trace of the server logs, it gives a rather strange error, of which I couldn’t find out much about through our friend Google:
- java.lang.NullPointerException at org.eclipse.persistence.internal.sessions.AbstractRecord.get(AbstractRecord.java:270)
Reasoning and Proof
I was able to, first, isolate the error from the BlazeDS application I was using into a simple servlet, simply by updating a Managed Entity twice in some Java without refreshing from the database. When I got an OptimisticLockException in the Java, I used the Narkisr technique to perform serialization on the OptimisticLockException thrown, and lo and behold, the JPA session appeared to be destroyed, and the whole application rendered unusable until a server restart.
So far, this showed me a few things:
- When the application was in a “ruined” state, it seemed to have an open JPA session or such like that then locked any other requests/transactions from the client
- It wasn’t BlazeDS or LCDS per se that is the problem, but in the serialization of EclipseLink OptimisticLockException to AMF that caused the problem.
- Since it is BlazeDS code that is doing the serialization, then I could head on over to the BlazeDS repository for it and download the code for it!
Solutions and Dilutions
So that’s how I got to the title of the post, how to control serialization of Java Objects in LCDS or BlazeDS. There are a few posts out there on the wild web that show how to do this, and I am borrowing heavily from them but it makes sense for me to show one of my solutions (yes, there was another
) in the context of this post.
From debugging the exception, I could see the full Object graph in Eclipse. Whilst I knew we wanted to throw the javax.persistence.OptimisticLock exception across, as well as the EJBException from the bean that was throwing the error, I also knew that if we serialized the org.eclipse.persistence.exceptions.OptimisticLockException then we would then get the application into a state that we were unable to recover from, other than restarting the server, not a good solution.
The bits of the puzzle that needed to be brought together to investigate and find a way to tell the Data Service not to serialize the org.eclipse.persistence.exceptions.OptimisticLockException are:
As always, someone has always said it better than me, and none more so than
Peter Farland over on this
Adobe.com forum post in response to some questions. I’m posting it here for context (it contains some extraneous info to this blog post about cloning, but still gold info):
PropertyProxy’s play two roles – the first is to control how EVERY instance of a complex type should be described for serialization, the second is to control how just this ONE instance of a complex type should be described for serialization.
The PropertyProxyRegistry simply maps a type (class or interface) to an instance of some PropertyProxy implementation. This serves as a reusable “template” that can be used for EVERY instance of a complex type as they pass through the serializer. (This avoids the wasteful creation of new PropertyProxy’s just to introspect an instance of a complex type).
However, perhaps you have a special requirement for just ONE instance of your complex type. In this scenario you look up the appropriate PropertyProxy for the complex type – but you need to make some specific adjustment say, excluding some property but just this once, for your value. In this scenario the PropertyProxy acts as a wrapper and the value serves as the default instance of the PropertyProxy. The serializer will see the value is wrapped in a PropertyProxy and will not consult the PropertyProxyRegistry.
Now, the problem is that you don’t want to modify the template PropertyProxy instance in the registry as that would impact EVERY other instance. So, you can clone the PropertyProxy for your ONE instance and make the adjustment.
If you didn’t care about the state of the template PropertyProxy in the registry, you could also simply construct your own PropertyProxy instance and use that to wrap your value.
Since the template PropertyProxy instances are shared across threads, then they should not be modified in an unsafe manner. Generally, however, it’s not a concern as template PropertyProxy instances are not modified after construction and the value to be introspected is passed in as an argument to the utility methods (rather than being part of the PropertyProxy state).
So the simple solution in in the first instance, was to create a PropertyProxy for the javax.persistence.OptimisticLockException, and make sure that it did not serialize the cause property (look up remember the object graph!).
I then used the technique to eliminate the whole org.eclipse.persistence.exceptions.OptimisticLockException from the serialization process, but through trial and error, I later found that it was specifically serialization of the session property and the query property of the exception. I then scoured by eyeball to check for any other appearances of these properties to guard against serialization of them into AMF.
So, my final three bits of code ended up looking like the following:
EclipseLinkExceptionsProxy.java
package com.adobe.trt.lcds;
import flex.messaging.io.BeanProxy;
public class EclipseLinkExceptionsProxy extends BeanProxy {
private static final long serialVersionUID = 3809660049108090824L;
static
{
addIgnoreProperty(org.eclipse.persistence.exceptions.EclipseLinkException.class, “session”);
addIgnoreProperty(org.eclipse.persistence.exceptions.DatabaseException.class, “query”);
addIgnoreProperty(org.eclipse.persistence.exceptions.OptimisticLockException.class, “query”);
}
}
EclipseLinkExceptionsProxyBootstrapService.java
package com.adobe.trt.lcds;
import flex.messaging.config.ConfigMap;
import flex.messaging.io.PropertyProxyRegistry;
import flex.messaging.services.AbstractBootstrapService;
public class EclipseLinkExceptionsBootstrapService extends AbstractBootstrapService {
@Override
public void initialize(String id, ConfigMap properties) {
PropertyProxyRegistry registry = PropertyProxyRegistry.getRegistry();
registry.register(Object.class, new EclipseLinkExceptionsProxy());
}
@Override
public void start() {
//No-op
}
@Override
public void stop() {
//No-op
}
}
services-config.xml for the BootstrapService
<services>
<service-include file-path="remoting-config.xml" />
<service-include file-path="proxy-config.xml" />
<service-include file-path="messaging-config.xml" />
<service id="eclipselinkExceptionsProxyBootstrap" class="com.adobe.trt.lcds.EclipseLinkExceptionsProxyBootstrapService"/>
</services>
The application could then throw an OptimisticLockException and continue as expected.
Footnotes
This was only tested against the OptimisticLockException issue, but it is a good start into how to control the Serialization of your Java Objects in LCDS or BlazeDS. I would definitely recommend a good look about at all the classes that implement the PropertyProxy class, you can get a lot of good tips from how to do things in there.