can any one help me - having a bad day with ejb3 server and
wiggy May 27, 2007 5:52 PMfolks i need some help - i must be going stupid but dont know where - advice greatfully received.
I have created an EJB project for a simple hello world type stateless session bean that i publish to an 4.2 jboss container .
I use eclipse as the editor - and have two projects setup, the first for the ejb project, the second project is a standalone application that uses the embedded jboss server (from the seam distro 1.2.1.ga).
tried several scenarios and cant get the client to call the ejb successfuly.
in my EJB project i declare a bean like this
package app; import javax.ejb.Remote; import javax.ejb.Stateless; import app.client.HelloUser; // (see later comments on client lookup) @Remote (HelloUser.class) @Stateless public class HelloUserBean implements HelloUser { HelloUserBean() {}; public String sayHello (String text) { String msg = "hello " + text + " /n"; System.out.println(msg); return msg; } }
I then have an 'app.client' dir for the bean interfaces. I have a default interface
package app.client; import javax.ejb.*; public interface HelloUser { public String sayHello (String text); }
and then extend various interfaces local, remote, WS etc from this e.g.
package app.client; import javax.ejb.*; import app.client.HelloUser; @Remote public interface HelloUserRemote extends HelloUser { }
so far so good. I create a jar file for all the interfaces that i make available to the second project (am i doing the right thing here. Without it i cant make a reference to the class i want when i do a jndi lookup or try DI)
Then i start the 4.2 server and deploy the ejb project. This goes fine.
I then have a second straight java project - this includes a /conf dir which is an exact copy of the /conf from the seam embedded dir which i include in my classpath, along with all the /lib jars from the seam /lib dir.
I then write my main client app code
/** * */ import java.util.Hashtable; import javax.ejb.EJB; import javax.naming.InitialContext; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.jboss.ejb3.embedded.EJB3StandaloneBootstrap; import app.client.HelloUser; import app.client.HelloUserRemote; /** * @author Will * */ public class ClientApp { @EJB public HelloUser tstHandler; public ClientApp () {} public static void main(String[] args) throws Exception { Logger log = Logger.getLogger(ClientApp.class); log.setLevel(Level.DEBUG); //log.debug("Welcome to Wills App"); // Boot the JBoss Microcontainer with EJB3 settings, automatically // loads ejb3-interceptors-aop.xml and embedded-jboss-beans.xml EJB3StandaloneBootstrap.boot(null); // Deploy custom stateless beans (datasource, mostly) //EJB3StandaloneBootstrap.deployXmlResource("META-INF/NeilsApp-beans.xml"); // Deploy all EJBs found on classpath (fast, scans build directory) // This is a relative location, matching the substring end of one // of java.class.path locations. Print out the value of // System.getProperty("java.class.path") to see all paths. EJB3StandaloneBootstrap.scanClasspath(); InitialContext ctx = getInitialContext(); // Look up the stateless TestHandler EJB //HelloUserRemote tstHandlerLoc = (HelloUserRemote) ctx.lookup("HelloUserBean/remote"); // Call the stateless EJB //String message = tstHandlerLoc.sayHello("hello Will"); //try dependency injection! String message = new ClientApp().tstHandler.sayHello("hello William"); //Shut down EJB container EJB3StandaloneBootstrap.shutdown(); } public static InitialContext getInitialContext() throws Exception { Hashtable props = getInitialContextProperties(); return new InitialContext(props); } private static Hashtable getInitialContextProperties() { Hashtable props = new Hashtable(); props.put("java.naming.factory.initial", "org.jnp.interfaces.LocalOnlyContextFactory"); props.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces"); return props; } }
as i am not using a Data Source at present so I comment out the
// Deploy custom stateless beans (datasource, mostly)
//EJB3StandaloneBootstrap.deployXmlResource("META-INF/NeilsApp-beans.xml");
section, and have not defined a persistence.xml file for the container yet.
If i run it like this - the Dependency Injection doesnt work and i get a null pointer exception when i hit the
String message = new ClientApp().tstHandler.sayHello("hello William");
If i comment this out and use a JNDI lookup call instead
// Look up the stateless TestHandler EJB
HelloUserRemote tstHandlerLoc = (HelloUserRemote) ctx.lookup("HelloUserBean/remote");
// Call the stateless EJB
String message = tstHandlerLoc.sayHello("hello Will");
then i get the following error
22:39:24,727 INFO [EJBContainer] STARTED EJB: app.HelloUserBean ejbName: HelloUserBean
Exception in thread "main" javax.naming.NameNotFoundException: remote not bound
at org.jnp.server.NamingServer.getBinding(NamingServer.java:529)
at org.jnp.server.NamingServer.getBinding(NamingServer.java:537)
at org.jnp.server.NamingServer.getObject(NamingServer.java:543)
at org.jnp.server.NamingServer.lookup(NamingServer.java:296)
at org.jnp.server.NamingServer.lookup(NamingServer.java:270)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:626)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:588)
at javax.naming.InitialContext.lookup(Unknown Source)
at ClientApp.main(ClientApp.java:52)
if however - I uncomment the line in the HelloUserBean and set the @Remote(HelloUser.class), and then proceed to do the lookup in the client app as follows (note i have dropped the HelloUserRemote now)
// Look up the stateless TestHandler EJB - dont use base interface def, and @Remote in defining bean class
HelloUser tstHandlerLoc = (HelloUser) ctx.lookup("HelloUserBean/remote");
// Call the stateless EJB
String message = tstHandlerLoc.sayHello("hello Will");
then i seems to work.
I dont understand why I cant get this to work.
first off i presume i should use remote as the 4.2 ejb server and the embedded server are running in different VM's (under my single eclipse edit session)
second - whether its DI or jndi lookup - why cant i find/map the remote interface properly and make the client call?
any help explaining this to a simpleton would be appreciated.
regards Wiggy