Glassfish 2.1 EJB 3.0 Exposing local EJB to other applications running in the same domain/jvm - ejb-3.0

I have an existing project that I am in need of configuring different. This needs to happen without major code changes. I am actually hoping I could somehow do this only with configuration. I have spent the past 2 to 3 days reading everything I can find on this issue. I understand the glassfish classloaders, and what is available to me.
I have a current sample project that has an EJB which defines a #Local interface.
The ejb is deployed inside an ejb-module as an ejb-module into the glassfish domain.
Now I am trying to find a way for another application which was deployed as an ear into the same domain, to be able to access that EJB via it's local interface.
I have read documentation that says this is not possible.
Then I have seen posts on here at StackOverflow, and other's on the web saying it is possible. But, I cannot find the actual solution.
With investigation, I have realised that the #Local EJB does not register itself onto jndi (atleast according to the logs), if I use the glassfish JNDI browser, I also do not see it visible. So it makes sense to me, that either it's not possible, or the deployment of the EJB project is at fault, and somehow I need to expose it.
#Remote is a possibility, if it can be by reference, and no performance overhead. But the preferred method allowing #Local EJB access is really the ultimate need.
Does anyone know what I would need to do to expose the #Local EJB to another application?
Or is this plainly not possible?
I am using Glassfish 2.1 With EJB 3.0
If Glassfish 2.1 can handle EJB 3.1 I would be willing to move to it if it provided this capability, but I doubt it's that easy.
Please assist.
Thank you.
I am adding a bounty. To complete the bounty, it would be required to run 2 ear applications in the same domain, where A.ear contains an #Local EJB that is used as well by the application in a B.ear.

The link #Peter gave you almost solves your problem. (link)
One trick which needs to be done to solve #Xavier's problem is to provide common.jar to both ears in the same version (loaded by the same class loader). If you do it, the class cast exception will not be thrown and you will be able to use the ejb with local interface.
To do it you need to put common.jar into glassfish/domains/domain1/lib folder (substitute domain1 with you domain name). This way this jar will be loaded by a Glassfish's shared class loader.
I made a quick test with Eclipse and Glassfish 3 with following structure:
package com.example;
JarShared
- #Local class Server
EarServer
- EjbServer
- #Stateless class ServerBean implements Server
EarClient
- EjbClient
- #Stateless #LocalBean class ClientBean
Lookup from ClientBean:
InitialContext ic = new InitialContext();
Server server = (Server) ic.
lookup("java:global/EarServer/EjbServer/ServerBean!com.example.Server");
I did not get ClassCastException and I could call sample method from ServerBean.
Important notes:
both EarServer and EarClient should not contain JarShared in lib folder, they should reuse the one which is in domains lib folder
remember to restart Glassfish after adding JarShared to it.
to make both ejb projects compile you must add JarShared to their build paths, but nothing more
If you have questions, post a comment.

Related

How to control module loading order in Liberty profile

I have an ear file with a web module and a ejb module(just used for message driven beans). The ejb module has dependency on web module and it's classes. I would need to load the web module first and then ejb module. But the liberty always loading the ejb module first causing com.ibm.ws.container.service.state.StateChangeException: java.lang.NoClassDefFoundError:
How to control the order of modules loading within the same ear file? On traditional webshpere there is an option called 'Starting weight'. Whichever module has lowest value takes precedence and loads it first. so the application works good on tradition Websphere. However, this property seems missing on Liberty. I already looked at this. It only talks about deploying the multiple war files and their order.
If your EJB module depends on Web, that is bad design. It should be the other way around.
If you have such situation , proper way would be to extract shared classes in to a common jar file, let say mycommon.jar and then put that into ear\lib folder. In this way they will be visible by both modules ejb and web.
If your EJB module depends on the javax web api (e.g. servletRequest) that is even worse, and you should redesign such classes to POJO DTOs.
As a last resort you could try what is described here and add <initialize-in-order>true</initialize-in-order> in your application.xml.
FRowe's solution will not work, as classes are not shared between the applications, so changing load order of apps will not help. Each Java™ EE application has its own class loader in a running Liberty server.
Consider using the ability to control app start order as described here: https://www.openliberty.io/blog/2020/06/05/graphql-open-liberty-20006.html?_ga=2.4728563.17466047.1620833568-1423690488.1614284842&cm_mc_uid=99965752544816136653536&cm_mc_sid_50200000=61078141620909829332#ORDER
You'll have to deploy the war module as an app instead of packaging it within the ear, but you should be able to achieve the proper ordering.

class casting of runtime added classes

I'm having a problem I simply can't get my head around.
I'm creating a jsf application where I (as administrator) can upload a jar file, and that way around update the application.
Through this tutorial: http://docs.oracle.com/javase/tutorial/deployment/jar/jarclassloader.html I have managed to classload the jar file. The first issue is that I can only class load as "Object" and not cast to an other class type. I get a ClassCastException.
JarClassLoader jcl=new JarClassLoader(url);
Class cl= jcl.retreiveClass(jcl.getMainClassName());
Object ob=cl.newInstance(); //I would like to make this a RouteBuilder object instead of Object
Concretely I'm using Apache Camel, where I can add routes to an existing "core" (CamelContext). What's happening is that I have the core of apache camel running in my web app, and I can then add routes runtime. It's a route I want to package as a jar and load into the app runtime (I want to develop and test the route in my local environment, and then afterwords upload it to the production application). A concrete route is just a simple java class that extends RouteBuilder. I want to upload the jar, classLoad (URLClassLoader) the main class (maybe the whole jar? - does that make sense?), and convert it to a RouteBuilder. This seems to be impossible. I have chosen to upload the jar file to a folder outside my war, so that the routes do not get erased when I restart the webapp (is this smart or should this be done in an other way?). Is that a problem regarding name spaces? Furthermore, I haven't been able to find out whether I need to traverse my entire jar file and classload ever single class inside. Any comments on that?
To me it seems like I have some fundamental misconceptions on how extending / updating a java application is done. I simply can't find any good examples/explanations on how to solve my problem and therefore I conclude that I don't get this on a conceptual level.
Could someone elaborate on how to extend a running jsf application (I guess the same issues are relevant in native java apps), explain how to upload and class load a jar at runtime, and how to cast loaded classes to other class types than Object?
Thanks
Lasse
If you are interested in loading Routes without stopping your application you could consider using an OSGi container like Karaf. Karaf provides support for Apache Camel routes out-of-the-box: http://camel.apache.org/karaf.html
All class loading is managed by the OSGi container and you just need to run some commands to update things. I am not sure if this could work with your JSF application but it worths to take a look.

Eclipse Java EE project and Spring : classnotfoundexception

I am trying to build an project in Eclipse (actually I'm using RAD, so basically eclipse, and when I say 'Java EE Project' I mean an 'Enterprise Application Project').
My Enterprise Application Project (the 'EAR' project) has two module projects :
- service
- web
The service project has some stuff in it, all wired up using Spring.
The web project has its own stuff in it, all wired up using Spring. The UI stuff in the web project needs to use the stuff in the service project.
Both projects are included in the EAR project as modules.
The web project lists the 'service' project as a dependent project in the build path, it's checked off for export, and also has it listed as a EE Module Dependency.
I'm having a really hard time to get this working though:
The spring context in the web project is of course what gets loaded when the application is deployed, and it imports the spring config I need from the service project. This seems to be working fine.
When spring tries to instantiate a bean it throws a ClassNotFoundException. On the very first bean.
I tried simply copying the spring config from my service context and pasting it into my web context, but I got the same ClassNotFoundException.
I have tried instantiating an object of that type (the class that spring says cannot be found) in the java controller class in the web project, and it is successful, both at compile time (no compile errors) and at runtime (no exceptions).
So the classes from my service project are not available on the classpath when spring tries to use them.
Any ideas what's going on here and/or what I might be able to do about it?
There is a class loader policy that you should use ParentClass First . That will be managed either through Application.xml or through web.xml . You need to check your xml's then try.
It's a class loader issue.
Since you're using Spring, I'll assume that you don't have EJBs. If that's the case, why do you need an EAR? Deploy the whole thing as a web project, in a single WAR.
Put all your .class and Spring configuration .xml files in WEB-INF/classes. Load the configuration using org.springframework.web.context.ContextLoaderListener.
I seem to have fixed this - I'm not sure exactly what the problem was but there must have been a small typo in my spring config. I decided to just start fresh with a new spring config and when I started building the new one back up things were working fine. There must have been a problem with the old one.
Thanks for the suggestions though.
Unfortunately we're not always able to change project structure. We're working on structures other people have put in place.
I looked into the ParentClassFirst vs ParentClassLast setting - it seems on websphere the ParentClassFirst setting is the default if you don't specify anything, so I'm leaving it without specification to get that functionality.
http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/crun_classload.html

Different EARs using common services. Should I use remote calls, or package them as local?

I have multiple EJB3 ears deployed on jboss server. One of them is an application containing common services exposed as remote. Now all other ears use those services via remote and it seems to be realy painful for performance.
What can i do to overcome this? Can I make those services #Local and package this jar to every single application to allow them to be used via #Local not #Remote?
According to the JavaEE tutorial, the client of a #Local bean "must run in the same JVM as the enterprise bean it accesses."
So you should have no problem using local calls between different deployed applications on the same server.
Are you sure this is the cause of your performance problems, though?
I agree with you, you cannot inject an ejb session bean from another ear and in the same jvm using local interface.
if you have two ear you must use the remote interface, and using:
#EJB(lookup ="JNDI_BEAN_NAME")
I disagree. See this thread as it provides an excellent description of why you shouldn't: http://www.coderanch.com/t/79249/Websphere/Local-EJB-calls-separate-ear
The only way, normally, to make local calls between ears is to make cross-classloader calls. Not pretty.
You can get around this by having a single classloader per server (versus scoped by ear). Also a bad idea for security/isolation reasons.
You should use remote calls between ears. Some Java EE implementations optimize these calls to be more efficient when calling within the same jvm.

Glassfish 3 EJB3 rmi example

Can someone please provide me or link for sample project with standard java rmi capabilities. I wish to deploy it in Glassfish 3 and I have just about tried everything to get a simple project running, but Glassfish does not register my objects. I see that the there is a standard JMX RMI registered on statrup on port 8686 for glassfish. I haven't found any tutorials or examples on this that work. If possible in JAR archive, simple hello world which I can call externally.
Thanks in advance
Ok basically it came down to the following:
Created simple main class within the EJB project.
Stating the class should be fired upon startup of the war from the manifest does not work.
Added the annotation #Startup right above my class declaration.
Added the annotation #PostConstruct above my main method, this invoked my method at start up and registered the RMI service.

Resources