I'm having difficulty with my EJB3.1 bean initialisation and more specifically to do with it failing due to perceived transaction rollback, even though I've marked the bean with @TransactionAttribute(NOT_SUPPORTED)
. This should mean that any client transaction is paused on bean method entry until exit (when it will be resumed. It's definitely the transactional apprach I want.
The "gist" of the code and error are as follows (note some of it is hand-cranked to hide details but is all relevant and representative):
@Singleton(name = "MyClass")
@ConcurrencyManagement(value = BEAN)
@TransactionAttribute(value = NOT_SUPPORTED)
@Local(MyInterface.class)
public class MyClass implements MyInterface {
@PostConstruct
public void init() throws MyException {
try {
...
} catch LowerLevelException e) {
throw new MyException("problem", e);
}
}
public Object doSomething(...) throws MyException {
...
}
...
}
This raises the following error:
javax.ejb.NoSuchEJBException: Singleton MyClass(Application: my-ear, EJBComponent: my-ejb.jar) failed to initialize.
which, when I debug is actually wrapping the following exception:
weblogic.ejb.container.InternalException: Transaction marked rollback or not expected transaction status: 4
Again, debugging raises some interesting details:
- Firstly, my
MyClass#init
is being executed completely and successfully without any issues/ exceptions. - The
#init
is being called on first call to my#doSomething
method from client code (as part of post-construct). - So, there are reams of levels of stack-indirection between the client-call to
MyClass#doSomething
down to#init
and the exception is raised inside of one of these layers. It's raised in WLS Singleton session bean management code. See below...
The stack resembles that below (MyClass names changed):
MyClass_fefgu8_Impl(MyClass).init() line: 96
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43
Method.invoke(Object, Object...) line: 601
Jsr250Metadata.invokeLifecycleMethod(Object, Method, Object[]) line: 393
InterceptionMetadata(Jsr250Metadata).invokeLifecycleMethods(Object, LifecycleEvent) line: 365
InterceptionMetadata.invokeLifecycleMethods(Object, LifecycleEvent) line: 403
EjbComponentCreatorImpl.invokePostConstruct(Object, String) line: 80
SingletonSessionManager.constructAndInitBean() line: 369
SingletonSessionManager.access$300(SingletonSessionManager) line: 63
SingletonSessionManager$SingletonLifecycleManager.doActualInit() line: 798 <== InternalException raised here
SingletonSessionManager$SingletonLifecycleManager.initInternal(boolean) line: 744
SingletonSessionManager$SingletonLifecycleManager.getBean() line: 648
SingletonSessionManager.getBeanFor(InvocationWrapper) line: 285
SingletonSessionManager.preInvoke(InvocationWrapper) line: 147
SingletonLocalObject(BaseLocalObject).getBeanInstance(InvocationWrapper) line: 146
SingletonLocalObject(BaseLocalObject).preInvoke(InvocationWrapper, ContextHandler, boolean, boolean) line: 103
SingletonLocalObject(BaseLocalObject).__WL_preInvoke(InvocationWrapper, ContextHandler) line: 67
SessionLocalMethodInvoker.invoke(Invokable, BaseLocalObject, InvocationWrapper, Object[], int) line: 20
MyClass_fefgu8_MyInterfaceImpl.doSomething(String, String, String, String) line: not available
And the Transaction rollback exception is actually raised in stack-frame:
SingletonSessionManager$SingletonLifecycleManager.doActualInit() line: 798
This level does have dealing with a transaction manager but I've no idea why it should be trying to mark a transaction for rollback, especially after a successful init from the main application code.
I'm using this EJB component to compile this bean but we use WLS EJB code on the server (or course):
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.ejb</artifactId>
<version>3.1</version>
<scope>provided</scope>
</dependency>
The reason I've put this out there is that it's proving tricky, there's precious little on-line (especially with transaction status 4), I've spent a bit too long on it and need to move on. I'm carrying on looking but I thought I might get more leads for when I'm back on Monday.
I've re-read a lot around EJB transaction handling and don't see any obvious issues. I believe I'm using the correct mechanism for handling the transaction in my bean (i.e. it's non-transactional). I've not yet tried putting it in the descriptor instead (which I just thought of and will give a go). I've also not yet delved deeply into howSingletonSessionManager$SingletonLifecycleManager.doActualInit
works but there's not a lot on-line about it.
The question
To rephrase, the question is... - What am I missing so that my bean methods are not participating in any supplied transaction, or more specifically, not trying to mark a transaction for rollback? - Why should it fail to initialise with this error if I've explicitly told it not to "support" (care about) any transactions?
N.B. I've checked this @Singleton bean failed to initialize because of not expected transaction status 1 issue but my scenario doesn't relate to Java EE security role permissions (I don't think!)
Thanks.
Update 1
Well, the latest is that removing my @TransactionAttribute
annotation seems to get me past the failure. This is strange though as the default should be TransactionAttributeType#Required and indeed, we have an additional layer in the stack trace and if I debug too long then I get a transaction timeout in my bean init.
Looking at the following level in the stack-trace (slowly nexting out), I see that there is a transaction (well, two, actually):
SingletonSessionManager.constructAndInitBean() line: 377
wrap weblogic.ejb.container.internal.InvocationWrapper (id=15676)
L callerTx weblogic.transaction.internal.ServerTransactionImpl (id=15681)
L invokeTx weblogic.transaction.internal.ServerTransactionImpl (id=15683)
I'll check if these were present in the pre-remove @TransactionAttribute
scenario and also try and watch ServerTransactionImpl
.
Update 2
Last update for a while... However, I think I've traced the issue into SingletonSessionManager#postCallback
which is called from SingletonSessionManager#constructAndInitBean
in the original stack-trace above. (I'd need to confirm this though as my lead is determined by running through the transactional case). Will report back if/ when but it seems we may have a failure trying to rollback our non-existent transaction in here.