Lookup of same EJB on multiple servers - java

I am trying to do a lookup from one deployment to another deployment, using exactle the same bean implementations. It is basically a consumer/producer setup with the same beans in both deployments on both machines.
ear
ejb-api
com.example.bean
ConsumerBean
ProducerBean
ejb-jar
com.example.bean
ConsumerBeanRemote
ProducerBeanRemote
The ProducerBeanRemote should look up the ConsumerBeanRemote and call its public method.
Our machines are communicating like this:
(Machine A) ProducerBeanRemote --> (Machine B) ConsumerBeanRemote
(Machine A) ProducerBeanRemote --> (Machine C) ConsumerBeanRemote
(Machine A) ProducerBeanRemote --> (Machine D) ConsumerBeanRemote
You get the idea...
So the problem is, it doesn't work. I tried to do a manual lookup using the jboss-as-ejb-client libraries, which didn't work because JBoss locks the EJB selector while starting its container (AND I bet the spec has something to say about manual lookups in a Java EE environment). The next thing I tried was doing a lookup using the feature from Spring, to no avail.
We are using the JBoss Application Server 7.1.1.Final.
I bet there has to be a way to accomplish my setup and I would greatly appreciate any help from the community.
UPDATE:
To connect from ProducerBeanRemote to ConsumerBeanRemote, we need the possibility to specify the remote InitialContext at runtime via configuration.
Properties properties = new Properties();
properties.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
properties.put("remote.connections", "default");
properties.put("remote.connection.default.host", "remote-host");
properties.put("remote.connection.default.port", "4447");
properties.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");
EJBClientConfiguration ejbClientConfiguration = new PropertiesBasedEJBClientConfiguration(properties);
ContextSelector<EJBClientContext> ejbClientContextSelector = new ConfigBasedEJBClientContextSelector(ejbClientConfiguration);
EJBClientContext.setSelector(ejbClientContextSelector);
StatelessEJBLocator<T> locator = new StatelessEJBLocator<>(viewType, appName, moduleName, beanName, distinctName);
return EJBClient.createProxy(locator);
The resulting exception is
java.lang.SecurityException: EJB client context selector may not be changed at org.jboss.ejb.client.EJBClientContext.setSelector(EJBClientContext.java:181)
We understand that this exception is thrown because of https://issues.jboss.org/browse/AS7-2998, so the question remains: How can we remotely call the same beans in a clean and configurable way?

Nearly the same question as described here: JNDI lookup from one server to many configurable servers
It seems to be impossible to get a reliant connection between multiple servers via EJB, so we ended up using JMS for our server to server communication. Maybe thats an option for you, too.

You didn't tell me much about your setup or any errors you're getting so I can't really help you troubleshoot them. I just struggled through getting a remote ejb client to work as well and these resources were absolutely invaluable:
https://docs.jboss.org/author/display/AS72/EJB+invocations+from+a+remote+client+using+JNDI
https://docs.jboss.org/author/display/AS71/Remote+EJB+invocations+via+JNDI+-+EJB+client+API+or+remote-naming+project
http://blog.jonasbandi.net/2013/08/jboss-remote-ejb-invocation-unexpected.html#comment-form
http://www.mastertheboss.com/jboss-as-7/jboss-as-7-remote-ejb-client-tutorial/page-2
Good luck!

The setup is possible. There is no need to reengineer the whole code using JMS.
It is possible to call remote ejb beans on different JBOSSAS7 servers from a single POJO client using your own custom Selector for the EJBClientContext. With the code mentioned, you are able to register different scopes for different servers
See an example from the jboss developers here
https://community.jboss.org/thread/223419?tstart=0
https://github.com/wfink/jboss-as-quickstart/blob/ejb-clients/ejb-clients/jboss-api/src/main/java/org/jboss/as/quickstarts/ejb/clients/selector/CustomScopeEJBClientContextSelector.java

Related

Embedded Jetty 8 and configuration of JNDI MySQL connection pool with no XML

I have been searching a good while now, and I am not able to find any good tutorials or answers to this question.
In this project there are only one XML-file, pom.xml, the server is an embedded Jetty 8, with a programmatically defined ServletContextHandler that handles all the incoming requests. My point is, no WebAppContext or WAR-file(as it seems like all tutorials expect a WEB-INF, WebAppContext, web.xml, jetty-env.xml or WAR file).
I simply want to add a JNDI-datasource for pooling sql-connections programmatically in Java. Are there anyone that could point me to a good tutorial, or give some tips on how to achieve this?
You have chosen an embedded-jetty with its special ServletContextHandler without a complete web container (that's not meant to be criticism, just the path you have followed so far).
If this is your target environment as well, why do you need JNDI on top of this? Something has to provide the JNDI implementation. I would just add a connection pool like BoneCP, C3PO etc. and use it without JNDI.
On the other hand, if your target environment requires you to use a connection pool, you can always add your own method on top of both providers:
Pseudo code:
public class MyConnectionFactory
// To be replaced with a property lookup etc.
private boolean development = true;
public Connection getConnection(String jndiName)
if (development)
// get connection from BoneCP etc. (ignore jndiName)
else {
// lookup data source using JNDI, then get connection
and then in your source always use this method.

EJB calls EJB in WebLogic and OpenEJB

I want to write an application which has 2 EJBs. This application can run in both OpenEJB and WebLogic 10.3. Both of the EJB are EJB 3.0.
I know how to implement in both OpenEJB and WebLogic, but the problem is I want to use the same code to deploy to both environments. I think the problem is that how to do JNDI lookup, because WebLogic's Context.INITIAL_CONTEXT_FACTORY is weblogic.jndi.WLInitialContextFactory but OpenEJB is not.
Current idea is the 1st EJB use a service locator to lookup the 2nd EJB and the service locator will read different INI in 2 environments. Is there any other suggestion? Is there a solution I can just use annotation, no need to use external INI files.
The 2 EJBs live in one container, but it's possible one will be move to other container in the future.
Update on 2011/10/06
By David's suggestion, I put some change. The code is a POJO, not JUnit code. It doesn't use #LocalClient and initialContext.bind("inject", this); (I put the 2 code in my JUnit code)
Put resources\META-INF\application-client.xml (only contain )
Put resources\jndi.properties
jdbc/OrderDB = new://Resource?type=DataSource
jdbc/OrderDB.JdbcDriver = oracle.jdbc.OracleDriver
jdbc/OrderDB.JdbcUrl = jdbc:oracle:thin:#*.*.*.*:1521:test
jdbc/OrderDB.JtaManaged = false
jdbc/OrderDB.UserName = test
jdbc/OrderDB.Password = test
Lookup code
InitialContext ctx= new InitialContext();
ctx.lookup("jdbc/" + name);
The following is the log, OpenEJB creates the JNDI for the database. I also use Eclipse debug mode to see the content of "ctx" and find "jdbc/OrderDB" in MyProps
INFO - Configuring Service(id=jdbc/OrderDB, type=Resource, provider-id=Default JDBC Database)
But finally I still cannot lookup it. I also try to use ctx.lookup(name), ctx.lookup("java:comp/env/jdbc/" + name) and the result is the same.
javax.naming.NameNotFoundException: Name "jdbc/OrderDB" not found.
Update on 2011/10/12
Base on David's comment, before Java EE6, I think the only solution is to use a service locator and some configuration to use different JNDI between WebLogic and OpenEJB. The following is the test result.
DB: WebLogic: OrderDB, OpenEJB: openejb:Resource/jdbc/OrderDB
Transaction manager: WebLogic: javax.transaction.TransactionManager, OpenEJB: java:comp/TransactionManager
EJB: Both of them just lookup the EJB name without any prefix
The question in the update is a very different question, so posting a different answer.
No Global JNDI prior to Java EE 6
The long and short of it is that prior to Java EE 6, there is no global JNDI. So it is quite literally the case that the question "what is the JNDI name of x" is an unanswerable question. Each EJB has its own private JNDI namespace and "POJOs" don't have any namespace at all, they use the JNDI namespace of whatever EJB invoked it. So to make "java:comp/env/myDataSource" appear as global as possible, you have to declare that reference for every single EJB in the application.
The amount of configuration work this creates for users is quite devastating. In Java EE 6 there is finally Global JNDI and three new standard namespaces, java:module, java:app and java:global. Any Global JNDI functionality existing prior to Java EE 6 is vendor-specific and non-portable.
The vendor-specific and non-portable way to do a Global JNDI lookup in OpenEJB for the given name would be to lookup openejb:Resource/jdbc/OrderDB
Calling a spade a spade
In OpenEJB we deliberately do not support non-standard lookups like jdbc/OrderDB or java:jdbc/OrderDB as some vendors do. The required prefix for global names in OpenEJB is openejb:.
JNDI is complex and confusing enough and making non-portable names look like portable names doesn't do users any favors. If a certain style of naming is not portable and going to create vendor lock-in, it should look like it. So with the openejb: prefix, you can access anything you need globally but it is at least clear that what you are doing is not portable and should not be expected to work in other platforms without some modification.
Note that there is a standard jndi.properties file you can use to externalize 100% of the config normally passed in as properties to the IntitialContext
You can still use a service locator pattern as it can make your code look a little nicer and perhaps easier to maintain, but the actual server connection information can be easily externalized.
You just need to make sure the jndi.properties file is on the client's classpath at the root (i.e. not in a META-INF directory). The IntialContext will find it and load it. Any properties passed into the IntialContext constructor will simply override those passed in via jndi.properties
On the OpenEJB side it should be possible to change the JNDI name format so that it matches the WebLogic format. If not, let me know and we can add any missing meta-data to the formatter so that it is possible to match it exactly.
Can't you just use the default context? Then you don't have to specify the specific implementation and you can do the lookup via a standard reference.
Otherwise I think you are left with some sort of properties file to determine the context details at runtime.

Is there a Java EE way to change user?

Assume the follwing method:
Test getTest()
{
Properties props = new Properties();
props.put(javax.naming.Context.SECURITY_PRINCIPAL, "OtherUser");
props.put(javax.naming.Context.SECURITY_CREDENTIALS, "OtherPassword");
InitialContext ic = new InitialContext(props);
return (TestHome)PortableRemoteObject.narrow(ic.lookup("ejb/Test"),
TestHome.class).create();
}
If this method (in an EJB) is called from a client using user "MyUser" I'd like it to return an EJB with a different caller principal. Calls to Test made by the client would then be noted as being from "OtherUser". i.e. I have programmactially changed a client's caller principal for a given EJB.
However, I find no text on this in the Java EE specs and although it works on our current Java EE app-server (Sybase EAS 4.1), I'd like to ask you if this is a Java EE standard approach or not.
A standard way of handling login/logoff is JAAS. I don't know if it's fair to say that it is the standard, but it's supported by the Java EE servers I've worked with so far (JBoss, Websphere), and apparently also by Sybase EAS.
JBoss, for instance, comes with several predefined login modules for Database and LDAP and whatnot, that you just have to declaratively configure for your application. However, you are also completely free to write your own login module by implementing the respective interface (javax.security.auth.spi.LoginModule).
Take a look at the JAAS Reference Guide.
About your code snippet: I don't know if that'll work on other app servers. This is EJB 1.1, and thus really, really old stuff. You should definitely look at EJB 3.1 and consider modernizing your application anyway.
If I get this right this should link a username to an EJB across more than one methodcall, which in my opinion is a state. I guess the standard for this would be to create a Stateful SessionBean with a setUser(String name) method. In a stateless bean you would have to pass the userName (or properties object) on each methodcall.

EJB, Remoting between two application-servers (glassfish)

I want to have a bean Foo in host A which is injected, by the #EJB annotation to a bean Bar in host B.
Both these hosts are separate stand-alone instances of Glassfish-v3.
When reading the Glassfish docs I found a lot of info, some of it sounded a bit contradicting.
I understood that every bean has a global jndi named assigned to it and understood how it is constructed, What is the syntax for portable global JNDI names?. I also understood that the the declaration of Foo in Bar should be something of this sort (assuming FooRemote is the remote business interface of Foo and fooejb is the its module): #EJB(lookup=java:global/fooejb/FooRemote) FooRemote foo, this is based on this.
What I can't understand is where I tell host A and host B to get to know each other.
I saw a lot of examples for application clients and application servers but I wasn't able to find an example for such a scenario.
In this question a sun-web.xml and Global-JNDI is mentioned but I think that it's not EJB3.1 (since it's not Portable JNDI) and I don't understand where this sun-web.xml should reside (I'd like to avoid it if I can).
It is mainly different in two ways:
There is no -Dorg.omg.CORBA.ORBInitialHost= param option (as far as I can see)
Any solution should of course allow the inclusion of a third host C which both A and B communicate with for different purposes.
I have a strong feeling I'm missing something basic here and I'd really appreciate pointers to what I'm missing.
BTW, I'd like to avoid as much as possible from descriptor files and such and leave most info on annotations and only the host ip's to config in the server.
Edit:
I think another interesting aspect of this question is how load-balancing is used in this aspect, i.e. let's say I have A1 and A2 servers which are the same, how will load-balancing occur with respect to routing the request from B to either A1 or A2
Edit2:
I think this might be unrelated to ejb 3.1 but related to the basis on how to enable two application servers to see each other's jndi registry. I think this is unrelated to ejb 3.1 as it seems a similar problem exists in the 3.0 with the Global not portable jndi.
I would imagine some configuration in each app server would allow me to configure which other "neighbours" it should query for jndi remote beans.
Hope that gives a clue to someone out there.
Thanks,
Ittai
With regards to EJB Load balancing you might like to take a look at this blog:
http://www.techpost.info/2010/12/ejb-load-balancer_7304.html
As stated in one of the pages you link to, when using a cluster then you don't need extra configuration to get this to work. If you need load balancing etc. I'd imagine it is easier to set up a cluster up than doing it manually.
sun-web.xml goes right next to web.xml in WEB-INF if you deploy it as a web project in .war file.
I would think you should be able to get it right using:
http://glassfish.java.net/javaee5/ejb/EJB_FAQ.html#cross-appserverremoteref and http://glassfish.java.net/javaee5/ejb/EJB_FAQ.html#mappingRemoteejbdependency
I would have thought there must be an easy way to configure a EJB connector or Resource adaptor in glassfish itself using the administration console or editing the server.xml. But I can't find such a thing now.
We are using remote EJBs and it works fine.
First you'll need the EJB on "Host A" wich implements an interface whose class is present on both hosts.
//For host A + B
public interface FooClass {
public void theMethod();
}
//Only for host A
#Stateless
public class FooClassImpl implements FooClass {
public void theMethod(){//Code goes here}
}
Then you'll need to create (on Host B) a glassfish-web.xml in your WEB-INF directory, where you specify where a remote EJB is located:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
<ejb-ref>
<ejb-ref-name>RemoteEJBName</ejb-ref-name>
<jndi-name>corbaname:iiop:<servername or IP>:3700#java:global/<projectname>/FooClassImpl!com.test.foo.FooClass</jndi-name>
</ejb-ref>
</glassfish-web-app>
At the injection point on Host B you'll need to inject the EJB like this:
#EJB(name = "RemoteEJBName")
private FooClass theFooClassInstance;
I hope this will do the trick.

MDB how to get connection settings from server environment

I have a message driven bean which connects to a remote HornetQ JMS provider (different for production/testing).
The connection settings are stored either in sun-ejb-jar.xml or as #ActivationConfigProperty annotations directly in the MDB class.
Since all these settings are bundled with the ear file it makes the deployment process quite cumbersome when you want to test in different environments since you have to remember to change the settings all the time.
Do you have any ideas on how I could make my application read this settings from the server?
I thought of creating some custom resources and read them with #Resource, but I don't know how to make the MDB read those settings because the #Resource injection AFAIK takes place after the MDB is already initilized...
EDIT
To clarify: What I'm looking for is something like sun-ejb-jar.xml configuration file which I should install on each server with specific configuration (for ex, different JMS providers - topics/queues, etc). But my ear app should be unchanged. It should automatically load the enviroment from each server. Does it make sense?
Do you have any ideas on how I could make my application read this settings from the server?
JMX-Mbeans can be used to connect with the server. Below is the sample code to connect with the server & fetch information from it, may help you to get idea of it.
//---
Hashtable props = new Hashtable();
props.put(InitialContext.PROVIDER_URL, "jnp://localhost:1099");
props.put(InitialContext.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
InitialContext ctx = new InitialContext(props);
MBeanServerConnection serverConn = (MBeanServerConnection)ctx.lookup("jmx/rmi/RMIAdaptor");
Set<Object> listOfBeans = serverConn.queryMBeans(null, null); // find-all
for(Object o : listOfBeans){
ObjectInstance beanInfo = (ObjectInstance) o;
System.out.println(beanInfo.getObjectName());
}
//---
It outputs the registered topics/queues like jboss.mq.destination:service=Topic,name=ProvisioningResponseTopic along with other stuff.
MBeans can also be used to get other information like ports, binding-address, domain etc.
Note : The above code is JBoss specific, but same can be achieved for Glassfish.
I don't know much about Glassfish. I think there is Application Server Management eXtension (AMX) to accomplish it.

Categories