views:

979

answers:

3

Hi, I'm writing my first JEE (EJB + Servlets etc.) application (please note: I'm using Eclipse).
I'm stuck with a problem with EntityManager injection not working, and having some difficulties finding why due to my JEE (and Java in general) noobness.

Here is my persistence.xml file - I think this is mostly correct, since I can launch the HSQL database manager from the JMX console and my PUBLIC.USER table shows up correctly.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" 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_1_0.xsd"&gt;
    <persistence-unit name="MyPu">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>java:/DefaultDS</jta-data-source>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
        </properties>
    </persistence-unit>
</persistence>

Here's my servlet code:

[...]
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws      
    String id = request.getParameter("username");
    String password = request.getParameter("password");

    UserManagerBean um = new UserManagerBean();
    um.register(username, password);

    RequestDispatcher dispatcher=getServletContext().getRequestDispatcher("/index.jsp");
    dispatcher.forward(request, response);
}

And here's my UserManagerBean Class:

//bunch of imports

import myPackage.UserManager;

public @Stateful class UserManagerBean implements UserManager {
    @PersistenceContext(unitName="MyPu")
    private EntityManager persistManager;

    public void register(String username, String password) {
        User user = new User(userame, password);
        persistManager.persist(user);
        persistManager.flush();
    }
}

The persistManager.persist(user) line throws a NullPointerException. From my own searching I understood that this is happening because, since I'm calling new() on UserManagerBean the injection from the @PersistenceContext annotation never takes place and persistManager never gets bound.
If so, it is evident that I'm missing something about the proper usage of EJBs.
What is the right way to instantiate my bean? What's with the interfaces? I'm not entirely sure if my bean should be stateful or stateless :\

Additional info:
I changed code in my servlet, from

UserManagerBean um = new UserManagerBean();

to

@EJB
private UserManagerBean um;

in the appropriate place. Now um is the NullPointer.

+1  A: 

As Petar Minchev said in the comments above @EJB doesn't work in servlets with JBoss 4.2.

In your WAR (in the WEB-INF directory) you'll need to modify two files:

web.xml:

<ejb-local-ref>
        <ejb-ref-name>ejb/UserManager</ejb-ref-name>
        <ejb-ref-type>Session</ejb-ref-type>
        <local-home/>
        <local>myPackage.UserManager</local>
</ejb-local-ref> 

jboss-web.xml:

<?xml version='1.0' encoding='ISO-8859-1'?>
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.3//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_3_2.dtd"&gt;
<jboss-web>

  <ejb-local-ref>
    <ejb-ref-name>ejb/UserManager</ejb-ref-name>
    <local-jndi-name>[earname]/UserManagerBean/local</local-jndi-name>
  </ejb-local-ref>

</jboss-web>

You can then get an instance of your EJB by doing:

UserManagerBean um = (UserManager)new InitialContext().lookup( "java:comp/env/ejb/UserManager" );
mtpettyp
I ended up using the JNDI lookup, so thanks for the code :)
Agos
A: 

As per the comments, it turns out that you indeed are using an appserver which doesn't support it at all -as I expected. To resolve this, you have 3 options:

  1. Use "good old" XML config files.
  2. Upgrade the server (there's already a stable 5.1.0).
  3. Replace the server (I can recommend Glassfish v3 to be the most up-to-date).
BalusC
+1  A: 

Quoting Referencing EJB3 Session Beans from non-EJB3 Beans from the JBoss documentation:

JBoss Application Server 4.2.2 implemented EJB3 functionality by way of an EJB MBean container running as a plugin in the JBoss Application Server. This had certain implications for application development.

The EJB3 plugin injects references to an EntityManager and @EJB references from one EJB object to another. However this support is limited to the EJB3 MBean and the JAR files it manages. Any JAR files which are loaded from a WAR (such as Servlets, JSF backing beans, and so forth) do not undergo this processing. The Java 5 Enterprise Edition standard specifies that a Servlet can reference a Session Bean through an @EJB annotated reference, this was not implemented in JBoss Application Server 4.2.2.

So even though the JEE 5 specification stipulates a wider scope of the @EJB annotation, JBoss 4.2.2 doesn't support it. In fact JBoss 4.2.2 is a transitional version that doesn't claim full JEE 5 compliance.

Consequently, either:

  • Stick with you actual version of JBoss but use a JDNI lookup to get your bean - or -
  • Swith to JBoss 5 AS that fully supports the entire Java 5 Enterprise Edition specification (but has horrible startup performances) - or -
  • Swith to another Java EE 5 application server like GlassFish v2 (or even v3) or WebLogic 10. I'd go with GFv3.
Pascal Thivent
Impending deadlines mean no AS change (for now). JNDI lookup for now it will be, it's a small app so no big deal. Will keep this advice as a valuable warning for any future encounter with J2EE!
Agos