Java agent not working with R6 client. ClassNotFoundException

We have a Java agent which runs fine in a Notes R5 client, but does not seem to work in R6.

The agent populates a document with information about a user, obtained from the company’s LDAP directory. Relevent section of code follows:

public class JavaAgent extends AgentBase {

public void NotesMain() {

try {

  Session session = getSession();

  AgentContext agentContext = session.getAgentContext();



  // (Your code goes here

  String userID = session.getEnvironmentString("Intranet_ID");



  BluepagesLookup bp = new BluepagesLookup();

  .

  .

  .

}

The agent makes use of classes contained in a shared Java library called “BluepagesLookup”. This shared library is included in the agent’s project (via the “Edit Project” button.)

The shared Java library contains the BluepagesLookup class, as well as two jar files: ibmjndi.jar, and jndi.jar. The jar files are included in the project for the shared Java library (again, via the “Edit Project” button.) It is my understanding that any archives which are included in this fashion will behave as though they are in the classpath. Following are the relevant sections of code:

import java.io.*;

import javax.naming.*;

import javax.naming.directory.*;

import java.util.*

public class BluepagesLookup extends Thread {

private DirContext ctx;

public BluepagesLookup() throws NamingException {

ctx = getContext();

}

public DirContext getContext() throws NamingException {

Properties props;



props = new Properties();

props.put("java.naming.factory.initial","com.ibm.jndi.LDAPCtxFactory");

props.put("java.naming.provider.url","ldap://myldapURL.ibm.com:389");

props.put("java.naming.ldap.version","2");

props.put("java.naming.security.authentication","none");

props.put("java.naming.factory.url.pkgs","com.ibm.jndi");

props.put("java.naming.referral","ignore");

props.put("java.naming.ldap.derefAliases", "never");



return new InitialDirContext(props);

}

.

.

.

}

This agent worked just fine with the Notes R5 (5.0.11) client). Now one of my customers went off and installed the R6 client, and is complaining that the agent no longer runs. I had him turn on the Java console, and this is what we see:

javax.naming.NoInitialContextException: Cannot instantiate class: com.ibm.jndi.LDAPCtxFactory. Root exception is java.lang.ClassNotFoundException: com.ibm.jndi.LDAPCtxFactory

at java.net.URLClassLoader.findClass(URLClassLoader.java:240)

at java.lang.ClassLoader.loadClass(ClassLoader.java:513)

at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:441)

at java.lang.ClassLoader.loadClass(ClassLoader.java:445)

at java.lang.Class.forName0(Native Method)

at java.lang.Class.forName(Class.java:220)

at com.sun.naming.internal.VersionHelper12.loadClass(VersionHelper12.java:57)

at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:661)

at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:255)

at javax.naming.InitialContext.init(InitialContext.java:231)

at javax.naming.InitialContext.<init>(InitialContext.java:207)

at javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:92)

at BluepagesLookup.getContext(BluepagesLookup.java:116)

at BluepagesLookup.<init>(BluepagesLookup.java:23)

at JavaAgent.NotesMain(JavaAgent.java:52)

at lotus.domino.AgentBase.runNotes(Unknown Source)

at lotus.domino.NotesThread.run(NotesThread.java:208)

The class “com.ibm.jndi.LDAPCtxFactory” is a member of the ibmjndi.jar archive, so it should be in the classpath, in theory. But it appears the client cannot locate this class.

I tested by installing the Notes R6 client on another workstation, and the same thing happened.

I also tested on local copies of the database, on each of an R5 and R6 client. The R5 client copy ran just fine, while the R6 copy didn’t. This makes me believe it is related to the client, rather than anything happening on the Notes server.

Any ideas on why this is happening? Is this a bug with the Notes R6 client product, or my application?

Thanks,

Mike

Subject: Java agent not working with R6 client. ClassNotFoundException

Check your email.

Subject: RE: Java agent not working with R6 client. ClassNotFoundException

Just wanted to follow up and post the workaround to my specific problem, discovered by Aditya.

The workaround takes advantage of the fact that in R6, Lotus seems to have packaged the Sun JNDI implementation with Notes. It’s one of many things contained in a file called rt.jar, which is, by default, in the classpath. So I just had to make a slight code change to dynamically load the Sun class instead of the IBM class, and then the agent worked. In R5, the Sun JNDI code is apparently not packaged with Notes. So this is an R6 only solution

Subject: RE: Java agent not working with R6 client. ClassNotFoundException

Due to popular demand, I am posting additional details of the previously mentioned workaround. Hope it helps.

I added some logic to determine the version of Notes (using NotesSession.getNotesVersion). Based on the version (we still have some users on R5), I choose between the IBM or Sun CtxFactory class, as follows:

// pass the result of session.getNotesVersion()

public String getCtxFactory(String version) {

	

	System.out.println("Running Notes Version: " + version);

	

	String release;

	//set up String Tokenizer to parse at spaces, and decimal points

	StringTokenizer strtok = new StringTokenizer(version, " .");

	if (strtok.hasMoreTokens()) {

		//skip past word "Release".  value is throwaway

		release = strtok.nextToken();

		//next token, before decimal point should be release number.  This is what we need

		if (strtok.hasMoreTokens()) {

			release = strtok.nextToken();

		} else {

			release = "5";

		}

	} else {

		release = "5";

	}

	if (release.equals("5")) {

		return new String("com.ibm.jndi.LDAPCtxFactory");

	} else {

		return new String("com.sun.jndi.ldap.LdapCtxFactory");

	}

}

I then rewrote my getContext method to accept a String parameter for the name of the Ctx Factory class to load and use:

public DirContext getContext(String ldapCtxFactoryClass) throws NamingException {

		Properties theProps;

		

		theProps = new Properties();

		theProps.put("java.naming.factory.initial",ldapCtxFactoryClass);

		theProps.put("java.naming.provider.url","ldap://bluepages.ibm.com:389");

		theProps.put("java.naming.ldap.version","2");

		theProps.put("java.naming.security.authentication","none");

		theProps.put("java.naming.factory.url.pkgs","com.ibm.jndi");

		theProps.put("java.naming.referral","ignore");

		theProps.put("java.naming.ldap.derefAliases", "never");



		return new InitialDirContext(theProps);

}

This enabled my agent to work properly. Once all of our users are on R6, I will most likely just remove the hybrid solution, and go with the Sun classes (unless Lotus addresses the problem in a future release.)

Subject: RE: Java agent not working with R6 client. ClassNotFoundException

Any reason why you just don’t install the Sun JNDI classes on those systemt hat need them, or provide it with the agent or as a library? Just curious.

Joseph Millar

Principal Software Engineer

Brightline Technology

Subject: RE: Java agent not working with R6 client. ClassNotFoundException

Joseph,

This goes back to the original problem. Our original implementation had the IBM JNDI classes imported into the agent’s workspace, which enabled the agent to access them as though they are in the classpath. This worked like a charm when run on a Notes R5 client, and eliminated the need to install additional classes or jars on users’ workstations (and avoids the maintenance/support headache that would almost certainly accompany that).

Once people started upgrading to R6, the agent stopped working, with ClassNotFoundException on the LdapCtxFactory class. It’s as if importing jars into the agent no longer places them where the agent can find them. Regardless of any possible options for working around this, we were looking for a solution that will still allow us to maintain all code with the database, rather than deploying it out to users’ workstations. At least this workaround provides this.

Hope that better explains our reasons.

Subject: RE: Java agent not working with R6 client. ClassNotFoundException

Ah, I begin to see the light. I’m puzzled by why the agent stopped working. Even with the base Sun classes in the JRE 1.3 in 6.0, if your agent was coded properly, it should have continued to access the com.ibm version just fine. This indicates to me that perhaps the agent is somehow relying on something other than explicit imports to load the needed classes. If you correct that problem, you should be OK going forward or until such time as all your clients are on 6.x and you can convert fully to the JRE JNDI interfaces, which will be carried forward.

Can you provide a small sample that illustrates the error?

But either way you go about it (fixing the original loading issue or including a fix to test for version), it’s still a change. so I guess whatever is least work and will get you solidly to 6.x is the best solution.

Joseph Millar

Principal Software Engineer

Brightline Technology