Monday, September 21, 2015

Sorting a Java ArrayList of SelectItem Objects

Recently I had a task where I needed to read all the names from several groups in the Name & Address Book.  I needed to get all the names sorted and unique for presenting in a Combobox.

In this post, I will show you how I did this, but more importantly I will show how I used the Java Collections Framework to my advantage.

In case you aren’t aware, the SelectItem object is the object type that Java Server Faces (thereby XPages) uses for the values of a Combo Box. It contains a value and a label, of which the label is what is shown and the value is what is saved.

Because the SelectItem does not implement the Comparator interface, you cannot easily sort an ArrayList of SelectItems. You could write your own sorting method if you like using the instructions outlined in this blog post. I considered this but then thought of an easier way to accomplish the same thing.

Here is what I did to solve this: Instead of creating just an ArrayList of SelectItems, I also created one of Strings. Strings of course are easily sortable since the String class does implement Comparator interface. Prior to sorting the list, I need to removed duplicates. To do this, I first create a HashSet and assign the values to it. A Set in java does not allow duplicates, so assigning all the values to the HashSet was the easiest way to remove the dupes. After this is done, I assign all the values back into the ArrayList and then sort the list. I then create an SelectItem ArrayList with the unique sorted values.

Note: This would be a lot more complicated if I needed my SelectItem object to have different Strings for Label and Value. I would probably use a HashMap instead of an ArrayList<String> if this was the case.

Code Example


public List<SelectItemgetUserList(String schema){ 
1  List<String> options = new ArrayList<String>(); 
List<SelectItemsortedOptions = new ArrayList<SelectItem>();

try { 
  Session session = getCurrentSession(); 
  Database nab = session.getDatabase(session.getCurrentDatabase().getServer(), "names");

if (nab.isOpen()) { 
View view = nab.getView("Groups"); 
if (view != null) { 
Document doc = view.getDocumentByKey("Group 1"true); 
if (doc != null) { 
Item item = doc.getFirstItem("Members"); 
Vector<String> v = item.getValues(); 
for(String person : v){ 
Name name = session.createName(person);  options.add(name.getCommon()); 
} 
doc.recycle(); 
item.recycle(); 
else { 
log.error("Group 1 cannot be opened."); 
} 
doc = view.getDocumentByKey("Group 2"true); 
if (doc != null) { 
Item item = doc.getFirstItem("Members"); 
Vector<String> v = item.getValues(); 
for(String person : v){ 
Name name = session.createName(person); 
options.add(name.getCommon()); 
} 
doc.recycle(); 
item.recycle(); 
else { 
log.error("Group cannot be found, or opened."); 
} 
……………… //get names from third group 
} 
else { 
log.error("Address Book is not found, or able to be opened."); 
} 
catch (NotesException e) { 
log.error("EXCEPTION in getUserList(): " + e.toString()); 
e.printStackTrace(); 
} 

Set<String> hs = new HashSet<String>();
hs.addAll(options); 
options.clear(); 
options.addAll(hs); 

Collections.sort(options); 

for(String person : options){  
SelectItem option = new SelectItem(); 
option.setLabel(person); 
option.setValue(person); 
sortedOptions.add(option); 
} 
return sortedOptions; 
}

Code Explanation using footnotes:


1  - Declare two ArrayLists, one for Strings, and one for SelectItems.

2  - The values of a multi-value field are returned as a Vector. For each item in the Vector, I assign the item into the String ArrayList

3 - This uses the Name class to get the formatted name. This is part of the original Notes API for java, and is quite useful.

4 -  This is where I pass the contents of the String ArrayList into a HashSet and then back again. All Sets in Java are not able to contain duplicate values. 

5 - After the duplicates are removed, then I sort the list. If you try to sort before removing duplicates it won't be sorted after changing to a Hashset and back. As you can see, sorting a String List is very easy using the Collections class.

6 -  Lastly, I convert the ArrayList of Strings into an ArrayList of SelectItems for use in my combo box.

Last Words


In Java the Collections Framework is super useful and one of the strengths of the language. If you are learning Java it would wise to pay special attention to knowing what it can do for you.  

Please check comments of this post for some great tips on how to improve on what I posted.

Wednesday, September 16, 2015

Quick Tip: Don't Forget to Hide Views from Web Browsers

One item to add to your checklist before deploying a new XPages application is to remember to hide your views from web browsers. The last application I deployed used a DB2 backend for everything but we still used views to hold keyword documents and error messages. If you forget to hide them from the web, then users could use the address bar and type in the view name which could allow users to see data they are not intended to see. Another factor is those default views are cringe-worthy ugly.

I knew that hiding the views was easy, but it actually took me a while to find the setting. I expected to find it in the properties of the view but it isn't there. Of course my next step was to use google to find the answer but amazingly, I couldn't find anything. I started to compose a Stack Overflow question but discovered the answer while composing the question.

The property is in the design properties as shown below.

The design view also has a column that shows whether the view is visible on the web or not. In the XPages world, I can't think of a single reason why you would ever want to show a view to a web browser.


Edit: If you follow the best practice of separating your design and data into two NSF's then you don't have to worry about hiding your views, you would hide the whole database from direct web access. We used a single NSF because all of our data was in a relational backend so our data and design were already separate. Thanks to David Leedy and Jesse Gallagher for pointing this out.

Sunday, August 23, 2015

Using DB2 in XPages Part 10: The MWLUG 2015 Presentation Slides, and Thoughts

MWLUG is now a wrap. I was honored to be chosen to speak along with Dwain Wuerfel on Integrating DB2 and XPages. I am a somewhat bummed that technical troubles limited the demo I wanted to show. Thankfully as I have been told, my backup plan did get my point across. To that end, I have created additional slides to incorporate what I showed in the demo.

I have embedded the demo below, but it might be hard to read, so click here to view directly on slideshare.

The Slides



Real World Experience: Integrating DB2 with XPages from Steve_Zavocki

Youtube Video Link


You can watch the session on youtube here: https://www.youtube.com/watch?v=GVgfWzBomoM

A big thanks to David Navarre for recording the session!

Conference Review


The conference this year was as great for content and making and renewing friendships. If you have never attended an MWLUG conference I can't recommend it enough. Both times I have attended I have paid my own way, and it was money well spent. Next year the conference is going to be in Austin, Texas and they are hoping for 250 attendees. Kudos to Richard Moy and team who are wonderful organizers!


Final Thoughts


Writing this post, it occurred to me that August 23 is exactly three years since I received my first *real world* (ie: paid) XPages experience. On this day in 2012 was when I started working at Harmons Grocery in Salt Lake City, Utah. Harmons was a great experience, and since then I have been further challenged working at Navy Federal Credit Union in Florida. I have very much enjoyed the transition from Notes Developer to a Web Application Developer. I am excited to see what the next three years brings, whether that is XPages, Java, or the latest Javascript frameworks; ideally all of the above and more.