Getting To The Java Roots of XPages – Part 8

Anybody who already knows java probably took a look at the java class that I created in the previous parts and saw all kinds of mistakes. This was done on purpose. If I had of shown a bigger java class then the people who are scared of java would have said that they just don’t understand it and would have given up reading these blog posts.

In this and the next few parts I’m going to tidy that class up a bit to make it much more robust. This also demonstrates another key advantage of using java, especially when we get to the stage in the series where we make the java available to all nsf’s.

Taking the getMyInternetAddress method we have now let us imagine that 3 years from now you need to pull the internet address from LDAP rather then from the Domino addressbook. If this java class was shared with all applications on the server it would mean that you just need to update the class to make the ldap connection and retrieve the value. As long as the method name stays the same there would be no need to update a single NSF on the Domino server. That is pretty powerful stuff and a great reason to separate all your business logic from the actual applications.

In terms of tidying up that class the first thing I’m going to do is RECYCLE, RECYCLE, RECYCLE. Even though we are working in Java whenever we get a Domino related object it it really using a C API to get the object, this creates what is known as a handle which is like a bucket dedicated to that Domino object. When I’m finished working with the object I need to tell it I’m finished so that it can release the handle so it can be used by something else. There are only so many of these buckets.

In Lotusscript you didn’t have to worry about this. When the script ended all the objects that you had opened would be automatically told to close and the handles would be released. In both java and ssjs, however, the object handles are not released immediately, this is especially evident in a loop scenario, loop too many documents without releasing the handle each time and the server runs out of handles and crashes. Too many server crashes and your admin will not be very happy.

So one of the first things you need to know about optimizing your java code is that Domino objects should always be recycled as soon as your done with them.

The second thing you need to know is that this only applies to Domino objects. There is no recycle method on non-domino objects. You can, if you want, set non-domino objects to null when your finished with them but java will know when there is nothing using a java object any more and  will take care of things.

To add the recycling to my class I could add the following just after where I get the result

nabDoc.recycle();
nabView.recycle();
nabDB.recycle();
thisDB.recycle();
session.recycle();

But that is not going to work 100% of the time. If something triggered an error, for example the user doesn’t have access the to nab, then the code would jump to the try block and those recycles would never run leaving a session and thisDB object hanging around.

Instead I’m going to use a nice little helper method given to me by Nathan Freeman that is designed to recycle any domino object passed into it. I’m going to add the following method to my AboutMe class :

public static void recycleDominoObjects(Object... args) {
	for (Object o : args) {
		if (o != null) {
			if (o instanceof Base) {
				try {
					((Base) o).recycle();
				} catch (Throwable t) {
					// who cares?
				}
                        }
                }
         }
}

Eeeek! More scary looking java code.

Well public means that this method can be seen from outside the class, static means there only ever needs to be one of these objects so the compiler knows how to optimize itself, void means that it returns nothing. recycleDominoObjects is the name of the methods and here is the interesting one (Object… args) tells it that it can accept any number of object parameters so it doesn’t care if you pass it one parameter or 10 parameters.

The code itself just loops through each object parameter, if the object is not already null it then checks to see what type of object it is using the instanceOf command. Base comes from a package called lotus.domino.Base and all Domino objects are instances of Base. So when it find a Domino object passed into it it will then call the recycle() method on that object.

To call that method from my getMyInternetAddress method I’m going to use a ‘Finally’ block. You have seen the try/catch block, finally is another part of that same pattern and looks like this

try{
    // Do Something here
} catch(Exception e) {
    // Do the error handling here
} finally {
    // Do the cleanup here
}

The finally block runs immediately after both the try block ( if there were no errors ) and the catch block ( if there were errors ) so if always runs regardless and is the perfect place to get rid of those Domino Objects. Here is my new version of the getMyInternetAddress method

public String getMyInternetAddress() {
		System.out.print("AboutMe getMyInternetAddress Called");
		String result = null;

		Session session =null;
		Database thisDB =null;
		Database nabDB =null;
		View nabView =null;
		Document nabDoc =null;

		try {
			session = ExtLibUtil.getCurrentSession();
			thisDB = session.getCurrentDatabase();
			nabDB = session.getDatabase(thisDB.getServer(),
					"names.nsf", false);
			nabView = nabDB.getView("($Users)");
			nabDoc = nabView.getDocumentByKey(session
					.getEffectiveUserName());
			result = nabDoc.getItemValueString("InternetAddress"
		} catch (NotesException e) {
			System.out.print(e);
			result = "No NAB Doc";
		} finally {
			recycleDominoObjects(nabDoc,nabView,nabDB,thisDB,session);
		}
		return result;
	}

You can see the finally block passing in all the possible domino objects into the recycleDominoObjects method. Even if one or more of those objects is null because an error happened before they were created I’m still able to recycle the other Domino objects. You will also notice that I’m declaring the domino objects outside the try/catch/finally block. This is because declaring them inside the try block would mean that they are only available to the try block and would not be accessible to the finally block.

In the next part I’m going to optimize that code even more because it still has some serious issues.

Advertisements
Tagged with: ,
Posted in None
Archives
%d bloggers like this: