Hot questions for Using Enterprise JavaBeans in java ee 6

Question:

I need to maintain a simple counter that is unique within the application, for all users and all nodes in a clustered environment. I thought about using the singleton session bean annotation javax.ejb.Singleton like so:

package foo;

import javax.ejb.Singleton;

@Singleton
public class Bean {
    private int counter;
    [...]
}

This looks simple, but I could not find an answer if this works as desired in a clustered environment. Would every node of the cluster have it's own instance or not?

Of course I could persist the bean in a database, but it's really only a counter and doing so would be overkill. Also, I want the counter to reset on application crash or restart, so persisting it would create more problems than it solves.


Answer:

Would every node of the cluster have it's own instance or not?

Yes, each cluster node will have a different Singleton instance. Therefore, @Singleton annotation is not the solution for your problem.

Take in mind that Java EE specification doesn't define any kind of cluster behavior. You need to search for specific vendor solution to achieve this kind of requirement. Just as an example see this link.

Question:

Message-Driven Bean Class

the requirements of a message-driven bean class:

It must not define the finalize method.

What is the reason for above requirement ?


Answer:

If you look in the EJB spec, you will see that it is a requirement for all types of EJB.

http://download.oracle.com/otndocs/jcp/ejb-3.1-pfd-oth-JSpec/

I can't find a definitive answer but looking on various Java forums over the last 13 years, you can see answers consistently saying that, because the container will decide the life-cycle of the EJB, the finalize may never be called (or called when you don't expect) and it would there be dangerous to use it.

https://community.oracle.com/thread/1582366

Question:

I have the code from below and wondering how does JPA know to persist this update. I expected an em.merge() to be needed in order to perform the update. Is this actually safe ?

@Stateless
class User { 

    ...

    public void generateRandomNicknames() {
        List<UserEntity> users = em.createNamedQuery("UserEntity.getAllUsers", UserEntity.class)
                                   .getResultList();
        for (UserEntity user : users) {
              user.setNickname(generateRandomNickname());
        }
        // em.merge(user) or em.persist(user) not needed ?
    }
}

Answer:

In short: Managed entities are generally synchronized with the database on transaction commit. The JPA implementation is responsible for tracking changed managed entities and update the database. In your case, calling user.setNickname(...) will notify JPA that this specific user object is dirty. And a transaction is by default active on calling business methods of a Session EJB.

Note that the above is the default behavior that can be altered by configuration!

Longer story, with references from the JEE 8 sub-specs (the question is about JEE 6, these still apply, although in different section numbers):

(JPA 2.1) Section 3.2.4: Synchronization to the Database

The state of persistent entities is synchronized to the database at transaction commit. This synchronization involves writing to the database any updates to persistent entities and their relationships as specified above.

[...]The persistence provider runtime is permitted to perform synchronization to the database at other times as well when a transaction is active and the persistence context is joined to the transaction. The flush method can be used by the application to force synchronization.

There are other interesting details in this chapter, but note that merge() does NOT have to be called, for a managed entity to be saved at the end of the transaction.

Which brings us to the next detail, the transaction. Since this is a method of a Session EJB, it is by default run in the context of a transaction:

(EJB core 3.2) Section 8.3.6: Specification of a Bean’s Transaction Management Type

By default, a session bean or message-driven bean has container managed transaction demarcation if the transaction management type is not specified. [...]

(EJB core 3.2) Section 8.3.7: Specification of the Transaction Attributes for a Bean’s Methods

The Bean Provider of an enterprise bean with container-managed transaction demarcation may specify the transaction attributes for the enterprise bean’s methods. By default, the value of the transaction attribute for a method of a bean with container-managed transaction demarcation is the REQUIRED transaction attribute, and the transaction attribute does not need to be explicitly specified in this case.

An important detail is that the entities are actually managed. This is, in this case, because they are returned from JPA itself and because of how the JPQL query "UserEntity.getAllUsers" is structured. In general entities could be unmanaged or detached, in which case calling merge() or persist() would have been necessary.

Question:

I have beans annotated with @Stateless packaged in WEB-INF/lib/*.jar. Does JBoss 5.1.0 GA support these type of EJB deployment mentioned here

Or do I need to package my beans always in an EAR and provide JBoss descriptors?


Answer:

JBoss 5 is a Java EE 5 EJB 3.0 Compatible Implementation. EJB3.1 spec (part Java EE 6) lets .war files to contain EJBs and is not part JBoss 5, you can try with JBoss AS 6 or any higher version

Question:

Im triying to deploy a little application but when I press run with de JBoss configuration, I get this Exception:

    13:46:04,768 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-5) MSC00001: Failed to start service jboss.persistenceunit."agenda5_war_exploded.war#manager1": org.jboss.msc.service.StartException in service jboss.persistenceunit."agenda5_war_exploded.war#manager1": Failed to start service
    at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1767) [jboss-msc-1.0.2.GA.jar:1.0.2.GA]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_79]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_79]
    at java.lang.Thread.run(Thread.java:745) [rt.jar:1.7.0_79]
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: manager1] Unable to build EntityManagerFactory
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:914)
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:889)
    at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:73)
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.createContainerEntityManagerFactory(PersistenceUnitServiceImpl.java:162)
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.start(PersistenceUnitServiceImpl.java:85)
    at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811) [jboss-msc-1.0.2.GA.jar:1.0.2.GA]
    at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746) [jboss-msc-1.0.2.GA.jar:1.0.2.GA]
    ... 3 more
Caused by: org.hibernate.HibernateException: Specified JDBC Driver com.mysql.jdbc.Driver class not found
    at org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl.configure(DriverManagerConnectionProviderImpl.java:104)
    at org.hibernate.service.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:75)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:159)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:131)
    at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.buildJdbcConnectionAccess(JdbcServicesImpl.java:234)
    at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:91)
    at org.hibernate.service.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:75)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:159)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:131)
    at org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:71)
    at org.hibernate.cfg.Configuration.buildSettingsInternal(Configuration.java:2270)
    at org.hibernate.cfg.Configuration.buildSettings(Configuration.java:2266)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1735)
    at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:84)
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:904)
    ... 9 more
Caused by: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver from [Module "org.hibernate:main" from local module loader @462d62d9 (roots: /Users/coolmyplanet/Downloads/jboss-as-7.1.1.Final/modules)]
    at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:190) [jboss-modules.jar:1.1.1.GA]
    at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:468) [jboss-modules.jar:1.1.1.GA]
    at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:456) [jboss-modules.jar:1.1.1.GA]
    at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398) [jboss-modules.jar:1.1.1.GA]
    at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:120) [jboss-modules.jar:1.1.1.GA]
    at java.lang.Class.forName0(Native Method) [rt.jar:1.7.0_79]
    at java.lang.Class.forName(Class.java:191) [rt.jar:1.7.0_79]
    at org.hibernate.internal.util.ReflectHelper.classForName(ReflectHelper.java:192)
    at org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl.configure(DriverManagerConnectionProviderImpl.java:101)
    ... 23 more

JBAS014777:   Services which failed to start:      service jboss.persistenceunit."agenda5_war_exploded.war#manager1": org.jboss.msc.service.StartException in service jboss.persistenceunit."agenda5_war_exploded.war#manager1": Failed to start service

My persistence.xml, I search in other posts but I can't fix the problem. Im new in JBoss and Intellij IDEA.

 <?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             version="2.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

    <persistence-unit name="manager1" transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>modelo.User</class>
        <properties>
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/test_app"/>
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
            <property name="hibernate.connection.username" value="root"/>
            <property name="hibernate.connection.password" value="root"/>
            <property name="hibernate.archive.autodetection" value="class"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="create"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
        </properties>
    </persistence-unit>
</persistence>

NEW

I fix the error by putting the JTA datasource in persistence.xml, but JBoss is telling me that this data source is missing.

service jboss.naming.context.java.sample (missing)

Answer:

You need to add a module dependency on the MySQL module you added.

The documentation is here: https://docs.jboss.org/author/display/AS7/Class+Loading+in+AS7

You can use Maven WAR plugin to add the Dependencies: com.mysql line in the MANIFEST.MF file. Or you can add a jboss-deployment.xml file.