Java EE application client on top of NetBeans Platform
For this article we will need FeedReader application (FeadReader Application project) and some empty Java EE enterprise application (feedreader-ear project) with application client (feedreader-ear-app-client project) , so let's create them somewhere on the disk.
Because NetBeans platform as well as FeedReader application is just a set of jars it should be possible to take all these jars, package them to enterprise application "/lib" directory (as it is common place for libraries in enterprise applications defined by Java EE 5 specification) and from application client's main class just call org.netbeans.Main.main to start an application. Let see what will happen if we follow these steps:
build.xml of feedreader-ear project and put there following pre-dist target:
<target name="pre-dist">
<!-- feedreader.home must point to FeedReader Application home directory -->
<property name="feedreader.home" value="../feedreader-suite"/>
<mkdir dir="${build.dir}/lib"/>
<copy todir="${build.dir}/lib">
<fileset dir="${feedreader.home}/build/jnlp/app" includes="*.jar" />
<fileset dir="${feedreader.home}/build/jnlp/branding" includes="*.jar" />
<fileset dir="${feedreader.home}/build/jnlp/netbeans" includes="*.jar" />
</copy>
</target>
public static void main(String[] args) {
try {
org.netbeans.Main.main(new String[] {"--branding", "feedreader"});
} catch (Exception ex) {
ex.printStackTrace();
}
}
To be able to compile this we have to add boot.jar from NetBeans Platform to appclient project libraries. But do not include it in packaged application as it will be added to lib directory in resulted ear by pre-dist target created in step 2. See attached picture, where to "mark" library to not being packaged in resulted EAR.
Now if we run feedreader-ear project we will find following problems:
java.lang.Error during application startupjava.io.FileNotFoundException: Windows2/WindowManager.wswmgr is thrown right after opening application's main windowSo, it does not look as simple as it seemed to at the beginning. Let see what all these problems means and if they can be somehow fixed or workarounded:
java.lang.Error during application startup
java.lang.Error: factory already defined
at java.net.URL.setURLStreamHandlerFactory(URL.java:1074)
at org.netbeans.core.startup.Main.initializeURLFactory(Main.java:126)
at org.netbeans.core.startup.Main.start(Main.java:281)
at org.netbeans.core.startup.TopThreadGroup.run(TopThreadGroup.java:96)
at java.lang.Thread.run(Thread.java:595)
According to comment found in the source of org.netbeans.core.startup.Main we can ignore this as it seems to have no effect on application being run (we can take it like other informational exceptions).
/** Sets value of netbeans.user property.
*/
final static void fixNetBeansUser() {
String userDir = "${user.home}/.feedreader-ear"; // NOI18N
final String PREFIX = "${user.home}/"; // NOI18N
int uh = userDir.indexOf(PREFIX);
if (uh == -1) {
return;
}
String newDir =
userDir.substring(0, uh) +
System.getProperty("user.home") + // NOI18N
File.separator +
userDir.substring(uh + PREFIX.length());
System.setProperty("netbeans.user", newDir); // NOI18N
}
%GLASSFISH_HOME%\lib). This jar comes from NetBeans, it is regular NetBeans module and it is discovered by the platform during its startup (not sure why it is being discovered by the platform yet - maybe because they're on the application's startup classpath). Platform also tries to find other modules this "module" depends on, but they are not found, thus this warning.<exclude name="lib/dbschema.jar"/> to %GLASSFISH_HOME%\lib\package-appclient.xml script. Although this may help, I did not test this and I do not recommend it. Other way how this can be workarounded is to correctly set netbeans.dirs property and to use custom ClassLoader to load libraries and to start NetBeans Platform using reflection.java.io.FileNotFoundException: Windows2/WindowManager.wswmgr is thrown right after opening application's main windowLast two problems can be workarounded by using custom ClassLoaders, so here is how the application client's main method can look like:
public static void main(String[] args) {
//create new "top-level" classloader which will not see dbschema.jar
//get original classloader
ClassLoader originalClassLoader = new Main().getClass().getClassLoader();
URLClassLoader applicationClassLoader = (URLClassLoader) (originalClassLoader.getParent());
URL[] us = applicationClassLoader.getURLs();
List l = new ArrayList();
for (int i = 0; i < us.length; i++) {
if (!us[i].getFile().endsWith("dbschema.jar")) {
l.add(us[i]);
}
}
//our new "top-level" classloader
ClassLoader rootClassLoader = new URLClassLoader(l.toArray(new URL[l.size()]), null);
//our custom "NB platform" classloader
l.clear();
for (int i = 0; i < resources.length; i++) {
URL u = originalClassLoader.getResource(resources[i]);
l.add(u);
}
ClassLoader loader = new URLClassLoader(l.toArray(new URL[l.size()]), rootClassLoader);
//fix userdir
fixNetBeansUser();
//fix netbeans.dirs property - to get rid of warning about dbschema module
//when running using appclient script
URL url = originalClassLoader.getResource(resources[0]);
System.setProperty("netbeans.dirs", new File(url.getFile()).getParentFile().getAbsolutePath());
//start our NB platform based application
try {
Object[] argss = new String[] {"--branding", "feedreader"};
Class c = loader.loadClass("org.netbeans.Main");
Method m = c.getMethod("main", new Class[] { String[].class });
m.invoke(null, new Object[] {argss});
} catch (Exception ex) {
ex.printStackTrace();
}
}
Full code of application client's main class is here. One more required change has to be done in build.xml modified in step 2 at the beginning of this article if you want to just reuse this class - replace ${build.dir}/lib with ${build.dir}/netbeans. Now you should be able to run FeedReader demo application using appclient script as well as using Java Web Start feature in GlassFish.
Posted at 06:04PM Jul 28, 2006 by jungi in NetBeans | Comments[1]
Today's Page Hits: 39
Posted by Gergely Dombi on August 04, 2006 at 10:13 AM CEST #