- This topic has 13 replies, 4 voices, and was last updated 20 years, 9 months ago by
Franck.
-
AuthorPosts
-
freemanlMemberHey,
Just a quick question. What is the best way to generate Client (implementation/stub) jar files for use with client applications?
Im guessing the clientjar option in xdoclet has something to do with it but I cant get it to output anything. I really dont want to (shouldn’t have to ??) include the main ejb jar with my client application.
Thanks in advance ..
Riyad KallaMemberI’ved asked our XDoclet guy to look at this.
FranckMemberHi,
Generation of the client jar file is the responsibility of the container vendor.
However, there is not much known about it. At least I have spent a weekend looking for info and, strangely enough, it turns out to be quite a jungle.
In the end I got it working for Weblogic. If you want to know more details, let me know.
If you manage to get it generated in another way, please let me know, since I am very much curious to know.
GregMemberI have never generated a client jar using xdoclet. So I looked around at some sample xdoclet ant build files. And this is the pattern that I saw a few times regarding client jar files.
<deploymentdescriptor destdir="${destdir}" validatexml="true" mergedir="${mergedir}" > <configParam name="clientjar" value="blah.jar"/> </deploymentdescriptor>
So you don’t need to set the clientjar attribute on the <deploymentdescriptor> subdoclet. Rather, you need to right-click the <deploymentdescriptor> subdoclet and click “Add”. And then select ConfigParam. Then select the ConfigParam and set name to “clientjar” and value to your file name. The destDir and validatexml attributes should already be set correctly if you are using the “Standard EJB” configuration.
I haven’t actually built a clientjar but I just wanted to let you know what I found and how to generate that configuration with the MyEclipse-XDoclet page. Hopefully it will work for you.
freemanlMemberI am hesitant to say that the above method (ie: configParam in deployment descriptor) didn’t work. I tried it, but it didn’t actually do anything!
Having said this, I am wondering: When is the client jar actually meant to be generated? When XDoclet is run, or at deployment? I am wondering if it is more likely a container managed thing (as rosana.rocha touched on) as it IS sitting in the deployment descriptor section.
I too have been searching for an answer for about a week and had no luck. I have scoured through the XDoclet documents and have not found anything that is really descriptive about what this actual option really does. The only real examples I can find involve storing both the client and the EJB in the same project (or linked projects).
How is everybody else doing client-EJB communication? I would be interested in knowing the method’s that everybody else uses? At the moment the only option’s I see are compiling the client with the EJB packaged with the client aplication(?).
-luke
FranckMemberHi,
I only can tell for BEA weblogic. The J2EE specifications do not define how the client jar file is generated.
For BEA weblogic you have to run a separate tool to obtain the client jar file. After a lot of fiddling around (also BEA’s documentation is very poor on this) I managed to do it like this in ANT:
<java fork="true" newenvironment="true" classname="weblogic.appc"> <classpath> <pathelement location="${jar.weblogic}"/> <pathelement location="${jar.tools}"/> </classpath> <arg value="-classpath"/> <arg pathref="j2ee.classpath"/> <arg value="-output"/> <arg value="${classes.clientjar}"/> <arg value="-basicClientJar"/> <arg value="-iiop"/> <arg value="${classes.source}"/> </java>
You actually run a BEA compiler (appc) over your source code. This will compile the client jar file.
I am sure for other vendors this is different.
To be honest, I do not understand myself, why this is so complicated. It looks like EJBs should only be called from Servlets in the same container. Then, a simple JNDI lookup does the trick.
However, if you are out of the container, this simple JNDI lookup does not work (unless you are willing to accept the vendor’s JNDI factory and stuff, which gives you vendor lockin).
The idea is that standalone applications should run from a J2EE container. I have never been able to grasp this concept myself. Does this mean that the standalone application must be deployed on the J2EE container? That can’t be true … So, what are you supposed to do with it???
With XDoclet you can specify the clientjar element, but in my opinion, the actual container does not do much with this information …
If you have more news, let me know!
Cheers,
Franck
GregMemberThanks for your input, Franck.
I agree that this clientjar matter leaves alot to be desired. What do you guys think should be going into the clientjar? EJB Interface classes generated by XDoclet or j2ee client libraries that EJB client applications would need? I frankly don’t know because I’ve never used this feature in XDoclet.
FranckMemberFor me that would be the runtime classes a client would need to call a bean in the J2EE container.
Ideally from a client perspective, the code calling a session bean should look like the following (standalone SWING client, e.g.):
public String getHelloWorld() { String providerUrl; String result; Properties props; Context context; Object remoteObj; MyBeanHome beanHome; MyBean bean; providerUrl = "iiop://localhost:7001"; props = new Properties(); props.put("java.naming.factory.initial", "com.sun.jndi.cosnaming.CNCtxFactory"); props.put("java.naming.provider.url", providerUrl); try { context = new InitialContext(props); remoteObj = context.lookup("ejb/MyBeanHome"); beanHome = (MyBeanHome) PortableRemoteObject.narrow(remoteObj, MyBeanHome.class); bean = beanHome.create(); result = bean.helloWorld(); } catch (Exception e) { e.printStackTrace(); } return result; }
The code in the try-block is the standard code for looking up a (session) bean. The problem is in creating the Context. If you look carefully, I am not using any vendor specific classes to create the Context. The JNDI factory comes directly from SUN’s JDK.
In order to get this working, I should have a client jar file that holds in principle the MyBeanHome and MyBean interfaces, their stubs and any necessary supporting classes (like custom Exceptions, and custom classes used in the interface which are Serializable).
The problem lies in the inclusion of the stubs. Where to get them? They can only be generated by a vendor specific tool (appc for BEA). XDoclet will not help out here. I have no clue how to do it for another vendor. Somewhere in the near future I will try to get it done for JBOSS, but I cannot promise anything 🙂 .
The alternative (at least for BEA) is to use their own protocol (t3) and JNDI factory. But that involves including their jar-files, and creates a provider lock in, which is not desired.
I hope I am doing something wrong … and that there is much simpler solution available, but I fear not …
freemanlMemberYeah. I’m afraid its beginning to look like rosana.rocha has nailed it really.
I did in fact cross post this question on the JBoss forum but alas have not had a reply. It is annoying that a tool like JBoss (who ranks themselves #1 in the app server market) does not have a tool for client deployment. Isn’t this a crucial aspect in relation to EJB usage or am I overselling the importance of such a tool?
Oh well, it looks like my client applications are just going to have to be uncessesarily complicated. Either that or I will look at switching App Servers.
It seems that the usefulness of EJB is greatly overshaddowed by the complexity of deployment (in this case).
As a side note, for anyone interested, I CAN get my client to work if I include the standard EJB jar file (the one i deploy to the server) with the client application, or put it on the client class path. I then use the “standard” jboss technique for obtaining a context and everything seems fine. I dont know if this would have any effect on transactional states, etc. Does anyone know of any downsides to using this method?
Obtaining a context can be done using the following code:
public static Context getInitContext() throws Exception { try { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); env.put(Context.PROVIDER_URL, "localhost:1099"); env.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces"); return new InitialContext(env); } catch (Exception e) { throw new Exception ("Error in TestClient.getInitContext()\n" + e.getClass() + ": " + e.getMessage()); } }
Where <server name> is your server. You will need jbossall-client.jar as well from your jboss distro ($JBOSS_HOME/client).
Thats how I get things going for JBoss.
I suppose a feature request would be for myeclipse to featue a deploy to file system option. Its a pain to have to copy the file each time (not that it is the fault of myeclipse). Is there a way I can generate an ant build script for ejb’s from the myeclipse project? That would be handy too.
FranckMemberI think the biggest downside is that you have to deploy your server code with the client. I really cannot stand that. What you could try to do is find out which are really the necessary files to get your client working. Then, maybe with a clever ant task you can grab these files into one client jar file.
If I understood your post correctly, you use a JBOSS JNDI factory to look up your beans. Plus you have to deploy a seperate JBOSS client jar file with your client as well.
Of course, this is workable, but I don’t appreciate the vendor lock in.
I think it is strange that the client needs to know the vendor type of the container where its server components reside. It should all have been standardized, but apparently it has not.
I did a similar post in the BEA forums, but also there I could not get a reply. Maybe it is a policy for vendors not to bother about it, so that they can create a vendor lock in or something like that. In the end that is better for them, you would say.
Now I start guessing, but a technological reason behind this, is the fact that in the background RMI is used for EJB communication. With RMI you get the stubs from running the rmic-compiler over the implementation object, not the interface. And if I am not mistaken, the RMI implementations are generated by the J2EE vendor upon deployment.
This is unlike CORBA for example. With CORBA you run (both client and server) the idlj-compiler over the CORBA interface specifications (IDL) and you get your stubs that you can use. You do not need anything from the server anymore. To me, that sounds like a much cleaner solution …
But, as I said before, this is probably guessing … 🙂
For MyEclipse, I am not sure what they can do about it. It would be really nice, if they can somehow describe what to do to develop a true J2EE standalone client, and how you can achieve that from their plugin. Maybe with the aid of some wizards of some sorts. This would really be an added value for something that is really underdocumented in the J2EE community.
Cheers,
Franck
freemanlMemberI guess one option I have found is to use JBoss-IDE to help you along the path of creating EJB client jars. This still seems less than ideal though.
JBoss prescribes that in order to create a client jar you ONLY need to wrap all of the interfaces into a jar file.
JBoss-IDE simply creates a build script (ant?) that when run generates the jar/war/ear’s that you define.
It all seems to work OK. You will still need to include the jbossall-client.jar i think too. I do keep getting RMI security exceptions though when I try to execute the application. I guess I need to set up a security policy somewhere! But geeze, like I have said before why so difficult!!
I agree vendor lockin sucks. If i dont supply the JNDI details when aquiring a context then it fails and asks me to specify them.
After all this, I STILL have to figure out how to deploy this sucker!!
-luke
FranckMemberI have been looking on the web (again) and there is really not much to find. That is so weird!!! I think we are the only 2 trying to make a rich client on top of an EJB layer. Must be that we are doing something wrong … 😕
An alternative workaround is to work with Servlets (as facades to your EJB layer) and working with HTTP requests. But, of course, this is also a terrible solution. The entire static typing advantage will be gone. Maybe an interesting link is this one:
http://www.bs-factory.org/components/remoting.shtml
Currently there is an open sourced project going on called JDNC (JDesktop Network Components) https://jdnc.dev.java.net/documentation/overview.html which has goal to simplify SWING based GUIs on top of a J2EE system.
From their web-site:
And these days that data is usually tied to a network data source, such as an SQL database, HTTP servlet, or WebService, bringing with it the complexity of networking. JDNC does the heavy lifting here, by providing built-in support for dealing with these network data sources, including multi-threaded support (so the UI doesn’t block during network operations) and incremental loading — hence, the “Network” in “JDesktop Network Components”.
I am not sure, but it looks like EJB is not within their scope, however. Maybe another indication that you should not try to build standalone clients on top of an EJB layer. Tonight I will drop a line on their forum and see what they can tell us about it. I’ll keep you posted.
Cheers,
Franck
FranckMemberThat should have been a link:
FranckMemberI have posted this message on the JDNC forum:
http://www.javadesktop.org/forums/thread.jspa?threadID=3860
Cheers,
FranckPS: Will only be back on Monday.
-
AuthorPosts