Thursday, May 31, 2012

Improving performance in Domino Designer when developing XPages

If the XPage has a view data source/the view name is a static value, it looks like Domino Designer is constantly polling the view for column info/etc.

If you are done dragging and dropping columns from the view to the view panel/etc. Go into source mode and compute the viewName.

Before

<xp:dominoView var="view1" viewName="MyView" />

After

<xp:dominoView var="view1" viewName="${javascript:return 'MyView'}" />

When the view name is computed, Domino Designer can't determine what view it should check -> No more lag.

I haven't tested this with Document Data source, but you might get a performance boost if you compute the formName as well, as Domino Designer won't have to check the fields for drag/drop.

Optimally I would wish the Designer team implemented a refresh fields/columns button for the data pane.

Share and enjoy!

Tuesday, May 29, 2012

Using Java reflection and Domino form to auto populate beans

>> Download DemoApp

Due to a lot of positive posts about using beans/MVC pattern for developing XPages apps, I've started writing more Java and less SSJS. I really like the performance improvements/stricter structure of code.

In one of my recent apps, I wrote a Model class for each of the forms in the app. The class has fields for all the form fields. Whilst writing the app, I thought about using Java reflection/Domino Form to auto populate the class instance. Java reflection lets you fetch methods from classes using their name (as a String). The Form class contains methods that lets you fetch all the declared field names in the form.

A couple of advantages to using auto population of fields is less code to maintain (~less bugs), and "auto discovery" of typos in either field names or getters/setters. If you call a field firs_name (typo), and write getters/setters for first_name, using the methodology I use, the code would crash, and you would instantly be aware of some error. If you use some kind of logging, you could look at the stack trace to determine what failed.

A couple of disadvantages. Using reflection/fetching field information adds a slight performance penalty. I don't notice any slowness, but it's something to be aware of if you're aiming for light speed/serving the entire Republic of China on one server. :)

In most of my apps, I use underscores to separate "words" in my field names. To make this work with reflection I convert the underscore field names to ProperCase, and prepend get/set.

E.g.
Field: first_name
ProperCased: FirstName
Getter: getFirstName
Setter: setFirstName

In the attached DemoApp, I have a helper class that deals with the most common field types. It has two methods:
setObjectFieldsFromDocument( String form, Object object, DominoDocument doc )
setDocumentFieldsFromObject( String form, Object object, DominoDocument doc ).

The first parameter is the name of the form that you want to use as "schema" for the population of the instance fields. The second parameter is the Java instance. The third parameter is a Document wrapped in a simple helper class.

The demoapp has a XPage that uses a controller bean (PersonController) to handle interaction with the model (Person). It's bound to view scope. When the XPage is loaded, it checks for a parameter (id). If id is available, the controller uses setObjectFieldsFromDocument to populate the model. When save is called, the controller uses setDocumentFieldsFromObject to update the underlying Notes Document with values from the model.

If this sounds interesting. Download the Demoapp, look at the Person XPage for the data binding, and use Package Explorer to take a look at underlying java code.

I'll just add the source code for the Person model class, in case some of you fear that everything in Java is complex

package com.dontpanic82;

import java.io.Serializable;
import java.util.Date;

public class Person implements Serializable {
 private static final long serialVersionUID = 1L;

 public static final String FORM = "Person";

 private String id;
 private String firstName;
 private String lastName;
 private String email;
 private String homepage;
 private Double age;
 private Date birthdate;

 public Person() {
 }

 public Double getAge() {
  return age;
 }

 public Date getBirthdate() {
  return birthdate;
 }

 public String getEmail() {
  return email;
 }

 public String getFirstName() {
  return firstName;
 }

 public String getHomepage() {
  return homepage;
 }

 public String getId() {
  return id;
 }

 public String getLastName() {
  return lastName;
 }

 public void setAge( Double age ) {
  this.age = age;
 }

 public void setBirthdate( Date birthdate ) {
  this.birthdate = birthdate;
 }

 public void setEmail( String email ) {
  this.email = email;
 }

 public void setFirstName( String firstName ) {
  this.firstName = firstName;
 }
 
 public void setHomepage( String homepage ) {
  this.homepage = homepage;
 }

 public void setId( String id ) {
  this.id = id;
 }

 public void setLastName( String lastName ) {
  this.lastName = lastName;
 }

}