Hot questions for Using Enterprise JavaBeans in tomee

Question:

I have 2 EJB @Singletons which are running in tomee

They are calling one another, and have a deadlock

@Startup
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class DeadlockReproducer {
    private final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB_STARTUP_CONFIG, this.getClass());

    @EJB
    private DeadlockReproducerAid deadlockReproducerAid;

    @PostConstruct
    public  void reproduce(){
        LOGGER.info("reproduce");
        deadlockReproducerAid.lockMe();
    }

    public void youCantGetMe(){
        LOGGER.info("youCantGetMe");
    }
}


@Startup
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class DeadlockReproducerAid {
    private final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB_STARTUP_CONFIG, this.getClass());

    @EJB
    DeadlockReproducer deadlockReproducer;

    public void lockMe(){
        LOGGER.info("lockMe");
        deadlockReproducer.youCantGetMe();
    }
}

I get a deadlock when youCantGetMe is waiting for reproduce to return.

Here is the stack trace:

"localhost-startStop-1" #68 daemon prio=5 os_prio=0 tid=0x0000000056d1f000 nid=0x14e0 waiting on condition [0x0000000058aab000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000fc7a2cc8> (a java.util.concurrent.FutureTask)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:429)
    at java.util.concurrent.FutureTask.get(FutureTask.java:191)
    at org.apache.openejb.core.singleton.SingletonInstanceManager.getInstance(SingletonInstanceManager.java:112)
    at org.apache.openejb.core.singleton.SingletonContainer.invoke(SingletonContainer.java:200)
    at org.apache.openejb.core.ivm.EjbObjectProxyHandler.synchronizedBusinessMethod(EjbObjectProxyHandler.java:308)
    at org.apache.openejb.core.ivm.EjbObjectProxyHandler.businessMethod(EjbObjectProxyHandler.java:303)
    at org.apache.openejb.core.ivm.EjbObjectProxyHandler._invoke(EjbObjectProxyHandler.java:92)
    at org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:308)
    at com.company.test.eu.logic.server.stateMachine.DeadlockReproducer$$LocalBeanProxy.youCantGetMe(com/company/test/eu/logic/server/stateMachine/DeadlockReproducer.java)
    at com.company.test.eu.logic.server.stateMachine.DeadlockReproducerAid.lockMe(DeadlockReproducerAid.java:31)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:192)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:173)
    at org.apache.openejb.monitoring.StatsInterceptor.record(StatsInterceptor.java:181)
    at org.apache.openejb.monitoring.StatsInterceptor.invoke(StatsInterceptor.java:100)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:192)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:173)
    at org.apache.openejb.core.interceptor.InterceptorStack.invoke(InterceptorStack.java:85)
    at org.apache.openejb.core.singleton.SingletonContainer._invoke(SingletonContainer.java:256)
    at org.apache.openejb.core.singleton.SingletonContainer.invoke(SingletonContainer.java:212)
    at org.apache.openejb.core.ivm.EjbObjectProxyHandler.synchronizedBusinessMethod(EjbObjectProxyHandler.java:308)
    at org.apache.openejb.core.ivm.EjbObjectProxyHandler.businessMethod(EjbObjectProxyHandler.java:303)
    at org.apache.openejb.core.ivm.EjbObjectProxyHandler._invoke(EjbObjectProxyHandler.java:92)
    at org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:308)
    at com.company.test.eu.logic.server.stateMachine.DeadlockReproducerAid$$LocalBeanProxy.lockMe(com/company/test/eu/logic/server/stateMachine/DeadlockReproducerAid.java)
    at com.company.test.eu.logic.server.stateMachine.DeadlockReproducer.reproduce(DeadlockReproducer.java:30)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:192)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext$LifecycleInvocation.invoke(ReflectionInvocationContext.java:223)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:173)
    at org.apache.openejb.monitoring.StatsInterceptor.record(StatsInterceptor.java:181)
    at org.apache.openejb.monitoring.StatsInterceptor.PostConstruct(StatsInterceptor.java:109)
    at sun.reflect.GeneratedMethodAccessor37.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:192)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:173)
    at org.apache.openejb.core.interceptor.InterceptorStack.invoke(InterceptorStack.java:85)
    at org.apache.openejb.BeanContext.newInstance(BeanContext.java:1590)
    at org.apache.openejb.core.singleton.SingletonInstanceManager.createInstance(SingletonInstanceManager.java:179)
    at org.apache.openejb.core.singleton.SingletonInstanceManager.access$100(SingletonInstanceManager.java:69)
    at org.apache.openejb.core.singleton.SingletonInstanceManager$1.call(SingletonInstanceManager.java:120)
    at org.apache.openejb.core.singleton.SingletonInstanceManager$1.call(SingletonInstanceManager.java:118)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at org.apache.openejb.core.singleton.SingletonInstanceManager.getInstance(SingletonInstanceManager.java:129)
    at org.apache.openejb.core.singleton.SingletonInstanceManager.initialize(SingletonInstanceManager.java:93)
    at org.apache.openejb.core.singleton.SingletonInstanceManager.start(SingletonInstanceManager.java:84)
    at org.apache.openejb.core.singleton.SingletonContainer.start(SingletonContainer.java:125)
    at org.apache.openejb.assembler.classic.Assembler.startEjbs(Assembler.java:1168)
    at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:807)
    at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:623)
    at org.apache.tomee.catalina.TomcatWebAppBuilder.startInternal(TomcatWebAppBuilder.java:1248)
    at org.apache.tomee.catalina.TomcatWebAppBuilder.configureStart(TomcatWebAppBuilder.java:1087)
    at org.apache.tomee.catalina.GlobalListenerSupport.lifecycleEvent(GlobalListenerSupport.java:130)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
    at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5378)
    - locked <0x00000000e1115938> (a org.apache.catalina.core.StandardContext)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    - locked <0x00000000e1115938> (a org.apache.catalina.core.StandardContext)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:649)
    at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1083)
    at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1880)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - <0x00000000fb344d08> (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync)
    - <0x00000000e0bca828> (a java.util.concurrent.ThreadPoolExecutor$Worker)

They are deadlocked when the public void reproduce() is called by @PostConstruct annotation.

When it is called by an another bean the youCantGetMe does return.

For example the following setup is working:

@Startup
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class DeadlockReproducer {
    private final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB_STARTUP_CONFIG, this.getClass());

    @EJB
    private DeadlockReproducerAid deadlockReproducerAid;

    //@PostConstruct - no postconstruct now
    public  void reproduce(){
        LOGGER.info("reproduce");
        deadlockReproducerAid.lockMe();
    }

    public void youCantGetMe(){
        LOGGER.info("youCantGetMe");
    }
}


@Startup
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class DeadlockReproducerAid {
    private final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB_STARTUP_CONFIG, this.getClass());

    @EJB
    DeadlockReproducer deadlockReproducer;

    public void lockMe(){
        LOGGER.info("lockMe");
        deadlockReproducer.youCantGetMe();
    }
}


@Startup
@Singleton
public class DeadlockInvoker {

    @EJB
    DeadlockReproducer deadlockReproducer;

    @PostConstruct
    public void startup(){
        deadlockReproducer.reproduce();
    }
}

Why can it be and how can I make it work without resorting to the trick with external invoker?

EDIT:

I am starting to figure out that this behavior has to do with Singleton lifecycle in EJB.

The singleton doesn't get to Ready state until @PostConstruct finished running, and probably when it's state is not Ready, it does not respond to external method calls.


Answer:

You need to mark that your first ejb requires the 2nd to start before it: https://docs.oracle.com/javaee/6/api/javax/ejb/DependsOn.html

Other than that I do not see any problems with the code, singletons use re-entrant locks so this should work.

Question:

We have two EJB beans that have the same name (say MyBean) but are in different packages (different sub modules), say com.example.module1 and com.example.module2 and they implement entirely different interfaces. Apache TomEE+ 1.7.2 recognizes only one of them randomly on each deploy and completely ignores the other one, not even a warning!

Tried changing openejb.deploymentId.format property in the conf/system.properties to the two below, but that didn't help.

openejb.deploymentId.format = {appId}/{ejbJarId}/{ejbName}

openejb.deploymentId.format = {appId}/{ejbJarId}/{ejbClass}

Anyone know how to fix this problem? Thanks much


Answer:

Have you tried setting a name for each?

@Stateless(name="MyBean1")
public class MyBean implements MyBeanLocal

or annotations

@Documented
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
public @interface TypeOne {

}

@Documented
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
public @interface TypeTwo {

}


@TypeOne
@Stateless
public class MyBean implements MyBeanLocal

@TypeTwo
@Stateless
public class MyBean implements MyBeanLocal

Question:

I have an EJB application that is currently deployed on TomEE 1.7.4 with OpenJDK 7 inside a docker container (openjdk 7, TomEE, and my war).

Note: The Jar files that I added within TomEE lib folder are reconized by the application, because I had some errors that has been solved after adding those Jar files.

The error log

INFO: PersistenceUnit(name=manager1, provider=org.hibernate.jpa.HibernatePersistenceProvider) - provider time 2214ms
Apr 25, 2018 5:35:21 PM org.apache.openejb.assembler.classic.Assembler destroyApplication
INFO: Undeploying app: /usr/local/tomee/webapps/myapp
Apr 25, 2018 5:35:21 PM org.apache.catalina.core.ContainerBase removeChild
SEVERE: ContainerBase.removeChild: destroy: 
org.apache.catalina.LifecycleException: An invalid Lifecycle transition was attempted ([before_destroy]) for component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/myapp]] in state [STARTING_PREP]
    at org.apache.catalina.util.LifecycleBase.invalidTransition(LifecycleBase.java:401)
    at org.apache.catalina.util.LifecycleBase.destroy(LifecycleBase.java:291)
    at org.apache.catalina.core.ContainerBase.removeChild(ContainerBase.java:1038)
    at org.apache.tomee.catalina.TomcatWebAppBuilder.undeploy(TomcatWebAppBuilder.java:1537)
    at org.apache.tomee.catalina.TomcatWebAppBuilder.undeploy(TomcatWebAppBuilder.java:1518)
    at org.apache.tomee.catalina.TomcatWebAppBuilder.undeployWebApps(TomcatWebAppBuilder.java:762)
    at org.apache.openejb.assembler.classic.Assembler.destroyApplication(Assembler.java:1982)
    at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:839)
    at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:677)
    at org.apache.tomee.catalina.TomcatWebAppBuilder.startInternal(TomcatWebAppBuilder.java:1261)
    at org.apache.tomee.catalina.TomcatWebAppBuilder.configureStart(TomcatWebAppBuilder.java:1100)
    at org.apache.tomee.catalina.GlobalListenerSupport.lifecycleEvent(GlobalListenerSupport.java:130)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
    at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5472)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:899)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:875)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
    at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1091)
    at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1980)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:473)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:622)
    at java.lang.Thread.run(Thread.java:748)

Apr 25, 2018 5:35:21 PM org.apache.tomee.catalina.TomcatWebAppBuilder startInternal
SEVERE: Unable to deploy collapsed ear in war StandardEngine[Catalina].StandardHost[localhost].StandardContext[/myapp]
org.apache.openejb.OpenEJBException: Creating application failed: /usr/local/tomee/webapps/myapp: javax.persistence.Table.indexes()[Ljavax/persistence/Index;
    at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:843)
    at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:677)
    at org.apache.tomee.catalina.TomcatWebAppBuilder.startInternal(TomcatWebAppBuilder.java:1261)
    at org.apache.tomee.catalina.TomcatWebAppBuilder.configureStart(TomcatWebAppBuilder.java:1100)
    at org.apache.tomee.catalina.GlobalListenerSupport.lifecycleEvent(GlobalListenerSupport.java:130)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
    at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5472)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:899)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:875)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
    at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1091)
    at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1980)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:473)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:622)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NoSuchMethodError: javax.persistence.Table.indexes()[Ljavax/persistence/Index;
    at org.hibernate.cfg.annotations.EntityBinder.processComplementaryTableDefinitions(EntityBinder.java:973)
    at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:824)
    at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3845)
    at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3799)
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1412)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1846)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:857)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850)
    at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:425)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:849)
    at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:152)
    at org.apache.openejb.assembler.classic.EntityManagerFactoryCallable.call(EntityManagerFactoryCallable.java:64)
    at org.apache.openejb.assembler.classic.ReloadableEntityManagerFactory.createDelegate(ReloadableEntityManagerFactory.java:116)
    at org.apache.openejb.assembler.classic.ReloadableEntityManagerFactory.<init>(ReloadableEntityManagerFactory.java:102)
    at org.apache.openejb.assembler.classic.PersistenceBuilder.createEntityManagerFactory(PersistenceBuilder.java:154)
    at org.apache.openejb.assembler.classic.Assembler.loadPersistenceUnits(Assembler.java:982)
    at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:741)

List of Jar added to TomEE lib folder:

  • mysql:mysql-connector-java:5.1.22
  • org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final
  • org.hibernate:hibernate-entitymanager:4.3.9.Final
  • org.hibernate:hibernate-core:4.3.9.Final
  • org.hibernate.common:hibernate-commons-annotations:4.0.5.Final
  • org.jboss:jandex:1.1.0.Final
  • org.jboss.logging:jboss-logging:3.1.3.GA
  • org.javassist:javassist:3.18.1-GA
  • antlr:antlr:2.7.7
  • dom4j:dom4j:1.6.1

Although, I tried to deploy other apps within this docker image and every think works as expected.


Answer:

TLDR; your TomEE version does not support the apis you seem to be using.

I would go with upgrading TomEE, so you would get proper support for the apis you want to use. Other solutions are just workarounds that might break in numerous ways as they are not supported.


A bit longer answer:

This looks java app dependency problem/version conflict for me: see this thread for similar error message and its cause. The dependencies you've added depend on javax.persistence spec 2.1, but based on the stack trace your app seems to be using older apis.

You seem to want to use Java Persistence API 2.1, that comes with Java EE 7. Java EE 6 contains Java Persistence API 2.0.

Version of TomEE you're using, Apache TomEE 1.7.4, supports only Java EE 6 and thus Persistence API 2.0, and it was last version not supporting Java EE 7:

From this point on the TomEE community will be focusing most of it's efforts on TomEE 7.0.0, which will be the first TomEE Java EE 7 driven version running on Apache Tomcat 8.x.

So an upgrade of TomEE would be in order.