There is an application ABC which dependency is on an ejb module 'XYZ' but both are deployed & running on different server machine.
ABC deployed on JBoss AS & IP address is 192.108.1.1
XYZ deployed on JBOss As & IP address is 192.108.1.2
in XYZ ejb module, there is a xyzService class which access db and populates the data into a bean class, please see below
#Stateless(mappedName = "ejb/xyzService")
#TransactionManagement(TransactionManagementType.BEAN)
public class XyzService extends XyzPersistenceService implements xyzRemote, xyzLocal {
public List<xyzBean> fetchDataFromDB (List<String> idList) throws Exception
{
List<xyzBean> detailList = null;
try {
// gets data from DB and populate into a bean class i.e. xyzBean
} catch (Exception e) {
new myExceptionClass("error", e);
}
return detailList;
}
}
//Bean class
public class xyzBean{
String Id;
String name;
// getter-setter here
}
Now i want,
1. lookup the object of service class of XYZ module
2. invoke the method
3. gets the list of bean class
Could you please guide me how to do that, while i am bit confused how to start doing this from my ABC application ?
This example is geared towards connecting to the XYZ bean, but you could easily use it with a little adjustment for the ABC bean. Anyway, here is how you can lookup your xyzService.
Explicitly
By #EJB annotation
By ejb-ref
Explicitly
// Lookup the EJB from JNDI
InitialContext ctx = new InitialContext();
xyzRemote remoteobj = (xyzRemote)ctx.lookup("ejb/xyzService");
By annotation
#EJB (mappedName="ejb/xyzService")
private xyzRemote remoteobj;
With annotation the container injects an instance of the remote EJB bean through DI.
By ejb-ref
In your client class, add the below code. This is only a
InitialContext ctx = new InitialContext();
xyzRemote remoteobj = (xyzRemote) ctx.lookup("java:comp/env/ejb/xyzService");
As for configuring your client's InitialContext, you'll need a jndi.properties file
### JBossNS properties
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=jnp://192.108.1.2:1099
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
Related
I have a class A as a bean.
public class A
{
// constructors
// properties
// getters and setters
}
Spring boot configuration:
#Configuration
public class AConfig{
#Bean
#Scope(scopeName = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public A getA() {
return new A();
}
}
I am working right now with WebSocket and I am trying to get a new class A instance for some specific WebSocket channels, let's say if I am working with WebSocket id:1 then I will have the instance of A (some address) for that WebSocket, and for the WebSocket id:2 I will have another instance of A (some other address), and I can have it across application. How can I achieve that? In this case, I guess I have to send some ID to the server to identify the spring bean I am looking for.
**Instead of Autowired we should use Constructor arguments to make it loosely coupled **
class MessageSocketDemo {
private A a;
public MessageSocketDemo(A a) {
this.a = a;
}
public MessageSocketDemo() {
a = new A("address");
}
}
class A {
String address;
public A(String add) {
address = add;
}
}
So when you create object of MessageSocketDemo you create object of A every time new.
Or make the Scope of A as prototype or request which will create it new every time it is asked, and a lookup method to create instance of A
I am using wildfly 10.
For some reason I've got error like this:
javax.naming.NameNotFoundException: ServiceAImpl-- service jboss.naming.context.java.global.ServiceAImpl: javax.naming.NameNotFoundException: ServiceAImpl -- service
The way that I access to jndi:
InitialContext initialContext = new InitialContext();
Context context = (Context) initialContext.lookup("java:global/");
IWorker worker = (IWorker) context.lookup("ServiceAImpl");
worker.createTimer(task);
rest of code:
public interface IWorker{
void createTimer(ExecutableTask aExecutableTask);
}
#Stateless
#Local(IServiceA.class)
public class IServiceAImpl
implements IServiceA {
#Override
public void createTimer(ExecutableTask aExecutableTask) {
System.out.println("I am doing some jobs");
}
}
#Local
public interface IServiceAextends IWorker{
}
How can I get access to this IWorker? How to get this JNDI?
Take a look here. You are going to find something similar to this in your Wildfly logs when it is starting.
java:global/<your-project>/bus-facade-fumo/WUFFacade!<your-project>.wuf.WUFFacadeRemote
java:app/bus-facade-<your-project>/WUFFacade!<your-project>.wuf.WUFFacadeRemote
java:module/WUFFacade!<your-project>.wuf.WUFFacadeRemote
java:jboss/exported/<your-project>/bus-facade-<your-project>/WUFFacade!<your-project>.wuf.WUFFacadeRemote
java:global/<your-project>/bus-facade-<your-project>/WUFFacade
java:app/bus-facade-<your-project>/WUFFacade
java:module/WUFFacade
So you can find the JNDIs you need in your console logs, just like the example above. In you case, you are almost there, but you have to complete this piece of code with the complete information:
Context context = (Context) initialContext.lookup("java:global/<HereYouNeedMoreInformation>");
Following is my Sample Code:
AddStatelessBean.java:
#Stateless(name = "AddStatelessBean", mappedName="ASBean")
#Remote(AddStatelessBean.class)
#LocalBean
public class AddStatelessBeanImpl implements AddStatelessBean {
public int add(int a, int b) {
return a + b;
}
}
My Calling Code:
CallAddBean.java:
public static AddStatelessBean getAsbByName() throws Exception {
Context initialContext = new InitialContext();
AddStatelessBean asbObj = (AddStatelessBean) initialContext.lookup("ASBean");
return asbObj;
}
But I get the following error:
javax.naming.NameNotFoundException: Context: VRDWIN7WAS9Node03Cell/nodes/VRDWIN7WAS9Node03/servers/server1, name: ASBean: First component in name ASBean not found. [Root exception is org.omg.CosNaming.NamingContextPackage.NotFound: IDL:omg.org/CosNaming/NamingContext/NotFound:1.0]
BUT, if I go to Websphere Admin Console -> Applications -> Websphere Enterprise Applications -> -> EJB JNDI Names and assign the same JNDI name there and try to lookup, it is working.
I don't want to do that extra step or configure any XMLs (ibm-ejb-jar-bnd.xml) for making that happen during App Deployment itself.
How do I make this binding from pure JAVA Code itself? My main motive is to make my code run Server independent.
The Scenario goes as follows :
i'm coding a java enterprise application
first i created entity classes from database table "Derby" then i made a helper classes in a java library project then i created a session bean in the enterprise application bean and created a bean facade remote in the java library project
here is the important code part of the session bean :
#Stateless(mappedName = "officefacade")
public class OfficeFacade implements OwnerFacadeRemote {
#PersistenceContext
private EntityManager em;
and then i coded a simple client to test the methods
client code :
public class Client {
private OwnerFacadeRemote request;
public static void main(String[] args) {
// TODO code application logic here
Client x = new Client();
}
public Object getEJBBean(String beanName)
{
try
{
InitialContext ctx = new InitialContext();
return ctx.lookup(beanName);
}
catch(Exception ex)
{
System.err.println("Error : " + ex.getMessage() + "\n\n\n");
}
return null;
}
private void insert()
{
request.createOwner(new OwnerDetails("1","M","444","M","afcdv"));
}
private void display()
{
List<OwnerDetails> xx = request.getAllOwner();
}
public Client()
{
request = (OwnerFacadeRemote) getEJBBean("officefacade");
insert();
display();
}
the problem is every time i run the client i get the error that Lookup failed for 'officefacade'
here is the complete error text
> Error : Lookup failed for 'officefacade' in SerialContext[myEnv{java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFac tory, java.naming.factory.url.pkgs=com.sun.enterprise.naming, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl}
how to make sure the mapped name is being available and how to fix it so the it can be found by the lookup even if it means hard coding the mapped name in the serial context "i don't know what this is but it seem as the problem is coming from it"
any help is much appreciated and thanks in advance for your efforts and i'm pretty sure everything is implemented correctly so it's a mapped name related problem
tools of development is netbeans 8.0.2 and glassfish 4.1
Try to replace #Stateless(mappedName = "officefacade") with #Stateless(name = "officefacade"), the lookup method of the InitialContext seems to work with the bean name
See the related JavaDoc section and the related method for more details
UPDATE
Just checked Oracle's documentation on this topic - according to the information available there you might need to actually lookup for "java:module/officefacade" instead of pure "officefacade", depending on the bean context.
I'm trying to create an EJB factory class, which works like this: You have a method which takes as argument a class of an EJB, then it checks whether the EJB has a remote interface (if not throw an exception) and if it does, it returns the concerning EJB.
The code below does exactly this. However the object it returns is of the type of the remote interface of the concerning bean and not of the bean itself. How can I change this? Is there a way to tell Java that the generic type T is of the same type as the class passed to the methods.
import java.util.Properties;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.naming.*;
public class EJBFactory
{
private InitialContext ctx;
public EJBFactory() throws NamingException {
ctx = new InitialContext();
}
public EJBFactory(String host, String port) throws NamingException {
Properties props = new Properties();
props.setProperty("org.omg.CORBA.ORBInitialHost", host);
props.setProperty("org.omg.CORBA.ORBInitialPort", port);
ctx = new InitialContext(props);
}
.
// To improve: The object returned should be of the type ejbClass
// instead of the remote interface, which it implements
public <T> T createEJB(Class ejbClass) throws NamingException
{
Class remoteInterface = null;
for(Class interface_: ejbClass.getInterfaces()) {
if(interface_.isAnnotationPresent(Remote.class))
remoteInterface = interface_;
}
if(remoteInterface == null)
throw new IllegalArgumentException(
"EJB Requires a remote interface");
// Get the stateless annotation, then get the jndiName
Stateless stateless =
(Stateless)ejbClass.getAnnotation(Stateless.class);
String jndiName = stateless.mappedName();
T ejbObj = (T) ctx.lookup(jndiName);
return ejbObj;
}
}
Example of a unit test which uses the Factory.
import junit.framework.TestCase;
public class SimpleEJBTest extends TestCase
{
TestRemote testBean;
#Override
protected void setUp() throws Exception {
super.setUp();
EJBFactory ejbFactory = new EJBFactory();
testBean = ejbFactory.createEJB(TestBean.class);
}
public void testSayHello() {
assertEquals("Hello", testBean.sayHello());
}
}
Note: The example works with Glassfish, I didn't test it with any other app server.
Clients of EJBs interact with them through the local/ remote interface that the EJBs implement. Client applications never have direct access to an actual session bean class instance. This is done to make instance pooling possible, where the container can reuse EJB instances to service different requests.
I'm not sure why you need to access the actual bean's object (since obviously I dont know your requirement). But if you still need to create an instance of that you can do it as follows using reflection Class.forName(className).newInstance(); Again the instance that you create like this is not an EJB. It is just a POJO thats all.
EDIT - after your comment regarding junit testing: When you access business methods from a JavaSE as follows, you are actually calling the methods in the EJB - just that you interact thru the interface. So if you want to test any business methods you can still do it from an object got thru a JNDI lookup in a Junit test.
//MyGreatBean implements MyGreat. MyGreat has #Remote, MyGreatBean has #Stateless
ref = jndiContext.lookup("MyGreatBean/remote");
MyGreat bean = (MyGreat) ref;
String retValue = bean.businessMethod();
assertEquals("Success", retValue);
From an earlier comment, I get a feeling you want to check what kind of annotations have been added to the actual EJB class - if you want to do that kind of checking without actually running the business methods, you can create an instance using Class.forName... like I mentioned above. When you create an instance like this you can only call methods that don't do any "Java EE" stuff. For example you can call a method in the EJB class that is as follows
public String someMethod(){
return "I am a POJO but I look like an EJB";
}
I do not think that you can get the EJB object. You can only get the interface. The createEJB should be called with the interface and it returns the interface.
try replacing
public <T> T createEJB(Class ejbClass) throws NamingException
with
public <T> T createEJB(Class<T> ejbClass) throws NamingException
Can you try this?
Create a interface. Make it have #Remote. Your ejb that is annotated with #Stateless should implement the above created interface. Now try to do the same thing that you are doing I think it should give you the desired result. Typing it down here without copying from an ide so excuse any errors. But you should get the drift I guess.
#Remote
public interface Example{
String some();
}
#stateless
public class ExampleBean implements Example{
}