Java Beans and funny stuff

I have such a backlog of posts that I have written and have neglected to post, it is not even funny.  I have a few videos that still need to be edited or redone and it is nuts. So first off, I am sorry for the long breaks in posts, but life tends to get in the way.

Today I was working with an apprentice and getting him involved with XPages.  He seems to enjoy it so far, and it is a help for me because I give some of the more mundane things to him.  He has zero Notes/Domino experience and has focused primarily on .NET development.  If you go to derultimativeligatipp.de, you can see a bit of his handy work.  Of course he worked with another apprentice of ours to build that site, and I must say together they built one awesome application.  But I digress.  Of course I think our apprentices are amazing, but we want to quickly discuss our adventures of the day with Beans and XPages.

As readers may or may not be aware, I have spent a great deal of time developing a standard java library that I use in all of my XPage applications for use both internally and for customers.  It includes custom controls, standard beans, and now a configuration.  But a simple configuration was not good enough for me.  Let me quickly get into my use case.

Up until now, I have been using a file saved under the Resources/Files tab of the project.  I wanted to get around needing profiles which can be a cached pain in the rear, I originally did not want to have a view to look up a specific document, and I did not want to touch the xsp.config xml file. Of course there are some wonderful snippets available from Paul Withers in case you would prefer that approach.  I wanted to save values that differ from database instance to database instance, as well as from dev version to QA version to productive version.  As far as I am aware, performing a design refresh also rewrites the config.xml file.  Really the best way to get the functionality I wanted was a good old fashioned NotesDocument, a good old fashioned view, and the wonderful ODA view method “getFirstDocumentByKey()”. #ODAOnceMoreForTheWin .

This brought on interesting points that I could discuss with the apprentice: abstract classes, Beans, and expression language.   I wanted to build the following structure:

AbstractConfig
-contains the view alias for lookups which will be used for all XPage configurations
-abstract init() method
-abstract getLookupKey() method
-a few other methods that are sensible for our use case but may not be needed for all.

AbstractDashboardConfiguration => AbstractConfig (just an example)
-implements init() to fetch the needed data
-protected final Strings for each field in the NotesDocument
-private members for each field value and the appropriate getter/setters

DashboardConfigurationDocument => AbstractDashboardConfiguration (just an example)
-save() implementation
-specific XPage rendering helper functions
-is set up as a viewScope variable

DashboardConfiguration => AbstractDashboardConfiguration (just an example)
-Specific methods to use a re-init interface that I built so that all of my applicationScoped beans can be reinitialized with a click of a button by an admin
-obviously applicationScoped

As you can see, the build up is pretty complex, and this is the easiest of examples.  There are probably a few “WTF?” questions that I should touch upon, so let me get to them first.

First off, I am sure the reason for an AbstractConfig class is clear.  When all configuration documents are already being saved in the same view, then why not.  Certain fields need to be set in order to guarantee that they are displayed in the correct view. Also, why should the name of the view be set in each configuration class?  It just makes sense to have a single abstractconfig java class.  But, the question that probably comes to mind is, why is there a need for another abstract class before the real implementation?

The answer is pretty simple: I hate StackOverflowExceptions.  I started to create two classes to handle configuration information.  One bean would be responsible for saving and editing the information (DashboardConfigurationDocument), and the other would be responsible for caching the information in the applicationScope (DashboardConfiguration).  Without the abstract class I am left with the following conundrum…..

It is clear that DashboardConfigurationDocument should get it’s information from the document… I mean….  it is sort of implied in the name.  It should also save itself. It then needs to inform the applicationScoped DashboardConfiguration bean that it should refresh its data. This data could be read from DashboardConfigurationDocument to get around needing to write the int() function twice.  Right there we have a problem because we have two classes that call each other.  It just makes the most sense that both of these classes have the same key functions and members in the abstract version, and the rest of the key implementation in the concrete classes.  It makes for a much cleaner implementation at the cost of hereditary chaos.  🙂   Truth be told I find it awesome.

The second major question that I should directly address is, why do I just not save the DashBoardConfigurationDocument bean in the application scope? Basically I am a control freak wanting to do crazy things.  No….  I assure you that I have a reason.  Let’s look at lazy admin A and multi-tasker admin B.  Admin A makes a single change, directly in the appScoped bean before going for coffee, and admin B gets a phone call after doing the same.  Neither are finished with their changes, neither of them had to save the changes explicitly, yet both of the have a change that is already potentially putting the application in an unstable state.  Baaaaaaaddddd  vooodooo….  baaaaaaaadddddd.  For this reason, I also like to separate my editing logic from my global configuration logic. Additionally, I can have XPage UI specific logic in the viewScoped class without feeling guilty about caching stupid spam members in the appScope bean.

I can use this pattern as often as I want, and I can be sure that I do not forget anything.  All of my field names are saved as final strings and I can use them in other sub-classes if I need to.  I can even decide later that I want to override my save function in another bean to get SQL support or whatever. It is just clean, and I like clean.

After taking some time to explain a lot of this to the apprentice, we dove into Expression Language and getting some good old binding done.  It worked like a charm…. almost.

This goes into another crazy use case.  I only wanted one configuration XPage.  I have an enum where I have specific configuration keys saved.  These values are then presented to the user in a combobox where a specific configuration key can be selected, and the document is opened, and the information is displayed.  We did this with Expression Language.  The ComboBox held string values representing each of the values in the enum, and the bean had the necessary getter and setter to take the string and set the enum value for that document.  This setter also triggered a process whereby the configuration was fetched and the values were refreshed.  It was a thing of beauty until we realized that the values were not being refreshed on the XPage although the values in the bean were being refreshed with the contents of the NotesDocument.  It took us two hours to figure this issue out.  The correct getters/setters were being called, the init() function was being called, the correct document was being retrieved, and the values were correct in the bean.  Why were they not refreshed on the XPage?

First off, I thought it was a simple refresh problem.  The errorMessages control displayed no errors, and I thought that it was just a simple case of needing to either perform a full refresh, a refresh directly on the component, or some other crazy thing.  We messed around without any success.  In the end, this was one instance where a simple EL expression just was not enough.  We saw that the EL expression was calling the correct methods;  the onChange partial refresh on the page was working correctly.  My suspicion is that the partial refresh was being performed faster than the methods called by the EL expression.  We took out the EL data binding and instead implemented a SSJS function calling the setter method for the configuration key.  When we did this, everything worked as planned.  We also now have one page that can be used for multiple similar configuration documents that can easily be extended without changes in the design.

Lesson learned:  Java is awesome, EL is cool, but ssjs still has to be used for certain things.

XPage Java dev Tutorial 2 – AdminPanel prt 1


 

General Feels and Gratitude

Hello Everybody!!  Today I am really happy to present my first NotesIn9 video!  It was really great being able to make this sub-series and be a part of the tutorials that really got me going with XPage development.  I want to thank David Leedy for giving me the opportunity as well as thank my employer for allowing me to use what I learn on company time to create content for others.  This is turning out to be a hobby that is really starting to take off.  Again, I have to thank twitter, David Leedy, and Paul Withers for sharing my first blog posts and spreading the word that this blog is out and about.  I would not be so into this right now if it were not for the fresh feeling of being able to do good for others and not just use this website as my own knowledge repository. Thank you to those who read these posts, watch the videos, and of course who retweet, comment and like what I am doing.  All that really makes it easier to stay motivated.


 

Down to Business

What is this mini/sub -series all about?

As you may or may not be aware, everything that we are doing here has a basis in my day to day development.  I started out using java for my xpage dev about a year ago (I had already used java extensively in my daily programming, just not in combination with XPages for which I mostly relied on JavaScript.) To really get started with Java, I decided to make a utility package that included everything that I needed to know to really get going.  I started off with making a sessionHelper.  I did this because I needed to learn how to get a session object.  I did not know anything about the variable resolver at first, and I also had a lot of trouble finding resources to figure it out.  After I managed that, I moved on to one of the most important features of all databases that I develop, the Admin Panel.

The Admin Panel is (currently) a custom control where I store tables that show the variable names and values of all objects located in the applicationScope, the sessionScope, and the viewScope.  I do not waste my time with the requestScope, although I suspect that such a thing would be possible if I found a use case for it.  Additionally to this, I show another HTML table that presents cookie information.  This is a part of another module that I call “the cookie helper”.  Finally, a larger and more complex table presents logging information to the user with a particular role.  The custom control contains functions that erase the variables located in the scoped maps (although I have not made that work without causing errors) add string variables to the scopes (not very helpful, but cool), and delete logging information shown in the debug section of the admin panel.  A great feature of the debug table is that there are six different error levels that all use different row styles.  This allows the trace information to be shown in a more understated way, and fatal errors to pop out like a sore thumb.  Later, I turned this same functionality around to store and show entire session logging documents in a logging database.

Today we are going to look at how to build your own Admin Panel using information built, retained, and retrieved in Java.

How is this sub-series built?

Due to time, I broke this down into three different parts.  Since I am actually coding on camera as much as possible, it is taking a while to get through it.  I am doing this so that you can see where I have difficulty, so that you can hear me commenting as I go, and because my entire concept in this Java Tutorial is to program an application from start to finish together.  When it is just taking too long and when I do not have a lot to say, I do edit out some parts.

Part one (this part) is going to be a basic introduction.  We do, for this one time only, go through a PowerPoint presentation where I go into what we are doing, the three parts, and some basic information about myself.  One thing that changed from the making of the PowerPoint slides to the videos is that the concept had to be changed from asking question before the recording of the next part to all the questions being asked in comments and through email and me answering them in a written format or in a fourth video.  It makes sense for numerous reasons, but we do not need to get into that.

Part two is primarily Java construction.  Although some Java classes were started in the first part, in part two we really get going.  I do not want to spoil it too much here, but we basically finish up all the beans that we are going to need for the custom control.

Part three is being my slight PITA.  I recorded it once already, but am not pleased with how it turned out.  I really need to stop doing my recordings after 1 AM.  I am going to be deleting the changes and redoing the video.  Part three includes registering the beans that we already made with the faces-config.xml file and designing our custom control.  We go into how to add a few custom properties, although we admittedly do not go into every detail that you could possibly go over.  There are numerous NotesIn9s if you need help specifically with Custom Controls.

 Why is this a sub-series?

This is a sub-series because it is a small part in the project that we are building together.  I was trying to find some way to make videos for this page’s main tutorial while also making content for NotesIn9.  I decided that it would be awesome to make some of the content that can really stand alone its own sub series and give them to David Leedy.  For those who follow along here, it should seem pretty seamless.  To those who watch the NotesIn9s, it is my hope that you can watch that content and get what you need without too much knowledge of what we are doing in the rest of the tutorials.  At any rate, I am posting the code on this website.  That being said, without any further ado- I give you the video, and following the video, the code!  Enjoy!


Video

Find the video here!


Code

COMING SOON!

XPage Java dev Tutorial 1

Greetings!!

The time has finally arrived for the first tutorial in XPage Java development.  In this tutorial we will learn how to get a handle on the current session in both the opentNTF Domino API (ODA) and the lotus domino API.  We will briefly go over what we did last time, and we will really hammer out some java code.  Stay tuned for next time when we will actually use Java and Custom controls to log data out to the user/XPage_Admin!!  That tutorial is planned to be given to David Leedy to be shown on NotesIn9!  Please make sure that you take a look at the comments that I added to the code which is displayed below!

Happy Programming!


 


 

package com.reederprogramming.utils;

import java.io.Serializable;

import javax.faces.context.FacesContext;

import org.openntf.domino.utils.Factory;

import com.ibm.xsp.extlib.util.ExtLibUtil;
import com.reederprogramming.exceptions.NullDatabaseException;
import com.reederprogramming.exceptions.NullSessionException;

import lotus.domino.Database;
import lotus.domino.Session;

/**
 * This class is going to contain key methods for dealing with the current session.
 * It implements Serializable in case I want to put this class in the sessionScope later and
 * use from JavaScript as well.  This may not be necessary, but it is easy to implement the interface
 * and take it out later if I need to, or leave it in since it does not hurt anything.
 * Note that all java beans MUST implement Serializable if they are going to be retained in server
 * memory.
 * 
 * @see java.io.Serializable
 * 
 * 
 * @author Greg@reederprogramming.com
 *
 */
public class SessionHelper implements Serializable {

	
	private static final long serialVersionUID = 2014071001L; //yyyyMMdd0v
	
	/**
	 * This is an example of how to get the current database using the utility class provided 
	 * by the Extension Libraries.  Alternatively, you could alter the getCurrentSession() to
	 * return the database.  Alternatively, you could also create an enum that includes all of
	 * valid strings and use that to get the object you desire from the VariableResolver.
	 * 
	 * @return returns an instance of the lotus.domino.Database.
	 * @throws NullDatabaseException thrown when the current database is null.  Should never happen, but
	 * can during multi-threading operations.
	 * @see lotus.domino.Database
	 * com.reederprogramming.exceptions.NullDatabaseException
	 * 
	 */
	public static Database getCurrentDatabase() throws NullDatabaseException{
		Database d  = null;
		d = ExtLibUtil.getCurrentDatabase();
		if(d == null){
			throw new NullDatabaseException("The current database could not be found!");
			/* This is an example of a checked Exception.  It must be handled or else the 
			*  compiler will yell.
			*/
		}
		return d;
	}
	
	/**
	 * This method shows two different examples.  The first one is how to get the 
	 * current session and the current database using the Factory enum provided by ODA
	 * 
	 * @see org.openntf.domino.utils.Factory
	 * @see org.openntf.domino.Database
	 * @see com.reederprogramming.exceptions.NullDatabaseException
	 * @return returns an instance of org.openntf.domino.Database from the ODA.
	 * @throws NullDatabaseException thrown when the current database is null.  Should never happen, but
	 * can during multi-threading operations.
	 * 
	 */
	public static org.openntf.domino.Database getCurrentODADatabase() throws NullDatabaseException{
		org.openntf.domino.Database d = null;
		d = Factory.getSession().getCurrentDatabase();
		if(d == null){
			throw new NullDatabaseException("The current database could not be found!");
		}
		return d;
	}
	
	/**
	 * This method displays a few things.  First off, we see how to check to see if an object is 
	 * the same as another class, and then we perform a cast to a higher level object.  Additionally,
	 * we see how to use the variableResolver to get the session instance.  This will be the same
	 * session object as returned by the session JavaScript keyword variable.
	 * 
	 * We also see an example of the FIX-ME and TO_DO keywords to aide with development processes.
	 * 
	 * @see lotus.domino.Session
	 * @see com.reederprogramming.exceptions.NullSessionException
	 * 
	 * @return returns an instance of the lotus.domino.Session class
	 * @throws NullSessionException
	 */
	public static Session getCurrentSession() throws NullSessionException{
		Object o = null;
		Session s = null;
		
		FacesContext context = FacesContext.getCurrentInstance();
		o = context.getApplication().getVariableResolver().resolveVariable(context, "session");
		if(o instanceof Session){
			s = (Session)o;
		}
		if(s == null){
			//FIXME add logging!!
			//TODO this must be expanded.
			throw new NullSessionException();
		}
		return s;
	}

	/**
	 * This is a similar example to the getCurrentDatabase() where we use the Extension Library utility
	 * class to get a handle on the current session.  This assumes that the Extension library is used
	 * and will always be used.  Becauase this is a class that should always be available, such an
	 * approach may not be wise.
	 * 
	 * @see com.ibm.xsp.extlib.util.ExtLibUtil
	 * @see lotus.domino.Session
	 * @see com.reederprogramming.exceptions.NullSessionException
	 * 
	 * @return returns an instance of the lotus.domino.Session class.
	 * @throws NullSessionException
	 */
	public static Session getCurrentExtLibSession() throws NullSessionException{
		Session s = null;
		s = ExtLibUtil.getCurrentSession();
		if(s == null){
			//FIXME add logging!!
			throw new NullSessionException();
		}
		return s;
	}
	
	/**
	 * This method illustrates how to get a handle on the current session using ODA.  This is only
	 * one possible way.  Furthermore, it shows how to wrap a normal lotus.domino object (they will always extend
	 * lotus.domino.Base) and return an ODA object.  According to one of the authors (Paul Withers), 
	 * it is however preferable to use the Factory.getSession() method.
	 * 
	 * @see org.openntf.domino.Session
	 * @see com.reederprogramming.exceptions.NullSessionException
	 * @see org.openntf.domino.utils.Factory
	 * 
	 * @return returns an instance of org.openntf.domino.Session
	 * @throws NullSessionException
	 */
	public static org.openntf.domino.Session getCurrentODASession() throws NullSessionException{
		/* 
		 * if you look at the above method declaration, you will notice that I am 
		 * specifying which Session object should be returned.  This is done because other
		 * methods in this class work with the lotus.domino.Session class. I must insert the full
		 * name (including package) in order to prevent ambiguity.  I can, however, debate if
		 * either of them should be imported, or which one makes more sense to import.
		 */
		
		//TODO change this method to simply use the getSession()  This is only for the sake of example
		org.openntf.domino.Session s = null;
		s = Factory.fromLotus(getCurrentSession(), org.openntf.domino.Session.class, null); 
	   
		/* 
		 * normally we would have to catch the NullSessionException given by the getCurrentSession().
		 * in this case, it just makes more sense for it to bubble up to the next method and let it deal with it.
		 */
		if(s == null){
			//FIXME add logging!!
			throw new NullSessionException("Missing session of type: " + org.openntf.domino.Session.class);
		}
		
		return s;
	}
}

 

package com.reederprogramming.exceptions;

/**
 * This is an Exception class to mark that a session object could not be returned.
 * It can be used for ODA or for lotus.
 * 
 * @author greg@reederprogramming.com
 */
public class NullSessionException extends Exception {
	
	private static final long serialVersionUID = 2014071001L; //yyyyMMdd0v

	public NullSessionException() {
	}

	public NullSessionException(String arg0) {
		super(arg0);
	}

	public NullSessionException(Throwable arg0) {
		super(arg0);
	}

	public NullSessionException(String arg0, Throwable arg1) {
		super(arg0, arg1);
	}

}

 

package com.reederprogramming.exceptions;

/**
 * This is an Exception class to mark that a Database object could not be returned.
 * It can be used for ODA or for lotus.
 * 
 * @author greg@reederprogramming.com
 */
public class NullDatabaseException extends Exception {
	
	private static final long serialVersionUID = 2014071001L; //yyyyMMdd0v

	public NullDatabaseException() {
		super();
	}

	public NullDatabaseException(String arg0) {
		super(arg0);
	}

	public NullDatabaseException(String arg0, Throwable arg1) {
		super(arg0, arg1);
	}

	public NullDatabaseException(Throwable arg0) {
		super(arg0);
	}

}




A few Years of XPage Developement – Part 5

Fixing River – opentNTF Domino API

Introducing “openNTF Domino API”

This jewel has been created by a few wonderful developers with tier 5 status, XPage God.  (Yes, I skipped Tier 4 for now).  Developers with XPage God status are those that can create content that no developer can live without.  That content can be pure backend, controls, or both.  Up until now, I have only scratched the surface of what this beast can do.  Its main draw for me was that recycling is a thing of the past.  This was something that should have been done a long time ago by IBM itself.  If we do not have to clean up our objects in Lotusscript, why should we have to do so in Java?  But that is only the first of many improvements.  Iterating through documents in a DocumentCollection has become much simpler.  No longer must you use a while loop that quickly turns into an infinite loop that eventually crashes the HTTP task of the server.  Additionally, error handling is improved.  When an error occurs, the information is saved in files on the server, and if an openLog database is located on the server, the error information is saved there too.  No longer must you play with the NotesException class (a horrible invention to say the least, being the only Exception that I know of where the “getMessage()” method always returns null and that introduced the .Text public property).  The uses for this API are too many to list here.

Since the openNTF Domino API, or ODA as I like to call it, is so important, I have since made it a requirement for hxu version 3.  I have also updated all of my internal databases to incorporate that API.  Once I figured out how to get started with it, using the API is the simplest thing to do.  The methods are almost the same as the IBM Domino API.  The biggest advantages, however, are what to do if you have an issue.  The people who wrote the API are active members of StackOverflow.  If something does not work, you are unsure how to get started, or you get some strange error, write to the original authors via those forums, openNTF, or directly and get help.   Ask for such service from IBM, I dare you.

Future Outlooks

This brings us to the current day and the advent of a Tier 4 XPage developer, “Xpage Sith Lord”.  To Understand Lord status, let’s take a look at the current problem produced by all of my internal databases.  So far, I have about 6 internal active XPage applications.  This is not including development and QA copies.  Each of these applications relies on the hxu jar.  Furthermore, key properties are stored in a file under Resources/Files in the database itself.  Certain controls and libraries are being copied into each database instance.  When hxu changes, all applications implementing hxu must be changed individually.  This is starting to become a bit of a hassle.  Those with Lord Status no longer write stuff for a single database, but rather create OSGI plug-ins that can be easily installed on the server level affecting all applications which have those marked as required.  Controls and libraries need no longer be copied and pasted into new projects, properties can be saved in the xsp.properties file or in the domino notes.ini, and everything can be centrally controlled.  I have a long way to go before I can say that I have reached tier 4, but I can say that I recognize the next steps in my progress as a Notes XPage developer.