I've added the following in my web.xml:
<ejb-ref>
<ejb-ref-name>ejb/userManagerBean</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home>gha.ywk.name.entry.ejb.usermanager.UserManagerHome</home>
<remote>what should go here??</remote>
</ejb-ref>
The following java code is giving me NamingException:
public UserManager getUserManager () throws HUDException {
String ROLE_JNDI_NAME = "ejb/userManagerBean";
try {
Properties props = System.getProperties();
Context ctx = new InitialContext(props);
UserManagerHome userHome = (UserManagerHome) ctx.lookup(ROLE_JNDI_NAME);
UserManager userManager = userHome.create();
WASSSecurity user = userManager.getUserProfile("user101", null);
return userManager;
} catch (NamingException e) {
log.error("Error Occured while getting EJB UserManager" + e);
return null;
} catch (RemoteException ex) {
log.error("Error Occured while getting EJB UserManager" + ex);
return null;
} catch (CreateException ex) {
log.error("Error Occured while getting EJB UserManager" + ex);
return null;
}
}
The code is used inside the container. By that I mean that the .WAR is deployed on the server (Sun Application Server).
StackTrace (after jsight's suggestion):
>Exception occurred in target VM: com.sun.enterprise.naming.java.javaURLContext.<init>(Ljava/util/Hashtable;Lcom/sun/enterprise/naming/NamingManagerImpl;)V
java.lang.NoSuchMethodError: com.sun.enterprise.naming.java.javaURLContext.<init>(Ljava/util/Hashtable;Lcom/sun/enterprise/naming/NamingManagerImpl;)V
at com.sun.enterprise.naming.java.javaURLContextFactory.getObjectInstance(javaURLContextFactory.java:32)
at javax.naming.spi.NamingManager.getURLObject(NamingManager.java:584)
at javax.naming.spi.NamingManager.getURLContext(NamingManager.java:533)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:279)
at javax.naming.InitialContext.lookup(InitialContext.java:351)
at gov.hud.pih.eiv.web.EjbClient.EjbClient.getUserManager(EjbClient.java:34)
I think you want to access an EJB application (known as EJB module) from a web application in Sun Application Server, right ?
ok, let's go.
When you deploy an EJB into an application server, the application server gives it an address - known as global JNDI address - as a way you can access it (something like your address). It changes from an application server to another.
In JBoss Application Server, you can see global JNDI address (after starting it up) in the following address
http://127.0.0.1:8080/jmx-console/HtmlAdaptor
In Sun Application Server, if you want to see global JNDI address (after starting it up), do the following
Access the admin console in the following address
http://127.0.0.1:4848/asadmin
And click JNDI browsing
If your EJB IS NOT registered right there, there is something wrong
EJB comes in two flavors: EJB 2.1 and EJB 3.0. So what is the difference ?
Well, well, well...
Let's start with EJB 2.1
Create a Home interface
It defines methods for CREATING, destroying, and finding local or remote EJB objects. It acts as life cycle interfaces for the EJB objects. All home interfaces have to extend standard interface javax.ejb.EJBHome - if you a using a remote ejb object - or javax.ejb.EJBLocalHome - if you are using a local EJB object.
// a remote EJB object - extends javax.ejb.EJBHome
// a local EJB object - extends javax.ejb.EJBLocalHome
public interface MyBeanRemoteHome extends javax.ejb.EJBHome {
MyBeanRemote create() throws javax.ejb.CreateException, java.rmi.RemoteException;
}
Application Server will create Home objects as a way you can obtain an EJB object, nothing else.
Take care of the following
A session bean’s remote home interface MUST DEFINE ONE OR MORE create<METHOD> methods.
A stateless session bean MUST DEFINE exactly one <METHOD> method with no arguments.
...
throws clause MUST INCLUDE javax.ejb.CreateException
...
If your Home interface extends javax.ejb.EJBHome, throws clauses MUST INCLUDE the java.rmi.RemoteException. If it extends javax.ejb.EJBLocalHome, MUST NOT INCLUDE the java.rmi.RemoteException.
...
Each create method of a stateful session bean MUST BE NAMED create<METHOD>, and it
must match one of the Init methods or ejbCreate<METHOD> methods defined in the session
bean class. The matching ejbCreate<METHOD> method MUST HAVE THE SAME NUMBER AND TYPES OF ARGUMENTS. The create method for a stateless session bean MUST BE NAMED create but need not have a matching “ejbCreate” method.
Now create an business interface in order to define business logic in our EJB object
// a remote EJB object - extends javax.ejb.EJBObject
// a local EJB object - extends javax.ejb.EJBLocalObject
public interface MyBeanRemote extends javax.ejb.EJBObject {
void doSomething() throws java.rmi.RemoteException;
}
Now take care of the following
If you are using a remote EJB object, remote interface methods MUST NOT EXPOSE local interface types or local home interface types.
...
If your Home interface extends javax.ejb.EJBObject, throws clauses MUST INCLUDE the java.rmi.RemoteException. If it extends javax.ejb.EJBLocalObject, MUST NOT INCLUDE the java.rmi.RemoteException.
Now our EJB
public class MyBean implements javax.ejb.SessionBean {
// why create method ? Take a special look at EJB Home details (above)
public void create() {
System.out.println("create");
}
public void doSomething() throws java.rmi.RemoteException {
// some code
};
}
Now take care of the following
It MUST IMPLEMENTS javax.ejb.SessionBean. It defines four methods - not shown above: setSessionContext, ejbRemove, ejbPassivate, and ejbActivate.
Notice our bean DOES NOT IMPLEMENT our business interface because of EJB specification says:
For each method defined in the interface, there must be a matching method in the session bean’s class. The matching method must have:
The same name
The same number and types of arguments, and the same return type.
All the exceptions defined in the throws clause of the matching method of the session
bean class must be defined in the throws clause of the method of the local interface.
And YOU HAVE TO DECLARE a ejb-jar.xml file according to
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd" version="2.1">
<enterprise-beans>
<session>
<ejb-name>HelloWorldEJB</ejb-name>
<home>br.com.MyBeanRemoteHome</home>
<remote>br.com.MyBeanRemote</remote>
<local-home>br.com.MyBeanLocalHome</local-home>
<local>br.com.MyBeanLocal</local>
<ejb-class>br.com.MyBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
</ejb-jar>
If you do not have a local EJB object remove from the deployment descriptor above
<local-home>br.com.MyBeanLocalHome</local-home>
<local>br.com.MyBeanLocal</local>
If you do not have a remote EJB object remove from the deployment descriptor above
<home>br.com.MyBeanRemoteHome</home>
<remote>br.com.MyBeanRemote</remote>
And put in META-INF directory
Our jar file will contain the following
/META-INF/ejb-jar.xml
br.com.MyBean.class
br.com.MyBeanRemote.class
br.com.MyBeanRemoteHome.class
Now our EJB 3.0
// or #Local
// You can not put #Remote and #Local at the same time
#Remote
public interface MyBean {
void doSomething();
}
#Stateless
public class MyBeanStateless implements MyBean {
public void doSomething() {
}
}
Nothing else,
In JBoss put jar file in
<JBOSS_HOME>/server/default/deploy
In Sun Application Server access (after starting it up) admin console
http://127.0.0.1:4848/asadmin
And access EJB Modules in order to deploy your ejb-jar file
As you have some problems when deploying your application in NetBeans, i suggest the following
Create a simple Java library PROJECT (a simple jar without a main method)
Add /server/default/lib (contains jar files in order you retrieve your EJB's) jar files to your Java application whether you are using JBoss (I do not know which directory in Sun Application Server)
Implement code above
Now create another war PROJECT
Add our project created just above and add <JBOSS_HOME>/client (contains jar files in order to access our EJB's). Again i do not know which directory in Sun Application Server. Ckeck out its documentation.
See its global mapping address as shown in the top of the answer
And implement the following code in your Servlet or something else whether you are using JBoss
public static Context getInitialContext() throws javax.naming.NamingException {
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
p.put(Context.URL_PKG_PREFIXES, " org.jboss.naming:org.jnp.interfaces");
p.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");
return new javax.naming.InitialContext(p);
}
Or the following whether you are using Sun Application Server - put the file appserv-rt.jar (I do not know which past contain appserv-rt.jar in Sun Application Server) in your classpath
public static Context getInitialContext() throws javax.naming.NamingException {
return new javax.naming.InitialContext();
}
In order to access your EJB in our Servlet or something else
MyBeanRemote myBean = (MyBeanRemote) getInitialContext().lookup(<PUT_EJB_GLOBAL_ADDRESS_RIGHT_HERE>);
myBean.doSomething();
regards,
Last two answers are both correct in that they are things you need to change/fix. But the NoSuchMethodError you see is not from your code, nor from things trying to find your code (would produce some kind of NoClassDefFoundException, I think, were this the case). This looks more like incompatible versions of the JNDI provider provided by the container, and what the JNDI implementation in the Java library wants. That's a pretty vague answer, but, would imagine it is solvable by perhaps upgrading your application server, and, ensuring you aren't deploying possibly-stale copies of infrastructure classes related to JNDI with your app, that might interfere.
First, fix your web.xml and add the Remote Interface in it:
<ejb-ref>
<description>Sample EJB</description>
<ejb-ref-name>SampleBean</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home>com.SampleHome</home>
<remote>com.Sample</remote> <!-- the remote interface goes here -->
</ejb-ref>
Then, regarding the java.lang.NoSuchMethodError, Sean is right, you have a mismatch between the version of the app server "client library" you are using inside NetBeans and the app server version (server-side). I can't tell you exactly which JARs you need to align though, refer to the Sun Application Server documentation.
PS: This is not a direct answer to the problem but I don't think you're currently passing any useful properties when creating your initial context with the results of the call to System.getProperties(), there is nothing helpful in these properties to define the environment of a context (e.g. the initial context factory). Refer to the InitialContext javadocs for more details.
Related
I am trying to port 2 EJB modules in my application from EJB2.1 to EJB3.0. I am using the Eclipse Kepler IDE and regenerated the session beans using an EJB3.0 configuration. I am not using an ejb-jar.xml because in EJB 3.0 that is supposed to be redundant. I have instead used annotations for marking my bean as Stateless and specifying the Local and Local Home Interfaces. I have still kept the Local Home interface since I wanted the basic structure of my project to be similar to what it was in EJB2.1. I have also done away with the xml bindings for the EJB while migrating.
We are using a WAS 7 application server for deployment and while the EJB is getting successfully deployed without errors, I am getting a naming Exception while looking up my Local Home interface from a separate POJO class of a different web application it is required in. I basically want to call the create() method of the Local Home interface after referencing the EJB Local Home. Adding code samples below:
Session Bean:
#Stateless
#Local(AccessLDAPSessionLocal.class)
#LocalHome(AccessLDAPSessionLocalHome.class)
public class AccessLDAPSessionBean implements AccessLDAPSessionLocal {
//Business Logic
}
Local Interface:
public interface AccessLDAPSessionLocal {
//business Interface
}
Local Home Interface:
public interface AccessLDAPSessionLocalHome extends EJBLocalHome {
public AccessLDAPSessionLocal create() throws CreateException;
}
Pojo class referencing the Local Home interface:
public static AccessLDAPSessionLocal getAccessLDAPSessionBean() throws NamingException, CreateException {
if (accessLDAPSessionBean == null) {
InitialContext context = new InitialContext();
Object obj = context.lookup("java:global/AccessLDAP/AccessLDAPSessionBean!com.ibm.asset.hrportal.core.ejb.ldap.AccessLDAPSessionLocalHome");
accessLDAPSessionBean = ((AccessLDAPSessionLocalHome) obj).create();
}
return accessLDAPSessionBean;
}
Also my Local and Local Home interfaces are inside my EJB client which I use as a jar file, while my Session Bean is inside the actual EJB which is used as an EAR.
Following is the error I am getting:
NamingException::javax.naming.NameNotFoundException: Name global not found in context "java:".
Am I missing some configuration resulting in the failure of JNDI lookup? Any help would be gratefully appreciated. Thanks in advance.
WebSphere Application Server 7.0 is only an implementation of EJB 3.0, but the java:global namespace wasn't added until EJB 3.1, which wasn't implemented in WebSphere Application Server until 8.0. As with all EJB 3.0 implementations, you will need to lookup a vendor-specific binding name. You can find the WebSphere Application Server binding name by looking at the CNTR0167I messages in SystemOut.log. See the EJB 3.0 application bindings overview topic in the Knowledge Center if you would like to customize this binding name.
Regardless, it is not a best practice to directly lookup EJBs by their binding name. Instead, you should use an EJB reference. In EJB 3.0, that means using an annotation like this in an EE managed object (such as a servlet or another EJB):
#EJB
private AccessLDAPSessionLocalHome home;
In this case, the EJB container is required to find a target EJB within the same application that contains the EJB reference, so you do not need to explicitly configure a target binding name for the EJB reference.
If you need to access the EJB reference from a utility class rather than an EE managed class, then declare the EJB reference with a name on a managed class (such as a servlet or another EJB), and look it up from the utility class:
#EJB(name = "ejb/accessHome", beanInterface = AccessLDAPSessionLocalHome.class)
public class MyServlet { ... }
public class MyUtility {
...
InitialContext context = new InitialContext();
Object obj = context.lookup("java:comp/env/ejb/accessHome");
...
}
You can configure multiple such EJB references on the same managed EE class using the #EJBs annotation:
#EJBs({
#EJB(name = "ejb/accessHome", beanInterface = AccessLDAPSessionLocalHome.class),
#EJB(name = "ejb/other" beanInterface = Other.class)
})
public class MyServlet { ... }
If your EJB is packaged in a separate EAR, then note that this is not a portable configuration. See the "Local client views" section of the EJB modules topic in the Knowledge Center. Additionally, you will need to explicitly configure a binding name for the EJB reference.
I think the way you are looking up the ejb is not correct. The JNDI name would be something like "java:comp/env/". ejb-ref-name would be part of your web.xml
Also, you will need to give providerURL and factoryName to the context object before doing the lookup.
I am trying to build an application ear file with the following structure:
app.ear
--> lib
-- app-domain.jar
-- app-api.jar
-- app-common.jar
...
--> META-INF
-- application.xml
-- glassfish-application.xml
-- MANIFEST.MF
-- app-ejb.jar
-- app-rs.war
The app-api.jar file contains my remote interfaces like
#Remote
public interface LanguageService {
/**
* #return all languages known to the system
*/
List<Language> loadLanguages();
The implementation is contained in the app-ejb.jar file and looks like this:
#Stateless
#Remote(LanguageService.class)
#Path("/language")
public class LanguageServiceImpl extends ValidatingService implements LanguageService {
#PersistenceContext(unitName = "kcalculator")
EntityManager em;
#GET
#Produces("application/json")
#Override
public List<Language> loadLanguages() {
CriteriaQuery<Language> query = createLoadLanguageQuery();
return em.createQuery(query).getResultList();
}
And finally I want to provide this as an JAX-RS web service and thus have my implementation of the javax.rs.Application class in the app-rs.war file, which looks like this:
#ApplicationPath("/resources")
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(LanguageServiceImpl.class);
return s;
}
This deploys without any problem, the application class is also detected. However, when i finally access the web service an internal server error occurs due to a NPE.
The LanguageServiceImpl cannot be looked up, the log contains the following entry:
Caused by: javax.naming.NameNotFoundException: No object bound to name java:module/LanguageServiceImpl!com.kcalculator.ejb.LanguageServiceImpl
at com.sun.enterprise.naming.impl.GlassfishNamingManagerImpl.lookup(GlassfishNamingManagerImpl.java:741)
at com.sun.enterprise.naming.impl.GlassfishNamingManagerImpl.lookup(GlassfishNamingManagerImpl.java:715)
at com.sun.enterprise.naming.impl.JavaURLContext.lookup(JavaURLContext.java:167)
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:471)
... 63 more
Hence the file is considered a Pojo, and so the reference to the entity manager is not initialized, which finally results in the Nullpointer exception.
I am kinda stuck, as annotating the bean class and giving it a mapped name is not working. Putting my application class into the ejb.jar file does not solve the problem either.
Can anyone point out what i am missing here?
Additional comment:
What I found out in the meantime: If I add a stateless session bean to my app-rs.war file and register it in MyApplication, it works without any problem. There injecting the LanguageService works, too. So it seems the problem is related to the fact that the service implementing bean class is located in another artifact.
The problem could be that you have an EJB with a remote interface.
JAX-RS 1.1 states in 6.2 that JAX-RS annotations only need to be supported on no-interface beans and local interfaces:
JAX-RS annotations MAY be applied to a bean’s local interface or directly to a no-interface bean.
As indicated in one of the previous comments, a working solution was found by moving the session beans to the web archive as well. Thus the separation between the ejb .jar file and the disclosing web service containing project is gone, however it seems rational to have the services in the artifact that is also supposed to provide the web services.
Thanks for the hints, however it is still not clear to me (according to the specification) why the initially described approach should not be feasible (but i realized it isn't...).
I have an application which is part JavaEE (the server side) part JavaSE (the client side). As I want that client to be well architectured, I use Weld in it to inject various components. Some of these components should be server-side #EJB.
What I plan to do is to extend Weld architecture to provide the "component" allowing Weld to perform JNDI lookup to load instances of EJBs when client tries to reference them. But how do I do that ?
In other worrds, I want to have
on the client side
public class ClientCode {
public #Inject #EJB MyEJBInterface;
}
on the server-side
#Stateless
public class MyEJB implements MyEJBInterface {
}
With Weld "implicitely" performing the JNDI lookup when ClientCode objects are created. How can I do that ?
Basically, doing so requires write a so-called portable CDI extension.
But, as it is quite long and requires a few tweaks, let me explain it further.
Portable extension
Like weld doc explains, first step is to create a class that implements the Extension tagging interface, in which one will write code corresponding to interesting CDI events. In that precise case, the most interesting event is, to my mind, AfterBeanDiscovery. Indeed, this event occurs after all "local" beans have been found by CDI impl.
So, writing extension is, more opr less, writing a handler for that event :
public void loadJndiBeansFromServer(
#Observes AfterBeanDiscovery beanDiscovery, BeanManager beanManager)
throws NamingException, ClassNotFoundException, IOException {
// Due to my inability to navigate in server JNDI naming (a weird issue in Glassfish naming)
// This props maps interface class to JNDI name for its server-side
Properties interfacesToNames = extractInterfacesToNames();
// JNDI properties
Properties jndiProperties = new Properties();
Context context = new InitialContext();
for (Entry<?, ?> entry : interfacesToNames.entrySet()) {
String interfaceName = entry.getKey().toString();
Class<?> interfaceClass = Class.forName(interfaceName);
String jndiName = entry.getValue().toString();
Bean<?> jndiBean = createJndIBeanFor(beanManager, interfaceClass, jndiName, jndiProperties);
beanDiscovery.addBean(jndiBean);
}
}
Creating the bean is not a trivial operation : it requires transforming "basic" Java reflection objects into more advanced weld ones (well, in my case)
private <Type> Bean<Type> createJndIBeanFor(BeanManager beanManager, Class<Type> interfaceClass,
String jndiName, Properties p) {
AnnotatedType<Type> annotatedType = beanManager
.createAnnotatedType(interfaceClass);
// Creating injection target in a classical way will fail, as interfaceClass is the interface of an EJB
JndiBean<Type> beanToAdd = new JndiBean<Type>(interfaceClass, jndiName, p);
return beanToAdd;
}
Finally, one has to write the JndiBean class. But before, a small travel in annotations realm is required.
Defining the used annotation
At first, I used the #EJB one. A bad idea : Weld uses qualifier annotation method calls result to build hashcode of bean ! So, I created my very own #JndiClient annotation, which holds no methods, neither constants, in order for it to be as simple as possible.
Constructing a JNDI client bean
Two notions merge here.
On one side, the Bean interface seems (to me) to define what the bean is.
On the other side, the InjectionTarget defines, to a certain extend, the lifecycle of that very bean.
From the literature I was able to find, those two interfaces implementations often share at least some of their state. So I've decided to impelment them using a unique class : the JndiBean !
In that bean, most of the methods are left empty (or to a default value) excepted
Bean#getTypes, which must return the EJB remote interface and all extended #Remote interfaces (as methods from these interfaces can be called through this interface)
Bean#getQualifiers which returns a Set containing only one element : an AnnotationLiteral corresponding to #JndiClient interface.
Contextual#create (you forgot Bean extended Contextual, didn't you ?) which performs the lookup :
#Override
public T create(CreationalContext<T> arg0) {
// Some classloading confusion occurs here in my case, but I guess they're of no interest to you
try {
Hashtable contextProps = new Hashtable();
contextProps.putAll(jndiProperties);
Context context = new InitialContext(contextProps);
Object serverSide = context.lookup(jndiName);
return interfaceClass.cast(serverSide);
} catch (NamingException e) {
// An unchecked exception to go through weld and break the world appart
throw new LookupFailed(e);
}
}
And that's all
Usage ?
Well, now, in my glassfish java client code, I can write things such as
private #Inject #JndiClient MyRemoteEJB instance;
And it works without any problems
A future ?
Well, for now, user credentials are not managed, but I guess it could be totally possible using the C of CDI : Contexts ... oh no ! Not contexts : scopes !
Section 3.5 of the CDI spec should help out. You may want to use some of the properties on the EJB annotation as well. Also, (probably don't need to tell you this) make sure you have JNDI set up correctly on the client to reference the server, and pack any of the needed interfaces into your client jar.
I have 2 ejbs. Ejb-A that calls Ejb-B. They are not in the same Ear.
For portability Ejb-B may or may not exist on the same server. (There is an external property file that has the provider URLs of Ejb-B. I have no control over this.)
Example Code: in Ejb-A
EjbBDelegate delegateB = EjbBDelegateHelper.getRemoteDelegate(); // lookup from list of URLs from props...
BookOfMagic bom = delegateB.getSomethingInteresting();
Use Cases/Outcomes:
When Ejb-B DOES NOT EXIST on the same server as Ejb-A, everything works correctly. (it round-robbins through the URLs)
When Ejb-B DOES EXIST on the same server, and Ejb-A happens to call Ejb-B on the same server, everything works correctly.
When Ejb-B DOES EXIST on the same server, and Ejb-A calls Ejb-B on a different server, I get:
javax.ejb.EJBException: nested exception is: java.lang.ClassCastException: $Proxy126
java.lang.ClassCastException: $Proxy126
I'm using Weblogic 10.0, Java 5, EJB3
Basically, if Ejb-B Exists on the server, it must be called ONLY on that server.
Which leads me to believe that the class is getting loaded by a local classloader (on deployment?), then when called remotely, a different classloader is loading it. (causing the Exception) But it should work, as it should be Serialized into the destination classloader...
What am I doing wrong??
Also, when reproducing this locally, Ejb-A would favor the Ejb-B on the same server, so it was difficult to reproduce. But this wasn't the case on other machines.
NOTE: This all worked correctly for EJB2
So I was able to 'fix' this issue by adding a #RemoteHome(MyRemoteHome.class) to the bean
public interface MyRemoteMethods {
String myMethod() throws RemoteException; // this Ex is required
}
public interface MyRemote extends EJBObject, MyRemoteMethods {
}
public interface MyRemoteHome extends EJBHome {
public MyRemote create() throws CreateException, RemoteException;
}
then my bean
...
#RemoteHome(MyRemoteHome.class)
public class MyBean implements MyRemoteMethods {
...
Previously, only the bean and the Remote interface existed. (there is no local usage)
Overall, this fix makes my EJB 3 a bit more EJB 2-ish and not as clean (more code and classes involved). I am also unclear why I can do a jndi lookup for the RemoteHome interface (and call create) from my local and remote servers and not get a ClassCastException, but when I do this for the Remote interface, I do get a ClassCastException. Is this a bug in Weblogic? (I've also seen some posts similar using JBoss)
I've got a NullPointerException using EJB3 in a J2SE environment (without EJB3 container)
Briefly, I've got a stateless bean implementing an interface.
When I call it in another class like in a main, a NullPointerException is triggered.
Sample:
#stateless
#Local(IMyInterface.class)
public class myBean implements IMyInterface{...}
public class Main{
#EJB
IMyInterface myInterface;
public static void main(String[] args){
Result result = myInterface.myBeanMethod(); // Exception happens here
}
}
I guess I miss some initialization stuff because the EJB is null when I first try to use it...
Thanks for your help,
EJBs can't work without a container. The dependencies (#EJB) are injected if the beans are instantiated by the container. If you are the one instantiating them, it is your responsibility to set the dependencies.
Furthermore, you are trying to use a non-static variable from a a static method - this won't even compile.
While you can use JPA (which is part of EJB 3) "Entity Beans" (actually, POJOs) in a J2SE environment, you can't use Session Beans without a container and you can't benefit from injection of resources using the #Resource or the more specialized #EJB and #WebServiceRef annotations in a non-managed environment, i.e. a container. In other words, only managed components support injection (Servlets, JSF Managed beans, EJB components, etc).
So, in your case, you'll need to:
Deploy your Session Bean in a Java EE container (like JBoss, GlassFish, WebLogic, etc)
Lookup the remote EJB using explicitly its global JNDI name. The code will look like that:
Foo foo = (Foo) new InitialContext().lookup("FooEJB");
A few additional remarks:
With EJB 3.0, the global JNDI name is container dependent so I can't tell you what it will be exactly (EJB 3.1 finally introduced "portable global JNDI names").
You'll need to set up the JNDI environment (which is container dependent) for the lookup either by providing a jndi.properties on the class path or by using the InitialContext(Hashtable) constructor.
You'll need to provide the application server "client library" on the class path of the client (which is obviously specific to each product).
Search for previous questions or open a new one if you need more specific guidance.