Calling an EJB from WAR, in a standalone Java class
zecas Mar 21, 2011 7:30 AMHi,
I'm getting some difficulties on putting an EJB to work, I hope someone can help me out, as this must be something very simple.
I have a EAR project that contains a WAR and an EJB modules. I'm using EJB3 and annotations, and I have the current one defined:
@Stateless(name="my-proc")
public class MyProc implements MyProcRemote, MyProcLocal {
/**
* Default constructor.
*/
public MyProc() {
}
/**
* {@inheritDoc}
*/
public void log(String message) {
System.out.println("Received Message: [" + message + "]");
}
}
@Local
public interface MyProcLocal {
public void log(String message);
}
@Remote
public interface MyProcRemote {
public void log(String message);
}
Looking into JBoss JMX console, I don't know exacly where to find the deployed EJB info, but on the console initial listing, I found:
id="jboss.j2ee:ear=myear-1.0.0.ear,jar=myejb-1.0.0.jar,name=QueueMDB,service=EJB3",type=Component (This is a different EJB)
id="jboss.j2ee:ear=myear-1.0.0.ear,jar=myejb-1.0.0.jar,name=my-proc,service=EJB3",type=Component
id="jboss.j2ee:ear=myear-1.0.0.ear,jar=myejb-1.0.0.jar,name=my-proc,service=EJB3_endpoint",type=Component
I've created a simple Servlet to inject the EJB, and it worked correctly, so I assume the EJB is well deployed:
public class MyServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@EJB MyProcRemote proc;
/**
* @see HttpServlet#HttpServlet()
*/
public MyServlet() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println("<html><body>");
writer.println("Hello.");
if( proc!=null ) {
proc.log("MyServlet!");
} else {
writer.println("<br>proc is null.");
}
writer.println("</body></html>");
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
My web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>myweb</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<description></description>
<display-name>MyServlet</display-name>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.test.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet</url-pattern>
</servlet-mapping>
</web-app>
My application.xml:
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd" id="Application_ID" version="5">
<display-name>myear</display-name>
<module>
<web>
<web-uri>myweb-1.0.0.war</web-uri>
<context-root>/myweb</context-root>
</web>
</module>
<module>
<ejb>myejb-1.0.0.jar</ejb>
</module>
</application>
I have no more definitions.
Now my problem:
In my WAR, I use an API from my company that lauches a thread for accepting socket connections. When a connection arrives, the code instantiates a plain Java class and executes a method.
Since the code runs from from an executing thread, and it calls one class defined by me (not a servlet, not anything JavaEE), I cannot use dependency injection (or can I?), so I'm having difficulties on getting a remote (or local) EJB interface to work.
I was hopping to use a JNDI lookup like "java:comp/env/my-proc" but i can't make it to work.
At this time I'm using:
public class Received {
...
public void exec(String message) {
...
try {
Context ctx = new InitialContext();
MyProcRemote proc = (MyProcRemote) ctx.lookup("my-proc/remote");
proc.log("Calling EJB!");
} catch(Exception e) {
e.printStackTrace();
}
...
}
...
}
The output is something like:
javax.naming.NameNotFoundException: my-proc not bound
at org.jnp.server.NamingServer.getBinding(NamingServer.java:771) ~[jnpserver.jar!/:5.0.3.GA]
at org.jnp.server.NamingServer.getBinding(NamingServer.java:779) ~[jnpserver.jar!/:5.0.3.GA]
at org.jnp.server.NamingServer.getObject(NamingServer.java:785) ~[jnpserver.jar!/:5.0.3.GA]
at org.jnp.server.NamingServer.lookup(NamingServer.java:396) ~[jnpserver.jar!/:5.0.3.GA]
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:726) ~[jnpserver.jar!/:5.0.3.GA]
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:686) ~[jnpserver.jar!/:5.0.3.GA]
at javax.naming.InitialContext.lookup(InitialContext.java:392) ~[na:1.6.0_21]
at com.test.Received.exec(Received.java:42) ~[myweb-1.0.0.war:na]
at java.lang.Thread.run(Thread.java:619) [na:1.6.0_21]
In the future, I'm going to use the local interface, but at this time, I can't put any of them to work.
I'm developping in JBoss, and the production environment will be a Websphere, so I'm looking for a cross-platform way of doing it, so JNDI seems to be the way to go.
Now the JNDI lookup string would be same? I would prefer so ... but if it is not, I can work out a way of external properties configuration of that JNDI string.
Note:
I will also try something like:
public static void main(String[] args) {
InitialContext context;
Properties properties = new Properties();
properties.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
properties.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
properties.put("java.naming.provider.url", "jnp://(ipaddress):1099");
try {
context = new InitialContext(properties);
BeanRemote remoteBean = (BeanRemote)context.lookup("BeanRemote/remote");
catch (NamingException e){
System.out.println("testing here");
e.printStackTrace();
throw new RuntimeException(e);
}
... that I found somewhere, but I was hopping not to need that many info, because in Websphere I may not need anything like that, and anyway defining the server (IP, hostname, whatever ...) will add complexity to deploys.
Thanks