Managing external Java dependencies in Domino Designer
One of the major advantages of developing in Java is the abundance of high quality open source libraries available to help you dramastically cut development time. Apache Jakarta and OpenSymphony are just two examples of sites that hosts high quality components you can leverage in your day-to-day developments (make sure to look into Jakarta Commons). The libraries are most often distributed in the form of one or multiple JAR files that you need link to when developing and compiling your code.
If you are unfamiliar with JAR files they are bascially ZIP files with a special directory structure. They are used to package compiled classes and let you handle one file instead of a whole directory tree. Much easier. For more information on JAR files refer to the page Packaging Programs in JAR Files at java.sun.com.
With external dependencies come complexity and issues as to where to place the JAR files so Domino Designer, the Notes client and the Domino server can find the code at design and runtime. When having external dependencies you basically have four options:
- Include the classes in the agent/web service you are writing.
- Put the classes in a Java script library and include the script library.
- Use the JavaUserClasses notes.ini setting.
- Put the classes in the jvm/lib/ext folder.
Below I'll explain a little about each approach.
Include the classes in the agent/web service you are writing
This means using the "Edit Project" button in the Domino Designer Java IDE to include JAR files from the local file system in the agent/web service itself. This approach is valid and very easy to use but can mean dublicating the classes across multiple agents/web services in the same database. It is perfect for not having any dependencies outside the database.
This means importing the JAR file(s) into a Java script library and then including the script library from agents/web services. This approach is for most cases the preferred way of using JAR files with Domino Designer since you avoid dublicating the code across design elements while avoiding dependencies outside the database. It also means that the code is easily shared among developers working on different agents concurrently.
Use the JavaUserClasses notes.ini setting
The JavaUserClasses notes.ini setting is the equivalent of the CLASSPATH setting used when developing in Java outside Notes. The setting makes the classes universally available so you can use them just like the classes from the java.*-packages lotus.domino.*-package. The setting is restricted in length (due to the limits imposed on notes.ini settings) and isn't sharable across clients.
Put the classes in the jvm/lib/ext folder
Putting external JAR files in the jvm/lib/ext folder under your binary Notes directory affords you the same universal availability of the classes as the JavaUserClasses setting but without having to manually edit the notes.ini file. This possibility was introduced with Notes 6. Putting the classes in the jvm/lib/ext folder has some additional advantages when it comes to security but that's for another post.
The table below shows the applicability of the different approaches.
| Designer | Notes | Domino | Replication | Sharable | Agent | Web service | Servlet | |
|---|---|---|---|---|---|---|---|---|
| Include in agent | + | + | + | + | - | + | - | - |
| Include in web service | + | + | + | + | - | - | + | - |
| Script library | + | + | + | + | + | + | + | - |
| JavaUserClasses | + | + | + | - | + | + | + | + |
| jvm/lib/ext | + | + | + | - | + | + | + | + |
As the table shows it is important to note that the JavaUserClasses and jvm/lib/ext approach are specific to the local machine that is it doesn't replicate. This means that all installations (clients and servers) must maintain the setting manually. This can really be a hassle and doesn't lend itself for use in applications deployed to end users. The approaches are very usable for servers though.
The table also shows that classes imported into a specific agent are not sharable that is you have to import the JAR file in every agent that uses the classes thus you have to remember updating the JAR file in every agent if upgradering to a new version of the JAR file. It can be a strength though if different versions are required. I recommend avoiding this approach whenever possible. Use script libraries instead.
Finally only the JavaUserClasses and jvm/lib/ext approaches can be used to load classes for servlets running under the Domino servlet manager.
Conclusion
In conclusion you should pay attention to what you are trying to accomplish when choosing the location for the JAR files you depend on. Each approach has its strengths and weeknesses.
For most cases the preferred way is using Java script libraries.
Re: Managing external Java dependencies in Domino Designer
Re: Managing external Java dependencies in Domino Designer
Re: Managing external Java dependencies in Domino Designer
AppConnSession VHIconn;
AppConnRecordSet records;
AppConnRecord record;
List vOPList = new LinkedList();
Map vFilters = new HashMap();
Map vInputs = new HashMap();
Vector row;
This part, however, causes a runtime error:
//Connect to the VHI Model
VHIconn = new AppConnSession();
VHIconn.connectToModel(<MyPCName>, <ModelName>,<loginId>,<password>, null);
The error I get is "java.lang.NoClassDefFoundError."
Re: Managing external Java dependencies in Domino Designer
Re: Managing external Java dependencies in Domino Designer
"java.lang.NoClassDefFoundError: com/wrq/apptrieve/include/EnumCommands"
It should be "com.wrq.apptrieve.appconn"
Thanks.
Re: Managing external Java dependencies in Domino Designer
Re: Managing external Java dependencies in Domino Designer
Re: Managing external Java dependencies in Domino Designer
Re: Managing external Java dependencies in Domino Designer
Re: Managing external Java dependencies in Domino Designer
Sounds like you are using imported Java instead of writing the code in the Domino Designer IDE - am I right? If that's the case you might want to check out my post on using imported Java in Notes.
Is there a stacktrace?
Re: Managing external Java dependencies in Domino Designer
Re: Managing external Java dependencies in Domino Designer
Re: Managing external Java dependencies in Domino Designer
Re: Managing external Java dependencies in Domino Designer
Re: Managing external Java dependencies in Domino Designer
Well I haven't been playing too much with applets on forms so I'm at a loss here. I would however also have thought that the applets would be loaded by the same JVM and hence static fields should be accessible from the two applets. You're sure it's not a code problem - it has been seen before... :-) If you post some code I'll be happy to look at it for you.
As to your other issue with JSObject (it sure seems like you have been messing with it for a while) I do not think it is necessarily a classloading issue. How do you obtain the JSObject?
Re: Managing external Java dependencies in Domino Designer
Well, I hope it's not a code problem, but I can't be sure... Perhaps I've missunderstood something and have it all wrong since the beginning of my tests :(
Anyway, to help you or anybody who wants to have a look at this, I've prepared this example based on what I try to do in my real application.
The file "test_applets.zip" contains the source code of the two applets, two JAR files containing each of the compiled applet and a Notes database with the implementation of those applets.
To be sure the example will run in the same kind of conditions, you first have to place the file "localclasses.jar" somewhere in your file system and then to reference the path to this file in the JavaUuseClasses (or JavaUserClassesExt) variable in the notes.ini. Once done, you can (re)start your Notes client 6.x or 7.x.
Then open the database and create a document based on form "Local and DB applets". This will start the applets in the same form. After that, I suggest to open files "WindowJSObjectApplet.java" (source of the "database applet") and "MainApplet.java" (source of the "local applet") and have a look at the code to understand what's happening and what should be displayed in the output console.
What I try to do is to set the window JSObject from the "database applet" into the "local applet". The "database applet" seems to have no problem to do that, but once in the "local applet", the window JSObject is still null and so it is not possible to call some Javascript. You'll also notice that trying to create a window JSObject directly from the "local database" is not a solution as this also returns always a null object...
I hope there is enough information here to help you start understanding what I'm trying to do and perhaps found something new :)
One more thing, if you start changing the source code of the "MainApplet" class, remember that once compiled in the "localclasses.jar" file and you'll each time have to replace this file where you initialy copy it in your file system. Then you'll have to restart your Notes client to make the changes available.
java.lang.IllegalAccessError
java.lang.IllegalAccessError
It sure sounds strange. I tried to reproduce in Notes 7.0.1 and was able to at first but on subsequent tries I wasn't able to reproduce any more. I think it was because I inadvertantly loaded an old jar from jvm/lib/ext. After resolving that I could consistantly reproduce the issue.
I haven't experienced the issue before but it certainly looks like a bug in how the built-in JVM works. However I wouldn't consider it a classloader bug since it really hasn't got anything to do with classloading. It's more an issue with how the JVM determines access to the fields declared in the bytecode and hence an incompability between the compiler in Domino Designer and the JVM the AMgr uses.
I think you should report the issue to Lotus Support as a bug. You are welcome to tell them that developers, independently from you, can reproduce the issue.
What you can do as a workaround is to create an accessor method with protected access:
public abstract class MyAgentBase extends AgentBase {
// declarations
Session session = null;
protected Session getMySession() {
return this.session;
}
}



