I am new to Java EE. At present I am going through The Java EE 6 Tutorial, Volume 1 (Basic Concepts Beta) by Sun Microsystems. To escape from monotonous reading time to time I play with few Java EE projects/codes written by others.
I came from SE. My head is still filled with SE. In SE (two tier application) I use
DATABASE_URL = "jdbc:mysql://something.db_server.com/db_name"
This is how my client knows where the database server is.
In one Java EE example I saw
// Access JNDI Initial Context.
Properties p = new Properties();
p.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
p.put("java.naming.provider.url","jnp://localhost:1099");
p.put("java.naming.factory.url.pkgs","org.jboss.naming:org.jnp.interfaces");
InitialContext ctx = new InitialContext(p);
// Change jndi name according to your server and ejb
HelloRemote remote = (HelloRemote) ctx.lookup("HelloBean/remote");
msg = "Message From EJB --> " + remote.sayHello();
This I understand. The code has url and port number. There is this line
p.put("java.naming.provider.url","jnp://localhost:1099");
Client side knows where is the server by the url and which port to knock. I think the code was written at the time of Java EE 5.
Today I have found another example where Netbeans 7, Java EE 6, and GlassFish 3 are used. The client side code
@EJB
private static MySessionRemote mySession;
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
JOptionPane.showMessageDialog(null,
"result = " + mySession.getResult());
}
Here is the link
http://netbeans.org/kb/docs/javaee/entappclient.html
No url and port number are given.
Java EE 6 Development with Netbeans 7 by David R. Heffelfinger has a similar example in chapter 7. The author did not explain how it is done in the book. I think he has done it but I probably missed it…
My question is how the client side locate the server without url? Is it stated in one of those xml files? Client can be in California and the GlassFish Server can be in New York. Can anyone explain it to me or point to any tutorial/blog/article where I can find the answer?
Thank you.
There are two things that are going on here.
The first thing is that the way in which to obtain a reference to a remote EJB is not specified in Java EE. You are at the mercy of how an individual vendor thinks it should be done.
Although JNDI is the de facto standard used for this, even this itself is not mandated.
Example: JBoss up till AS7
In JBoss AS up till AS 7, the following sequence was used to obtain a remote reference:
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
env.put(Context.PROVIDER_URL, "jnp://myserver.example.com:1099");
InitialContext context = new InitialContext(env);
Bean bean = (Bean) context.lookup("myear/MyBean/remote");
Here, the URL of the remote server is provided to the initial context and from that context a bean is retrieved. (Note that you must NOT add the well known "java:/" prefix here, or else it will be intercepted by JNDI and resolved locally, despite doing the lookup on a remote context)
Since this method was as mentioned not standardized, a single vendor can change it completely between releases of implementations. Even for implementations for the same Java EE version.
Example: JBoss AS7
In JBoss AS 7, JBoss wanted to move away from JNDI (because it was not specified that JNDI had to be used) and now it happens in approximately the following way:
You'll first need to put a jboss-ejb-client.properties
file on your classpath with the following context:
endpoint.name = client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED = false
remote.connections = default
remote.connection.default.host = myserver.example.com
remote.connection.default.port = 4447
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS = false
And use code as the following:
Properties env = new Properties();
env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
InitialContext context = new InitialContext(env);
Bean bean = (Bean) context.lookup("ejb:/myear/mymodule/MyBean!com.example.Bean");
So from the code it looks like no URL is given, but it's statically hidden in a config file.
Application Client Container
Today I have found another example where Netbeans 7, Java EE 6, and GlassFish 3 are used. The client side code [...]
This is yet another thing. What's demonstrated there is a so-called Application Client Container (aka ACC).
This is different from the example above, where a Java SE application used JNDI to contact the remote server. The Application Client Container is a bit of an obscure thing in Java EE. The idea seems to be that you download the client code dynamically from the Server (like an Applet or Java Web Start app), and that it then magically 'knows' where it originated from. There is very limited support for (static) injection in the main class, which you can use to inject remote beans directly.
The Application Client Container is an idea from the early days of Java EE and as far as I know has never gotten much attention. After all these years it has never advanced much after its initial conception. Since it still requires a ton of vendor specific things to be done, I think most people don't bother with it and just use JNDI.
There would need to be a jndi.properties
file with the configuration data in it. A client can't magically know the server to connect to even if it would need to connect to a server running on the same host as the client - there can still be multiple.
The example is very odd though - the EJB annotation would indicate it is supposed to run in a Java EE container, not as a client application.
I would also like to note that invoking EJBs in client applications is not really that common; its more a server side technology. If you want to provide an interface to client applications its far easier and more portable to use for example RESTful webservices through JAX-RS.