Can I add a JNDI Binding with a customized name for inject a Stateless Bean on my client Servlet? - servlets

In one hand, I have a Stateless EJB Bean which implements a remote interface.
#Stateless(name = "ejbBean")
#Remote(TimedBean.class)
public class TimedBeanImpl implements TimedBean
...
On the other hand, I have a Servlet client where I need to inject this EJB bean for invoking its operations. The injection referts to a JNDI automatically generated by the server:
public class LoadTimer implements ServletContextListener {
// EAR Local Mapping - EAR Dev Mapping
// #EJB(mappedName = "java:global/appTest/appTestModuleOne-01.00.00/ejbBean")
#EJB(mappedName = "java:global/appTest-01.00.00/appTestModuleOne-01.00.00/ejbBean")
private TimedBean timedBean;
#Override
public void contextInitialized(ServletContextEvent servletcontextevent) {
...
It works.
But the fact of referencing the jndi automatically generated makes the solution highly dependent on the specific environment:
It depends on the server. For example, my local server for testing it's a JBOSS 7.1 and my dev server it's a JBOSS EAP 6.2, and the automatically generated jndi's are different.
It depends on the packaging. Not is the same refers to the ejbBean deploying in a EAR file than in a WAR file.
And it depends on the version of artifacts. More changes.
I want, if possible, is to specify a unique name for the bean can be referred to the servlet in each server, for each version and packaging, in order not to have to be making continuous changes in development and avoid errors in deployments.
Greetings!

You can use <application-name> in application.xml and <module-name> in your module descriptor (web.xml or ejb-jar.xml) to mitigate the hardcoded version numbers. (Note that as of EE 6, you should use #EJB(lookup="...") rather mappedName.) The spec also requires that your application server give you an option to override the lookup name of the #EJB reference while deploying the application, so it should not matter what is hardcoded in your application at development time.

Related

Global module with ejbs

I deployed a global module with remote ejbs defined, but I can't access them from deployed applications.
Here is the interface:
#Remote
public interface ICryptoAPI..
and bean definition:
#Stateless
public class CryptoAPI implements ICryptoAPI ...
How can I find jndi name of the ejbs deployed, since default #Ejb cannot find bean? Just to mention, /subsystem=naming:jndi-view() from jboss-cli doesn't print anything about deployed module and there are no errors in wildfly log.
Maybe, it is not possible to define injectable ejbs in global modules?
The portable JNDI name, an EJB is bound to, depends on how beans are deployed and some configurations (e.g. deployment descriptors).
In addition to the portable JNDI name, JBoss provides access from a remote VM within the java:jboss/exported namespace.
For your convenience, JBoss' default logging shows the JNDI names, an EJB is bound to, on console and in the server logfile upon deployment. The logger is org.jboss.as.ejb3.deployment on INFO level.
Example:
12:00:00,000 INFO [org.jboss.as.ejb3.deployment] (MSC service thread 1-6) WFLYEJB0473: JNDI bindings for session bean named 'MyBean' in deployment unit 'subdeployment "my-beans.jar" of deployment "my-app.ear"' are as follows:
java:global/my-app/my-beans/MyBean!my.package.MyBeanRemote
java:app/my-beans/MyBean!my.package.MyBeanRemote
java:module/MyBean!my.package.MyBeanRemote
java:jboss/exported/my-app/my-beans/MyBean!my.package.MyBeanRemote
For accesing the EJB, you can do a manual JNDI lookup or use the #EJB annotations lookup method for injection.

websphere liberty 8.5.5.9 remote ejb lookup fails

I have created two liberty instances on my local machine. I deployed a war module which contains a remote ejb in server X and deployed another war in server Y which has to remote lookup the ejb from server X.
Below is the code to lookup the ejb from a restful webservice.
Properties p = new Properties();
p.setProperty("java.naming.provider.url", "corbaname:iiop:localhost:2809");
InitialContext context = new InitialContext (p);
context.lookup("corbaname:rir:#ejb/global/caching/CachingServiceBean!com%5c.ejb%5c.CachingService");
When I try to call the web service I get below exception
DII operation not supported by local object
P.S.
I have enabled ejbRemote feature on both the servers with different port numbers.
I changed my lookup string to "corbaloc:iiop:localhost:2809/NameService#ejb/global/caching/CachingServiceBean!com%5c.ejb%5c.CachingService" and then I get the below error
Then I changed my lookup string to "corbaname:iiop:localhost:2809/NameService#ejb/global/caching/CachingServiceBean!com%5c.ejb%5c.CachingService" and then I got the below error
After checking apache geronimo-yoko implementation on GitHub, I understood that I have to use corbaloc:iiop:localhost:2809. But still I am getting exceptions caused by
org.omg.CORBA.OBJECT_NOT_EXIST: unable to dispatch - servant or POA not found
I used the following urls with no luck:
corbaloc:iiop:localhost:2809/global/caching/CachingServiceBean!com.ejb.CachingService
corbaloc:iiop:localhost:2809/#ejb/global/caching/CachingServiceBean!com.ejb.CachingService
3.corbaloc:iiop:localhost:2809/caching/CachingServiceBean!com.ejb.CachingService
4.corbaloc:iiop:localhost:2809/ejb/global/caching/CachingServiceBean!com.ejb.CachingService
I think the problem is with the packaging. I packed my ejb in a war module.
I followed the steps described in the PDF mentioned in this page http://www.redbooks.ibm.com/redpieces/abstracts/sg248076.html and everything is working now.
I used corbaname::host:port syntax to lookup the remote ejb instead of corbaloc:iiop:host:port
After packing my ejb in an ear then it started working.

Why does WebSphere create duplicate EJB environment entries?

I specified a String resource in an EJB with the #Resource annotation. The EJB is packaged within an EJB module. The ejb.jar has an ejb-jar.xml which specifies a default value for the String resource. The ejb.jar is packaged in an ear archive together with a web module.
When the ear is deployed to WebSphere, the Environment entries for EJB modules section shows three EJB entries:
The String resource I mapped for the ejb module;
The String resource I mapped for the ejb module, only this time it is called EJB_fully_qualified_name/resource_name;
The same fully qualified name of the resource but now mapped for the web module.
Unless I provide a default value for all the variants above the resource is not injected. If I add an ejb-jar.xml to the web module, WebSphere displays four entries (one simple name and one fully qualified name of the resource per module). Is this a WebSphere quirk or am I doing something wrong? I am using WebSphere 8.5.5.3 in a cluster environment.
Here is the bean:
#Singleton
#Startup
public class ConfigSingleton {
#Resource
private String serviceLookup;
}
Here is the ejb-jar.xml:
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>ConfigSingleton</ejb-name>
<env-entry>
<env-entry-name>serviceLookup</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>value</env-entry-value>
</env-entry>
</session>
</enterprise-beans>
</ejb-jar>
You have defined 2 completely different resources; either may be looked up.
Per the Java EE specifications, when you don't use the 'name' attribute of the #Resource annotation a default name is provided for you, which is the fully qualified class name where the annotation exists followed by the JavaBeans property name (which is basically either the name of the field, or the name of the method with 'set' removed and the next character in lowercase). The javadoc for the #Resource annotation is a little misleading as it just says the default is the field name; but does not clarify exactly what the field name is; it is in fact the class name followed by the field name, much like you would see if you printed out the java.lang.reflect.Field that would represent it.
When combining annotations and XML, the XML overrides the annotation only when the 'name' matches. In the sample provided, the names do not match, so you actually have 2 different resources.
If you want your <env-entry> in XML to override the #Resource annotation, so that you can inject a value, then you either need to change your annotation to look like this:
#Resource(name="serviceLookup")
Or change the <env-entry-name> to the fully qualified class name / serviceLookup.
Also, when the EJB module is included in a WAR modules things get a bit more complicated. Not the 'name' aspect, but where you can provide the value. In addition to providing a value in ejb-jar.xml, WebSphere also allows you to provide a value in ibm-ejb-jar-bnd.xml. However, when the EJB modules is in a WAR, then it may also be provided in ibm-web-bnd.xml... since all of the resources for all of the EJBs are visible in the java:comp/env name space for the entire WAR module. So, in the sample, you are getting two different names because of the defaults, and what appears to be two additional copies which are really just provided in case you want to override the values in ibm-web-bnd.xml.
I think what you're seeing here is the different JNDI namespaces:
https://docs.oracle.com/cd/E19798-01/821-1841/girgn/index.html
The resource value can be accessed from within the EJB module using the original name, but if it needs to be accessed from another module within the same application, it should give a JNDI path qualified by the module name, to ensure uniqueness (and traceability), and so on for other applications, and the global namespace.

Weblogic Stateless Session methods invoked from different cluster member servers

My environment is Weblogic 10.3.5 on Solaris box. EJB is version 3 and there is anotation in the Bean class. Sorry for the confusion as the code is new to me and they also have deployment descriptor to generate ejb2 client code for another client to call, so it's not straigtforward.
I have a stateless session bean deployed to a cluster which has 2 server members say they are member1 and member2.
The session bean is deployed as clusterable as this is in the anotation:
homeIsClusterable = Constants.Bool.TRUE
This is how my Stand alone Java client lookup and call the EJB methods:
private void testBean(){
bean.methodA();
bean.methodB();
}
In the provider URL I ONLY specify the provider URL to ONE server member:
env.put(Context.PROVIDER_URL, "t3://member1:7005");
env.lookup("remote#the.bean.qulified.remoteinterface")
The Jndi name above is using the "mapped name + qualified remote interface class name", the mapped name is defined in the anotation.
Now the problem is, I found out, bean.methodA() got invoked in member1, and methodB() got invoked on member2, I found this from the logs of each server member. So it's always like this, member1 log will only show debug information from methodA, and member2 will only show debug information from methodB.
So here is my conceptual question - is this possible at all ? Are the above 2 methods supposed to be called on member1 only ? I know it's possible when you lookup through home interface you could possibly get a bean from either server, but in this case the ejb3 lookup is not going through the home interface(like in ejb2 we get a home and then call create method) but directly getting a remote object.
This caused issue as our methodB has a dependancy on methodA(methodA is doing some cleanup job, and then method re-initialize the cache), we need to do this on each cluster member.
This is just extra info but please focus on the above question from a concept perspective.
From the documentation:
When home-is-clusterable is True, the EJB can be deployed from multiple WebLogic Servers in a cluster. Calls to the home stub are load-balanced between the servers on which this bean is deployed, and if a server hosting the bean is unreachable, the call automatically fails over to another server hosting the bean.
I believe this is the case even when you explicitly only connect to a single member. This has some pretty good info in the Replica-Aware Home section:
http://www.informit.com/articles/article.aspx?p=101737&seqNum=8
It's more or less the whole point of clustering... a cluster appears as if it's a single server instance to a client.

Calling EJB from war client

I have my application ear .Now inside this ear I have two parts .
First EJB module
Second Web Module packaged inside the war. So my Ear root looks like
EAR
---EJB Modules
---WAR Modules
Now I have a requirement to call one of the ejb from one of the war client. Is there any way other than remote EJB call to do the same.
#Named
#SessionScoped
public class WarManagedBean{
#EJB
private EjbBean ejbBean;
public void method(){
//Using of EJB
}
}

Resources