Invoking EJB 3.1 session Bean using remote standalone client - java

Although I have used EJB earlier, I want to re-assure myself that I understand how it really works.
So, I created a Simple Session Bean EJB (3.1), and packaged it as .ear (which has client jar as well). The below is the snippet:
Session Bean Implementation:
package com.example;
import javax.ejb.Stateless;
#Stateless
public class FirstSessionEJB implements FirstSessionEJBRemote {
public FirstSessionEJB() {
}
#Override
public String print() {
return "Hello";
}
}
Remote interface:
package com.example;
import javax.ejb.Remote;
#Remote
public interface FirstSessionEJBRemote {
public String print();
}
I deployed this EJB as .ear and it was successfully deployed in Wildfly 10.x.
Now, I want to access this using a standalone Java client, running in a separate JVM.
Here is the client code (It might not be completed as I am not clear on how to invoke mainly due to JNDI).
package com.example.main;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.example.FirstSessionEJBRemote;
public class Main {
public static void main(String[] args) throws NamingException {
String GLOBAL_JNDI_NAME="java:global/FirstEJBProjEAR/FirstEJBProj/FirstSessionEJB!com.example.FirstSessionEJBRemote";
Hashtable<String,String> jndiProperties = new Hashtable<>();
jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
InitialContext ic = new InitialContext(jndiProperties);
FirstSessionEJBRemote ejbRemote = null;
ejbRemote = (FirstSessionEJBRemote)ic.lookup(GLOBAL_JNDI_NAME);
ejbRemote.print();
}
}
I referred to this link on how to do the JNDI lookup (and what all parameters to use in, however it is not working.)
In the link it is mentioned that it has Wildfly specific jar which works without JNDI lookup.
Can anyone help me understand:
1) What all properties I need to set up for JNDI look up?
2) Is there any specific jar that needs to be present in client side application?
I don't want to use any specific Wildfly jar, that is, I want to go with traditional JNDI lookup, so can anyone please guide me on this?
It is very frustrating to struggle just to write a simple "Hello world" kind of EJB. I referred to some books are well, but all what they have provided is just the "lookup" code without actually telling what all properties needs to be included for JNDI and any jar to be included.

As the article you link to states albeit a bit hidden in that mountain of text, you do need the jboss-client.jar that you will find in the Wildfly server installation (bin/client/jboss-client.jar); it needs to be on the client's runtime classpath. It contains to begin with that org.jboss.ejb.client.naming package referenced in your code.
The jar contains the extra bit of magic for a client to be able to setup and maintain EJB remote invocations with the Wildfly server, just using JNDI isn't going to cut it. And there is no one jar to rule them all, each container (Wildfly, Glassfish, Weblogic, etc.) has its own implementation for a client library.
Do note that invoking EJBs from a client application is very old school (read: you don't want to do that). A more realistic and modern day view of EJB technology is to use it within an enterprise container itself, such as from a web application / war - say as part of a RESTful service. You likely don't even need the extra layer of the EAR file then, you can just package everything neatly into the one war application.
And in that scenario if you do have a client application, that client can talk to the RESTful service - a much simpler and cross-server, cross-platform communications interface.

Related

Jakarta EE 10 #Startup on K8S

Stack
Java
Jakarta EE 10
JBoss/Widlfly 27
Kubernetes K8S
JAX-RS (RestEasy)
I want to initialize some caches on startup of my app. During that time i want my readiness probe to respond not ready.
With the management inteface turned on, this works BUT not with my classes, instead the standard one responds.
Wildfly runs in standalone mode.
What i try to accomplish is to run my OWN code for readiness/live BUT that these endpoints are available during startup. I created my own outside of microprofile.healt but they are not available during startup.
Does anybody have some ideas?
Below is my code
import jakarta.enterprise.context.ApplicationScoped;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;
import org.eclipse.microprofile.health.Liveness;
import org.eclipse.microprofile.health.Readiness;
/**
* Created by Gerry Askefalk on: 2023-01-13
*/
#ApplicationScoped
#Liveness
#Readiness
public class Mycheck implements HealthCheck {
#Override
public HealthCheckResponse call() {
return HealthCheckResponse.named("mycheck").up().build();
}
}
Ok
the solution (and my bad) was to not add microprofile extensions to WF.
When i did, it works!
This article explained it to me.
microprofile on wf

Inject of remote EJB interface into external module

I have an EAR application with three modules:
beans are in "app-ejb" module
remote interfaces are in "app-remote"
web services are in "app-war"
app-ejb and app-war use app-remote as library.
all are packaged in "app.ear".
This is working fine, but now I have to use the same beans outside the EAR application, and injection is not working.
I have in app-ejb:
#Stateless
#LocalBean
public class Services implements ServicesRemote {
[...]
}
and his remote interface in app-remote:
#Remote
public interface ServicesRemote {
[...]
}
In my app-war I can inject the remote bean without problem:
#Stateless
#LocalBean
public class UseServices {
#EJB
private ServicesRemote services;
[...]
}
Anyway in my external ejb application, deployed as stand-alone and using the same ejb-remote as library, if I try to inject the same EJB like this:
#Stateless
#LocalBean
public class UseServicesFromAnotherApp {
#EJB
private ServicesRemote services;
[...]
}
Glassfish (4.1) give me an error "Class [ Lcom/[...]/ServicesRemote; ] not found".
Is this expected? How can I inject the remote bean correctly?
Injection doesn't work with remote interfaces. Beans that are "injectable", live inside container's JVM and are available for injection to other beans inside the same application. The same holds true for accessing beans in another application in the same container, although applications may live in the same JVM. Since remote methods are originated from another JVM or another application, injection is not possible. You must use JNDI lookup instead to get a reference to a remote bean.
As a matter or personal taste, I would stay away from EJB Remote interfaces, and instead I would use another "remoting" technique such as REST.
The problem was probably generated by a number of hot deploys, made glassfish unstable.
When I restarted glassfish my code start to work properly (it's actually still working).
Sorry for posting here without trying to restart glassfish first.

Understanding of embeddable EJBContainer

I spent some time in attempts to understand Embeddable Enterprise Bean Applications and still need some clarifications. Assume I need Junit to test EJB application.
So I have assumptions what should happened, please help me figure out correct answer:
Junit is entrypoint and it deploys EJB application to server? So that EJB and Jboss are "embedded" into tests.
Junit and 'EJB' application are two separate JVM processes and they somehow communicate by jndi names or something(I don't use remote EJB).
Real server(JBoss) never used and EJBContainer is just kind of Mock.
Something else.
Edited:
I found an example:
Could you please comment on this code:
#Test
public void test() throws Exception {
String jbossHomeDir = "E:\\dev_station\\java_station\\Serveurs\\jboss-as-7.1.1.Final";
System.setProperty("jboss.home.dir", jbossHomeDir);
StandaloneServer server = EmbeddedServerFactory.create(new File(
jbossHomeDir), System.getProperties(), System.getenv(),
"org.jboss.logmanager");
server.start();
server.deploy(new File("target/classes"));
Context namingContext = server.getContext();
}
The Java EE 6 Tutorial (that first link in the question) says that
The embedded container, the enterprise bean components, and the client all are executed in the same virtual machine using the same classpath.
That is, the JUnit test ("client"), the embedded container (implemented by JBoss Wildfly, Glassfish, etc.), and the Java EE application components (EJBs, etc.) all run in the same JVM instance (the same process).
Nothing is mocked. Container services (transactions, injection, etc.) are provided by an actual Java EE server implementation.
So, the correct alternative between those four listed in the question is number 1.

EJB Injection in Application Client don't work

I tried inject a stateless EJB in my application client and I get the following error
SEVERE: Exception while preparing the app : Unable to load the EJB module. DeploymentContext does not contain any EJB. Check the archive to ensure correct packaging for C:\glassfish3\glassfish\domains\domain1\applications\EJB.
If you use EJB component annotations to define the EJB, and an ejb or web deployment descriptor is also used, please make sure that the deployment descriptor references a Java EE 5 or higher version schema, and that the metadata-complete attribute is not set to true, so the component annotations can be processed as expected
My client is defined thus:
#EJB
private static Sless sless;
public static void main(String[] args) {
System.out.println("Sless says: " + sless.hello());
}
The class Sless is my interface which is defined thus:
#Remote
public interface Sless {
public String hello();
}
I also have a class implementing Sless
#Stateless
public class SlessBean implements Sless{
#Override
public String hello() {
return "hello, world!\n";
}
}
Any help as to where the problem is coming from would be appreciated.
1) Standalone clients or non-managed POJOs(POJOs which are not maintained by Containers) do not support annotation injection. So #EJB will not work.
2) You will have to do a manual JNDI look up from your standalone client.
What you need for this ?
1) Your EJB extending Remote interface. Because Local interface does not expose EJB to Cross Application or Remote calls.
2) Dependency jar files in your standalone client. ie: ORB Jar
3) You will need to know RMI/IIOP port on your server.
4) You will also have to take care if Standalone client and Server use different JDK/JRE implementations. For ex: 1 using SUN JDK and other using IBM JDK.
Follow this for connecting to EJB on Glassfish from a Standalone client >> https://glassfish.java.net/javaee5/ejb/EJB_FAQ.html#StandaloneRemoteEJB

New to EJB world... Null pointer exception in EJB client

I am learning EJB and I am trying to execute the Helloworld example given in EJB In Action book.
My app server is JBoss, I created the Jar file for the bean class and interface in the right directory( I can see the EJB in JMX console).
Now I created a simple client using EJB annotations, but I am getting a NullPointerException.
Here is my client code.
Client code:
package com.client;
import javax.ejb.EJB;
import com.EJB.*;
public class HelloWorldClient {
#EJB
private static HelloWorldInterface HelloBean;
public static void main(String[] args)
{
HelloBean.SayHelloWorldInEJB();
}
}
Bean class
package com.EJB;
import javax.ejb.Stateless;
#Stateless
public class HelloWorldBean implements HelloWorldInterface {
public void SayHelloWorldInEJB() {
// TODO Auto-generated method stub
System.out.println("Hello world from the world of EJB");
}
}
Interface
package com.EJB;
import javax.ejb.Local;;
#Local
public interface HelloWorldInterface {
public void SayHelloWorldInEJB();
}
Note: I tried using specifying the interface as Remote, it still didn't work.
Steps that I did so far to get to this point.
1) Created the file EJB files
2) Made the build.xml and deployed the EJB.
Am I missing any configuration files ???
Now I created a simple client using EJB annotations, but I am getting a NullPointerException.
Your client code looks like an Application Client and such client is supposed to be deployed on the app server and then executed in an Application Client Container (ACC) so that injection can occur. Starting the ACC requires an application server specific command.
The following wiki explains the usage of the ACC in JBoss (how to package, deploy and launch an ACC): How to use an application client in JBoss-5.
If you don't want to use an Application Client Container and instead just run the application client class through a java command, injection won't be possible and you'll have to perform a JNDI lookup.
And in both cases, you'll have to provide and use a remote business interface for your bean.
Resources
How to use an application client in JBoss-5
Creating and Running an Application Client on the GlassFish Server
Related questions
application-client
You would have to make two changes:
Replace the #EJB dependency injection with JNDI lookup. Dependency Injection is not supported for POJOs in EJB 3 (Don't know about EJB 3.1 though )
Then, the interface has to be a remote interface. The reason is that, the client here is a standalone java program - It would be running in JVM different from the web-app JVM.
Both dependency injection through #EJB and having the interface as #Local should work if the client was a servlet in the same server.

Categories