I'm deploying a Java EE application on JBoss 7.1.1, and when my session beans get deployed, JBoss prints out a message saying that it has created multiple JNDI bindings. Something like this:
java:global/ear-name/jar-name/MyClassImpl!fully.qualified.path.to.Interface
java:app/jar-name/MyClassImpl!fully.qualified.path.to.Interface
java:module/MyClassImpl!fully.qualified.path.to.Interface
java:jboss/exported/ear-name/jar-name/MyClassImpl!fully.qualified.path.to.Interface
java:global/ear-name/jar-name/MyClassImpl
java:app/jar-name/MyClassImpl
java:module/MyClassImpl
It varies a little bit from EJB to EJB, but that's the general idea.
I'm confused about what's going on here. Why are there so many of them? Is there a difference between these JNDI bindings? If there is, when should each of them be used?
You can find all the documentation here [1] but in short some of it is dictated by spec and some are functionality specific to JBoss (mainly java:jboss/exported, java:jboss entries)
[1] https://docs.jboss.org/author/display/AS71/JNDI%20Reference.html
Related
Similar to What to put into jta-data-source of persistence.xml? and How to map jpa datasources in WildFly?
However, I am asking for something that would work on all vendors or at least WildFly, Glassfish/Payara, WebSphere Application Server classic, WebSphere Application Server Liberty, TomEE. I am not looking for something that works in a Java SE Unit test.
So far I found that java:comp/env/jdbc/xxx works in WebSphere Application Server and TomEE. There's a mapping exercise (which is expected) to get it working but I cannot get the same to work on GlassFish/Payara and JBoss/WildFly.
More specifically I do not wish to use default data source because for my scenario I am actually working on two different data sources. E.g. for reference data and another for transactional.
If all of the app servers you work with are Java EE 7 compliant, you can use the default data source, which is required per EE7 spec to be available at:
java:comp/DefaultDataSource
The app server you run on ought to let you customize the configuration of the DefaultDataSource.
Since I'm familiar with WebSphere Liberty, I can point you to this doc for default data sources on Liberty:
Configuring a default data source
If you are using WebSphere traditional, as of v9.0 it supports Java EE 7, and has a default data source available out of the box (under the spec mandated JNDI name).
If you want to use the same JNDI name that works on all servers, it's best to use resource references, as explained in What is resource-ref in web.xml used for?
Basically, you would define an arbitrary JNDI name (ideally without any java:comp prefix or similar, just something like "myDatasource") and then map it to the concrete JNDI name provided by the target server.You would need to define a server-specific descriptor for each server with the mapping the if the server cannot use the JNDI directly (e.g. glassfish-web.xml for GlassFish/Payara, jboss-web.xml for WildFly, ibm-web-bnd.xml for WebSphere Classic and Liberty). TomEE seems to support references without any prefix, so it should be able to configure a datasource without any additional mapping if you choose a name without a prefix.
We're using Maven and Artifactory, and therefore our ear files have names like
our-project-ear-0.0.1-20151215.151526-3.ear.
So JNDI names for our EJBs have names like
java:global/our-project-ear/our-project-ejb/AnEjbJar!com.acme.ourproject.SomeEjb.
These names are not just ugly and complex, they also embed temporary suffixes added by Maven/Artifactory.
I thought we could simplify the names via the JBoss-specific #RemoteHomeBinding annotation, but I do not find this annotation in EAP 6.3. Is there still a way to do this? If not, how can I control the JNDI name under which my EJBs are published?
Figured it out myself. The #RemoteBinding, #LocalBinding, #RemoteHomeBinding and #LocalHomeBinding annotations have been phased out in AS7.x. A version of the JBoss instructions for migrating from AS5/6 to AS7 (not the current one) states:
>In AS7 there is no possibility for custom JNDI names of EJB beans and it's not planned for 7.1.
>Therefor the annotation #RemoteBindings and #LocalBindings are not available.
The recommended approach is to use the default bindings. However, custom JNDI names can also be defined via the #EJB annotation, as stated in this Oracle blog:
The developer can select an additional JNDI name that resolves to a particular client view of a session bean by using the #EJB annotation. Starting with Java EE 6, the #EJB name() attribute value can be prefixed with any one of the three portable Java EE namespaces : java:global, java:app, java:module. This has the effect of exporting the dependency into the selected scope.
I think what you are looking for is :
#Ejb(lookup="java:/global/somecustomPath")
As this will not affect where in JNDI the bean is bound but rather where to find it in JNDI.
If I'm right this is because JBOSS7 is a JEE6 application server and JEE6 introduced the concept of Portable Global JNDI names in JEE6.
We have ".sar"(Service Archive file) used in jboss. Currently we are planning to migrate the code to Weblogic.
Is there a way to deploy .sar files into weblogic.
If not directly possible, is there a work around where we can deploy the services on web logic.
In order to get the custom mbeans that are in the .sar you will need to repackage the contents as an .ear as a .sar is not standard Java EE deployment mechanism - that is a JBoss proprietary archive.
Here are some instructions on how to create, package and deploy your own service MBeans (JMX Beans) along with an example of how to use it.
https://blogs.oracle.com/WebLogicServer/entry/developing_custom_mbeans_to_ma
One thing you could do is to "substitute" or "emulate" the SAR Deployer, by creating, configuring and registering MBeans. That, AFAIK, could be done in two ways:
1) Using Standard Java EE components: that means on web tier you can use the init() method of a servlet (make sure that it is preloaded on startup) or, better, a ServletContextListener
2) Using WebLogic specific components. I'm talking about Startup classes. Simply register a startup class that creates, configures and registers your MBeans.
If you are using a web module, the first approach has the obvious advantage that you are using pure Java EE components. Although you are not using that, you can add a "dummy" web module only for doing that
Concerning what you have to do in those classes, you can choose a "from scratch" approach, by parsing the xml files that describe services and therefore manually create, configure and register MBeans or, if I remember well, the XMBeans from JBoss is something that can be reused outside JBoss but you need to check because I'm not sure
After reading about it for so long, I now have chance to get my hand dirty with EJB. I use Glassfish+Eclipse 3.7 on Ubuntu.
I first created an EJB that just returns a greeting message. Then I create the application client to access this EJB using InitialContext. This works exactly like expected.
Then, I created a servlet to access to that EJB. Neither access with #EJB nor InitialContext works.
When I use #EJB, the 404 page appear with this description: "The requested resource () is not available."
When I use InitialContent, an ClassNotFoundException is thrown. Apparently, the class loader of the servlet cannot access to the EJB class. I tried to add EJB jar file to the servlet's lib folder and I got the error message that the JNDI name already exists. Apparently, Glass Fish tries publish the EJB in the Servlet's lib folder too.
The only way to get this to work is to publish the EJB with the servlet. This way, both I can get the servlet and a stand-alone application to access to that EJB. The problem is that I need to always employ the servlet with the EJB which is not desirable since my client may not want to use web front end.
Anyway, my question is what is appropriate way to have the servlet access to the EJB employed outside its class loader without repeatedly publishing the EJB.
P.S. It is also possible that the problem might be the way Eclipse configure and employ those components.
Thank a lot for any helps.
Perhaps you need to treat the EJB component as if it were remote. And maybe it really is since you don't give a lot of detail on how you are deploying. Try the directions at http://glassfish.java.net/javaee5/ejb/EJB_FAQ.html#nonJavaEEwebcontainerRemoteEJB.
A few pointers:
you may need to put the webapp and the ejb-jar in an .ear (enterprise application) and deploy it to glassfish
you may need the remote interfaces on the classpath of the webapp (if they are not available at runtime, but they were at compile time, you can't expect it to work)
NetBeans is generally better with enterprise stuff and wizards for creating and deploying applications. Give it a try.
After try out a while, I found that I can do by referring it as "/". This even works with injection.
I have a few separate application projects (EARs) with multiple EJBs that I want to deploy to the same JBoss server. Now, some of the projects may have the same EJBs, but different versions. In similar circumstances, some projects may use different versions of the same "ordinary" classes (i.e. classes loaded within VM, without JNDI lookup).
With OC4J, this seems not to have been a problem, but now with JBoss, I get the impression that everything resides in the same "name space" (or class loader perhaps). Am I correct in this assumption?
Basically, what I want to do (or ensure) are two things:
From a client that does a JNDI-lookup of an EJB, I want to be able to indicate which application it resides in, so that the correct version of the EJB is returned.
From within an EJB, when instantiating a class, I want to ensure that the class is the one deployed with the same application (EAR) as the EJB was.
I think I read that you could configure some "isolation" properties for EJBs, am I guessing correctly in that might would solve my second point?
JBoss's default behaviour is to use a flat classloader. This reduces the footprint, but as you've found, it makes deploying multiple applications troublesome.
Thankfully, the fix is easy. In the ear-deployer.xml file in the deploy directory, make sure the following parameter is set:
<attribute name="Isolated">true</attribute>
This will give each deployed EAR its own classloader space. It will still be able to access stuff from the JBoss lib directory, but the deployed EARs will be invisible to each other.
You're correct that classes from different EAR's reside in the same "space". JBoss uses by default a flat classloader hierarchy, meaning that all classes (except for WAR packaged ones) are loaded by the same classloader. With the introduction of JBoss 5 there's a new standard profile that strictly follows the Java EE rules and thus supports isolated classloading. Older JBoss versions also support this behavior through the callByValue and isolate properties in the deployer configuraion.