@Singleton bean failed to initialize because of not expected transaction status 4 when it's marked TransactionAttribute=NOT_SUPPORTED

StackOverflow https://stackoverflow.com/questions/17112959

Question

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:

  1. Firstly, my MyClass#init is being executed completely and successfully without any issues/ exceptions.
  2. The #init is being called on first call to my #doSomething method from client code (as part of post-construct).
  3. 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.

Was it helpful?

Solution

N.B. This was not originally an answer but just some more useful info in digging in to find answers to such problems as there really isn't much on-line in this area. After some additional effort, the cause and an answer have since been found. The answer has been left in its original format with new findings documented as edits and debug help left in-tact to hopefully ease the debugging of others with similar issues. This is a dark place.

Well, still no firm answer to the above issue and the problem seems to have gone away.

I have found though (looking at a different NoSuchEJBException issue) that the underlying cause is swallowed by the WLS stack.

This is the sensible place to start looking for SingletonBean failed to init NosuchEJBException issues in cases where you don't make it into your PostConstruct method (i.e. your bean could not be created):

SingletonSessionManager$SingletonLifecycleManager.doActualInit() line: 819   
SingletonSessionManager$SingletonLifecycleManager.initInternal(boolean) line: 744     
SingletonSessionManager$SingletonLifecycleManager.getBean() line: 648           
SingletonSessionManager.getBeanFor(InvocationWrapper) line: 285      

Initially, root exceptions are caught and included into the NoSuchEJBExceptions raised in the lower levels, as above. However, at the point in the stack below, the NoSuchEJBException is replaced with an InternalError that gets wrapped and the cause(s) lost. Curiously, it may even set itself as the cause (debugger goes a bit haywire):

SingletonSessionManager#getBeanFor

So, this is a prime place for finding what the root exception may be.

FYI: My problem in the second instance was a spring-injection issue within WLS (spring-repackaged) where a datasource wasn't beig properly injected into my ELB service impl as the datasource didn't exist with the @Resource(name="...") JNDI name. This wasn't logged at all due to the aforementioned exception-handling issue. Once I'd stepped through and found the cause, it was an easy fix. Shame to have to spend so much time finding it out.

[EDIT] FYI: It seems my problem causing the "InternalException Transaction Rolled-back status 4" exception may have been due to the EJB init (PostConstruct) exceeding the transaction timeout. This should be irrelevant if my EJB is set as @TransactionAttribute(NOT-SUPPORTED) but apparently not so. Debugging revealed that for this and @TransactionAttribute(NEVER), there is an invokeTx used at the level of the SingletonSessionManager#constructAndInitBean and managed within the InvocationWrapper. So, the timeout would cause the rollback, leading to the InternalException, mapped to the NoSuchEJBException, swallowed by the other NoSuchEJBException leading to a rubbish error message.

[EDIT2] FYI: It seems this is due to a bug in WLS where the invokeTx is set and managed when it shouldn't be for @TransactionAttribute(NOT-SUPPORTED). We've raised a bug with Oracle who have given it a sev 2. In the meantime, we've moved potentially time-consuming (network-dependent) code out of the @PostConstruct method as a workaround.

[EDIT3] FYI: From Oracle ... The class level transaction attribute annotation is not enforced on singleton lifecycle interceptors postconstrcut/predestroy, so it defaults to REQUIRED.

They concur that this is an issue and are looking into it. In the meantime, ensure transaction timeouts aren't breached by code within your @PostConstruct. This would include latency-based timeouts (our issue was intermittent as it depended on which geographical "server" was accessed).

Debugging tips

As a debugging process, btw, I suppose I would:

  1. Put a breakpoint in your EJB init (@PostConstruct) method and unwind until you see the exception occur in your debug values.
  2. If you don't hit your init, put breakpoints as close as possible to the WLS #doActualInit listed above and find your way into the init methods. then, just watch for when the exception is first raised. Note, you may have to put your breakpoint inside InvocationHandler#invoke to get near this through the proxy layers (or roll your own).
  3. If you do hit it, watch the unwinding stack by putting a breakpoint in your init and unwinding or in EjbComponentCreatorImpl.invokePostConstruct(Object, String) and watching.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top