Getting To The Java Roots of XPages – Part 12

So following on from the last part I now have two packages in the scary.java.demo package, StaffInfo and AboutMe. Both of these classes do pretty much the exact same thing, AboutMe goes to the nab and gets your information while StaffInfo goes to the nab and gets the info for the selected person. As mentioned this introduces a maintenance issue, if the place you lookup staff info changes you will need to change two classes, wouldn’t it be better if you just needed to change one.

You can do this in numerous ways and for this particular way I’m going to simply reference the StaffInfo class from within the AboutMe class. As a result the AboutMe class becomes a lot simpler. Here is the full AboutMe class now after the changes.

package scary.java.demo;

import java.io.Serializable;
import lotus.domino.NotesException;
import lotus.domino.Session;
import com.ibm.xsp.extlib.util.ExtLibUtil;

public class AboutMe implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private StaffInfo myInfo = new StaffInfo();

	public AboutMe() {
	    Session session = ExtLibUtil.getCurrentSession();
	    try {
		myInfo.load(session.getEffectiveUserName());
	    } catch (NotesException e) {
		e.printStackTrace();
	    }
	}

	public String getMyInternetAddress() {
	    return myInfo.getInternetAddress();
	}

	public String getMyCommonName() {
	    return myInfo.getCommonName();
	}

	public String getMyFirstName() {
	    return myInfo.getFirstName();
	}

	public String getMyLastName() {
	    return myInfo.getLastName();
	}

	public String getMyLocation() {
	    return myInfo.getLocation();
	}

}

You will notice that I don’t have individual variables to store the current users information anymore, they have all been replaced with a single variable called myInfo that has a type of ‘StaffInfo’. It was initialized by calling the empty constructor when I was declaring it.

So I have a nice new empty variable called myInfo, next I need to load it up with the current users information. Well my variable has all the public methods that StaffInfo provides so all I need to do it call it’s load() method and pass in the current users name. Like with the previous AboutMe class I’m going to do this directly in the constructor. I get the Domino session and then call myInfo.load() passing in the current user name.

Now the variable myInfo has been loaded with all the relevant user information so my methods in the AboutMe class can just reference them directly by calling the methods in the myInfo variable. So you get the current users commonName I can just call myInfo.getCommonName()

I still haven’t changed anything on the XPage, my bean is still being created the exact same way and the Expression Language is still the same but the business logic code in the backend has changed significantly to be more efficient and easier to maintain in the long run. This java stuff is not so scary.

Tagged with: ,
Posted in None

Getting To The Java Roots of XPages – Part 11

So far I’ve been dealing with a very simple class which just gets the current users information from the NAB, While this is useful wouldn’t it be better if I could get this info for any staff member?

To do this I have created a new class in my java package called StaffInfo. It is VERY similar to the original MyInfo class, in fact all I did was copy the code from that class and make a few minor changes to remove the references to ‘my’. Here is the entire class fro your review.

package scary.java.demo;

import java.io.Serializable;

import lotus.domino.Base;
import lotus.domino.Database;
import lotus.domino.Document;
import lotus.domino.Name;
import lotus.domino.NotesException;
import lotus.domino.Session;
import lotus.domino.View;

import com.ibm.xsp.extlib.util.ExtLibUtil;

public class StaffInfo implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private String InternetAddress = null;
	private String CommonName = null;
	private String FirstName = null;
	private String LastName = null;
	private String Location = null;
	
	public StaffInfo() {
	    
	}

	public void load(String FQName) {
	    Session session = null;
	    Database thisDB = null;
	    Database nabDB = null;
	    View nabView = null;
	    Document nabDoc = null;
	    Name nabName = null;

	    try {
		session = ExtLibUtil.getCurrentSession();
		thisDB = session.getCurrentDatabase();
		nabDB = session.getDatabase(thisDB.getServer(), "names.nsf",false);
		nabView = nabDB.getView("($Users)");
		nabDoc = nabView.getDocumentByKey(FQName);
		nabName = session.createName(nabDoc.getItemValueString("FullName"));
		
		InternetAddress = nabDoc.getItemValueString("InternetAddress");
		CommonName = nabName.getCommon();
		FirstName = nabName.getGiven();
		LastName = nabName.getSurname();
		Location = nabDoc.getItemValueString("Location");
		
		} catch (NotesException e) {
			System.out.print(e);
		} finally {
			recycleDominoObjects(nabName,nabDoc, nabView, nabDB, thisDB, session);
		}
	}

	public String getInternetAddress() {
	    return InternetAddress;
	}

	public String getCommonName() {
	    return CommonName;
	}

	public String getFirstName() {
	    return FirstName;
	}

	public String getLastName() {
	    return LastName;
	}

	public String getLocation() {
	    return Location;
	}

	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?
					}
				}
			}
		}
	}
}

Everything in the above code is stuff that I have explained already but there is a minor change. The empty constructor has no code in it again because there is no way to know at construction time which staff member your looking to get and you can’t pass in any parameter to the constructor so a new public method has been added which contains the code to load in the users information into the variables.

However I’ve just introduced a maintainability issue. I have two classes that pretty much do the exact same thing so in the next part I’ll show how to change the MyInfo class to make use of this class.

Tagged with: ,
Posted in None

Getting To The Java Roots of XPages – Part 10

If I wanted to add some more methods to my class to get additional details it could be as easy as duplicating the code I already have and end up with something like this for each method.

public String getMyIFirstName() {
   if (myFirstName == null) {
      Session session = null;
      Database thisDB = null;
      Database nabDB = null;
      View nabView = null;
      Document nabDoc = null;
      Name tmpName = 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());
         tmpName = session.createName(nabDoc.getItemValueString("FullName"));
         myFirstname = tmpName.getGivenName();
      } catch (NotesException e) {
         System.out.print(e);
      } finally {
         recycleDominoObjects(tmpName,nabDoc,nabView,nabDB,thisDB,session);
      }
   }
   return myFirstName;
}

After creating about 2 methods like this you will start to see how inefficient it is, first of all your duplicating code over and over for each method which will be a maintenance nightmare, secondly you are hitting the nab and doing a document lookup each time the method is being called for the first time.

By reexamining the concept behind what is trying to be achieved you may come to the conclusion that it would be better if you only hit the nab once, loaded all the details and then your individual methods would use the preloaded data.

Remember that Empty Constructor we had

public AboutMe() {
   // Empty Constructor
}

Well that gets called the first time the bean is used so it would be the perfect place to load all the variables. So after moving some code around the constructor now looks like this

public AboutMe() {
	Session session = null;
	Database thisDB = null;
	Database nabDB = null;
	View nabView = null;
	Document nabDoc = null;
	Name nabName = 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());
		nabName = session.createName(nabDoc.getItemValueString("FullName"));
		
		myInternetAddress = nabDoc.getItemValueString("InternetAddress");
		myCommonName = nabName.getCommon();
		myFirstName = nabName.getGiven();
		myLastName = nabName.getSurname();
		myLocation = nabDoc.getItemValueString("Location");
		
	} catch (NotesException e) {
		System.out.print(e);
	} finally {
		recycleDominoObjects(nabName,nabDoc, nabView, nabDB, thisDB, session);
	}
}

and the methods have been simplified to look like this

public String getMyInternetAddress() {
	return myInternetAddress;
}

public String getMyCommonName() {
	return myCommonName;
}

public String getMyFirstName() {
	return myFirstName;
}

public String getMyLastName() {
	return myLastName;
}

public String getMyLocation() {
	return myLocation;
}

So now when the bean is called the first time it will access the nab, find the person doc and load up all the variables and the methods will just return whatever is stored in the variable. This is a lot easier to maintain, if you need to change the lookup database location you just do it in one place and adding additional methods is easier also as there is less duplicated code.

You may also have noticed that I didn’t have to make any changes on the xpage side of things. It is still calling the same bean and method as before. This is a great example of how the UI is separate to the code behind it.

in the next part I’m going to change it all again and make this even more generic and show you a powerful java feature called extending.

Tagged with: ,
Posted in None

Getting To The Java Roots of XPages – Part 9

In the last part we looked at recycling domino handles in java but I mentioned that the class has some other serious issues. The biggest problem that I see now is that every time the getMyInternetAddress method is called it has to access the nab and get the document and return the value.

If I was using this method multiple times on the same page then that would mean multiple calls to the nab and multiple calls to the document and multiple calls to the getItemValueString etc. Unless your internet email address changes a lot then there really is no need to hit the nab multiple times.

Fixing this is very easy but needs a bit of a basic explanation first. When an object is created a space in memory is assigned for the entire object that exists for the life of the object. If I have a viewScope bean that is created from the scary.java.demo.AboutMe class then there is an AboutMe object created that exists for the life of the viewScope. If I set a value of a variable in that bean I can then read that value back later as long as I’m still in the same viewScope session.

So to make my class much more efficient I can store the internet address in a variable, when the getMyInternetAddress method is called the first time it will know that I haven’t set the variable yet and it will go and get the value and put it into the variable before sending it back to the xpage, if I call the method a second time it will know it has the variable and just send it back with no need to hit the nab and find the document which will be much faster.

So how do i do this? Well first I need a variable to store the value in. I’ll create this outside of the method.

private String myInternetAddress = null;

You will notice that I gave it a name that matches the method name but without the get bit at the front, in fact it matches the Expression Language version of the method name. This has been done on purpose and if you follow the series more you’ll find out why. I’ve set this as private which means that only this class can see it, it is a String and I’ve set it to null to begin with.

Now inside my getMyInternetAddress method I just have to add a very simple check, if the variable is null then I get the value from the nab, if it is not null then I know I’ve already gotten it and I can just pass back the value I already have.

Here is the new version of the method

public String getMyInternetAddress() {
		if (myInternetAddress == 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());
				myInternetAddress = nabDoc.getItemValueString("InternetAddress");
			} catch (NotesException e) {
				System.out.print(e);
				myInternetAddress = "No NAB Doc";
			} finally {
				recycleDominoObjects(nabDoc,nabView,nabDB,thisDB,session);
			}
		}
		return myInternetAddress;
	}

It is still not perfect but it is getting there. In the next part I’m going to add two more methods to get a person’s first and last names.

Tagged with: ,
Posted in None
Archives