Building an App with the frostillic.us Framework, Part 3

Thu Jul 17 14:19:39 EDT 2014

Tags: xpages
  1. Building an App with the frostillic.us Framework, Part 1
  2. Building an App with the frostillic.us Framework, Part 2
  3. Building an App with the frostillic.us Framework, Part 3
  4. Building an App with the frostillic.us Framework, Part 4
  5. Building an App with the frostillic.us Framework, Part 5
  6. Building an App with the frostillic.us Framework, Part 6
  7. Building an App with the frostillic.us Framework, Part 7
  1. Define the data model
  2. Create the view and add it to an XPage
  3. Create the editing page
  4. Add validation and translation to the model
  5. Add notification to the model
  6. Add sorting to the view
  7. Basic servlet
  8. REST with Angular.js

On the scale of "bog-standard" to "weird", the next phase of writing a frostillic.us Framework app sits in the middle: the basic steps of creating a model-editing page are pretty standard, but you can use unique aspects of the Framework to save a bunch of coding and add some nice dynamic features.

Create the editing page

The first step to adding the ability to create and edit notes is to adjust the main note-list page to add a button to actually create one. In my standard layout custom control, I have a facet area named "ActionBar" to add buttons to the top of the page:

<xc:layout navigationPath="/Home">
	<xp:this.facets>
		<xc:linksbar xp:key="LeftColumn" />
		<xp:div xp:key="ActionBar">
			<xp:link themeId="Button.Command" value="/note.xsp" text="New Note"/>
		</xp:div>
	</xp:this.facets>
	
	...
</xc:layout>

I like to use normal links for going to the editing page rather than an "openPage" simple action to avoid the extra round trip. By giving it the "themeId" of Button.Command, it ends up with styling that looks more like a button than a link.

Now that that's over with, we move on to the actual editing page. So we create a page named "note.xsp" and add in our basic surrounding XSP and the data source:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xe="http://www.ibm.com/xsp/coreex" xmlns:xc="http://www.ibm.com/xsp/custom" xmlns:ff="http://frostillic.us/framework"
	beforePageLoad="#{controller.beforePageLoad}" afterPageLoad="#{controller.afterPageLoad}" pageTitle="Note">

	<xp:this.data>
		<ff:modelObjectData var="note" managerName="Notes" key="${empty param.id ? 'new' : param.id}"/>
	</xp:this.data>
	
</xp:view>

You can see a couple Framework-isms here: the "ff" namespace for the model data sources, the "beforePageLoad" and "afterPageLoad" events bound to the implied controller class, and the model data source itself. That data source takes the place of the traditional xp:dominoDocument element when using Framework model objects. It has two important properties: "managerName", which is the managed bean name of the manager class to fetch the object from, and "key", which tells the manager to either fetch an existing object by ID (for Domino-backed model objects, the document UNID) or create a new one. For this, I use the ternary operator in EL to check to see if there was an ID passed in via URL - if so, use that ID; otherwise, tell the manager to create a new model. Think of this as the difference between visiting a xp:dominoDocument-using page with action=editDocument&documentId=XXXX and with action=newDocument.

Now, on to the actual "form" portion. For traditional label/field sets, I'm a fan of using the ExtLib's xe:formTable and associated controls, since it's very focused on declaratively describing the form, and then I can use custom renderers to modify the look as I see fit. So let's toss one of those on the page:

<xe:formTable formTitle="Note">
	<xe:this.facets>
		<xp:div xp:key="footer">
			<xp:button id="save" value="Save">
				<xp:eventHandler event="onclick" submit="true" refreshMode="complete" immediate="false" save="true"/>
			</xp:button>
		</xp:div>
	</xe:this.facets>

	<xe:formRow binding="#{controller.components[note].Title}"/>
	<xe:formRow binding="#{controller.components[note].Body}">
		<xe:djTextarea/>
	</xe:formRow>
</xe:formTable>

So far, so good, right? That is, except for that "binding" business. That's the fruit of my recent dabbling in the potential uses of that property. Think of that as telling the back-end framework code that the two rows represent, respectively, the "Title" and "Body" fields of the given note object specifically, and asking it to fill in the messy details. As a result, the framework looks up an appropriate label for the field (by default, just the name of the field in the model, but it also looks for a human-friendly and translated version, which I'll get to in the next entry), creates an input component if one hasn't been provided, and attaches any appropriate validators, converters, and date/time helpers.

There are two types of use here: for the "Title" field, just a plain text box will do, which is what the controller does in the absence of other direction; for the "Body" field, however, I want to use Dojo's auto-expanding textarea control, and so placing one inside the form row will cause the controller to pick up on it and use the existing control rather than adding a new one. We haven't added any extra validation or type information to the model yet, so the result is basic:

There's one last bit of housekeeping to add: sending the user back to the main home page after saving a note. I use navigation rules for this purpose, and this syntax matches what you get if you set the "Next page (success or cancel)" option in the XPage's properties pane:

<xp:this.navigationRules>
	<xp:navigationRule outcome="xsp-success" viewId="/home.xsp"/>
</xp:this.navigationRules>

And that's it! Other than a few Framework-isms in the areas of the data source and the binding code, the result is pretty similar to a page you'd get using traditional methods. In the next entry, I'll spruce things up a bit: adding in some validation, a different field type, and a dash of translation.

Building an App with the frostillic.us Framework, Part 2

Fri Jul 11 18:01:48 EDT 2014

Tags: xpages
  1. Building an App with the frostillic.us Framework, Part 1
  2. Building an App with the frostillic.us Framework, Part 2
  3. Building an App with the frostillic.us Framework, Part 3
  4. Building an App with the frostillic.us Framework, Part 4
  5. Building an App with the frostillic.us Framework, Part 5
  6. Building an App with the frostillic.us Framework, Part 6
  7. Building an App with the frostillic.us Framework, Part 7
  1. Define the data model
  2. Create the view and add it to an XPage
  3. Create the editing page
  4. Add validation and translation to the model
  5. Add notification to the model
  6. Add sorting to the view
  7. Basic servlet
  8. REST with Angular.js

The first stage of building a frostillic.us-Framework-based app was a bit unusual - focusing on creating a model object in Java - but the next phase is about as bog-standard as it gets:

Create the view and add it to an XPage

The view we'll need is a basic one showing all Notes. We'll name it "Notes\All" to match the expected prefix in the model and add our two expected columns: Title and Body. The model classes work with sortable columns, so we'll make Title sortable:

Once we have the view, we can refer to it in EL in an XPage as #{Notes.all}. For demo purposes, we'll drop it on the page using a standard xp:viewPanel - not the fanciest presentation, but it'll get the job done:

<xp:viewPanel value="#{Notes.all}" pageName="/note.xsp">
	<xp:this.facets>
		<xp:pager xp:key="headerPager" id="pager1" partialRefresh="true" layout="Previous Group Next" />
	</xp:this.facets>
	
	<xp:viewColumn columnName="Title" displayAs="link">
		<xp:viewColumnHeader value="Title" sortable="true"/>
	</xp:viewColumn>
	<xp:viewColumn columnName="Body">
		<xp:viewColumnHeader value="Body"/>
	</xp:viewColumn>
</xp:viewPanel>

Here, I'm using value="..." to specify the data source. There is also a normal data source for model collections, but it's rarely needed - the EL syntax is much more concise and clear, and it works well with relations (e.g. #{note.responses}). I also specify a pageName="..." for the generated links, since $$OpenDominoDocument URLs won't help here. I may add something to assist with that down the line, but for now specifying the page will do.

Other than those, though: pretty standard stuff. That's one of the goals of the framework: when it makes sense to do things the standard way, I want to do that - no need to reinvent every wheel. So the lists extend TabularDataModel in addition to implementing List and the model objects themselves implement ViewRowData in addition to DataObject.

The next topic - creating an editing page - continues this trend of working with the standard components while cutting out as much hassle as possible.

Building an App with the frostillic.us Framework, Part 1

Wed Jul 09 10:18:00 EDT 2014

Tags: xpages
  1. Building an App with the frostillic.us Framework, Part 1
  2. Building an App with the frostillic.us Framework, Part 2
  3. Building an App with the frostillic.us Framework, Part 3
  4. Building an App with the frostillic.us Framework, Part 4
  5. Building an App with the frostillic.us Framework, Part 5
  6. Building an App with the frostillic.us Framework, Part 6
  7. Building an App with the frostillic.us Framework, Part 7

Now that the framework I've been building is settling into a real project, I figured one of the best ways for me to explain how it works and to double-check my own assumptions is to make a tutorial on how to actually construct an app using it. This will be a very simple one to start with: a note-taking app with just a couple fields and only one business object to speak of.

The overall conceit of the framework is that it uses standard/ExtLib components and idioms where appropriate but declares its own new idioms when the standard ones are deficient. This is done in a way, though, that is opt-in at each step. Though this app is positively stewing in the "Jesse" way of doing things, each component - controllers, models, servlets, etc. - can operate independently and alongside other methods of XPage development.

Probably unsurprisingly, writing a fully framework-based app is heavy on Java and uses some aspects that may be strange at first (annotations, namely), but I hope that the tutorial will explain why I go this route, and that it will demonstrate how using Java in this way can save a tremendous amount of programming and eliminate swaths of potential bugs.

I have a tentative plan for the series, and I'll adjust this list and add links as appropriate:

  1. Define the data model
  2. Create the view and add it to an XPage
  3. Create the editing page
  4. Add validation and translation to the model
  5. Add notification to the model
  6. Add sorting to the view
  7. Basic servlet
  8. REST with Angular.js

Without further ado, on to part 1:

Define the Data Model

Technically, I should start with part 0: set up the framework. As of this writing, I haven't packaged it up on OpenNTF yet, but I've created a ZIP file containing a current build, the NTF I use to create these apps, as well as the OpenNTF API from my branch - the framework relies on some features not yet released in an API milestone release:

frostillicus.framework-20140709.zip

Requirements-wise, you'll probably need 9.0.1 (the ExtLib that ships with it should suffice) and I haven't tested it on a server without AllPermission granted to all Java.

Now that that's out of the way, on to the actual code. To start with, we'll create the class that represents our core data model - the Note (in the note-taking sense) - and its Manager class. Domino-based model classes in the framework extend the frostillicus.xsp.model.domino.AbstractDominoModel class, while the Managers extend frostillicus.xsp.model.domino.AbstractDominoManager and are kept in the model package:

package model;

import javax.persistence.Table;

import frostillicus.xsp.bean.ApplicationScoped;
import frostillicus.xsp.bean.ManagedBean;
import frostillicus.xsp.model.domino.AbstractDominoModel;
import frostillicus.xsp.model.domino.AbstractDominoManager;

@Table(name="Note")
public class Note extends AbstractDominoModel {



	@ManagedBean(name="Notes")
	@ApplicationScoped
	public static class Manager extends AbstractDominoManager<Note> {

		@Override
		protected String getViewPrefix() {
			return "Notes\\";
		}
	}
}

So! What's going on here? Quite a few things, and just as important are the things that are not going on, such as code to declare all of the fields and each pertinent view's capabilities. Nonetheless, it's still a whole pile of Java concepts - this is the part that's the most unusual from a standard-XPages-dev perspective.

  • Right at the start of the class, you see @Table(name="Note"). This is part of my overall attempt to borrow aspects of the Java Persistence API and Hibernate when appropriate. Normally, @Table refers to a SQL table, but I'm using it here to declare the form name to use when creating documents. This may change in future versions.
  • There are no getters/setters (or other methods) in the Note class! These objects implement DataObject and so the standard way of accessing data is via getValue(...) and setValue(...). There are ways to add special behavior - complex getters, validation, and types - but the default behavior is to mimic the Domino way of just storing anything with any name.
  • The Manager class is stored as what's called an "inner class" in Java. It's a way of storing multiple related classes inside a single .java file. The full name of the class is a combination of the two names - so if you import the Task class in another file, the manager is named Task.Manager.
  • I'm using @ManagedBean annotations. These are something I tossed together a while ago based on how managed beans can be done in newer versions of JSF. In essence, these annotations let you specify the name and scope of your beans in-line with the code, without adding them to faces-config.xml. The result acts just the same way.
  • The only method specified in the Manager class is to provide a standard prefix for accessing views. I'll demonstrate using that later, but this is specified here to encourage the idiom of naming views like "Notes\All" or "Notes\By Day". It's not required, but following it saves some code elsewhere.
  • The Manager is also the place where you can specify an external database to house the data, but I'm not doing that here.

It's a strange bit of code, but my hope is that each line is clear once you understand the concept. My aim is to, as much as possible with Java, make the code in the model classes focus on specifying what the object does and where it's found, not on the messy business of actually retrieving and storing it (while also avoiding the configuration headaches of full JPA/Hibernate).

In the next post in the series, I'll cover adding a view for these documents to the DB and to an XPage.

The Trouble With Developing on Domino

Tue Jul 08 10:57:51 EDT 2014

Tags: domino

The core trouble in my eyes with developing on Domino is that it is unloved for what it is. Not so much by customers (I have no interest in whether companies use Exchange or SharePoint or whatever), but more by IBM. The situation reminds me of Apple with products like WebObjects, Xserve, and Aperture: there's clearly a dedicated and talented team behind it, but the organization's heart isn't in it. The analogy is inexact: first, Apple's overarching motivations and strategies are much easier to grok than IBM's; second, enterprise software never really dies - it just goes all COBOL and lingers in maintenance somewhere forever (did you know OS/2 is still a thing?).

So Domino is still around, and still exists, but is generally positioned as something for large companies to use for mail, or continue using if they happened to start doing so decades ago, or as an adjunct to Connections. But it's like with Lotusphere's rebranding: when (dev conference) + (biz conference) = (biz conference), the algebra to figure out the perceived value of (dev conference) isn't difficult. To a certain extent, this is just how IBM does business: they talk to large organizations' higher-ups and make their sales that way, not by being outwardly compelling. However, on this front, Bluemix's entry has provided a telling counter-example: though there's still the stock over-puffed business page, the bluemix.net site talks directly to developers using a layout and writing style that an actual human being might enjoy. They even have honest-to-goodness Developer Evangelists!

It leaves us, as Domino developers, in an awkward position. We have a full-fledged NoSQL server with an integrated Java dev stack, albeit one without a guiding soul. We have an easy-to-install, flawlessly-clustering, cross-platform server that is perpetually 20% away from being perfect for the modern world. Large portions can be charitably characterized as having been in maintenance mode for a long time: the core API, SSL in all protocols, calendar/contacts connectivity, indexing, the admin client, and so forth. The bad news is easy to perceive: less vendor interest and customers driven primarily by inertia make for a poor career path. But the point of this post isn't doom and gloom! The way I figure it, there are a number of bright sides to explain why I and others continue to develop on this platform:

  • There's always a chance that Domino will be less "Xserve" and more "Mac Pro", a product seemingly at death's door for years until it was given a fresh breath of life.
  • As Paul Graham pointed out years ago, when you're writing server-run software, you can use whichever platform you'd like. Though, all else being equal, it's nicer to have a popular platform, if you can use the tool to do greater work with your time than you would elsewhere, it's worthwhile.
  • Due to Domino's nature, almost all of its (technical) problems are solvable even if IBM never touches it again. Some of them, like the API, are things where the community has already built a workaround. Some, like SSL for HTTP, have seen IBM package their own workaround with the server. And the rest, like NIF and CalDAV/CardDAV support, linger as perfect "if I had time" projects.

The last one is crucial for our position: though a totally unsupported problem would eventually fall prey to incompatibility with newer operating systems and machines, Domino has reached a point in the last couple years (thanks to the extensibility API in 8.5.2 and the vital bug-fixes in 8.5.3 and 9) where it's an agglomeration of replaceable parts. There are enough hooks and APIs to - with varying degrees of difficulty - take advantage of the core strengths of the platform while dramatically improving the components on top. That's not enough to last forever, but it doesn't have to be. Apps built in the mean time will still run and improve, and any time spent programming on the platform is valuable experience that can be applied elsewhere, whether directly or more generally.

Just don't ask about licensing.

Dabbling in Reflection

Mon Jul 07 15:00:07 EDT 2014

Tags: java

In a similar vein to my post from the other day, I'd like to discuss one of the other bugaboos that crops up from time to time in the edges of XPages development, usually spoken of in hushed tones: reflection.

If you're not familiar with the term, reflection is an aspect of metaprogramming; specifically, it's the ability to inspect and operate on objects and classes at runtime. Reflection in Java isn't as smooth as it is in other languages, but it makes sense as you work with it.

The most basic form is the getClass() that every non-null object has: you can use it to get an object representing the class of the object in question, which is your main starting point. This code will print out "java.lang.String":

Class<?> stringClass = "".getClass();
System.out.println(stringClass.getName());

From here, you can start to get fancier. For example, this code...

Class<?> stringClass = "".getClass();

for(java.lang.reflect.Method method : stringClass.getMethods()) {
	System.out.println(method);
}

... will print out the signatures for all public instance and static methods, with output like:

public boolean java.lang.String.equals(java.lang.Object)
public int java.lang.String.hashCode()
public java.lang.String java.lang.String.toString()
public char java.lang.String.charAt(int)
public int java.lang.String.compareTo(java.lang.String)
...
public int java.lang.String.compareTo(java.lang.Object)
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

There is also a variant to show just the methods from that specific class, including private/protected ones. But the java.lang.reflect.Method objects you get there are useful for more than just printing out signatures: they're proxies for actually executing the method against an appropriate object. To demonstrate, say you have this class:

public class ExampleClass {
	private String name;

	public ExampleClass(final String name) { this.name = name; }

	public void printName() { System.out.println(name); }
}

You can then use reflection to call the method (this also demonstrates an alternate way of getting a class object if you know the class you want):

ExampleClass someObject = new ExampleClass("my name is someObject");
Method printNameMethod = ExampleClass.class.getMethod("printName");
printNameMethod.invoke(someObject);

So, okay, I found a way to call a method that involves way more typing for no gain - so what? Well, in a situation where reflection is actually useful, you won't actually know what methods are available. And this happens constantly in XPages, but you don't have to worry about it: reflection is how EL and SSJS do their work. If you've ever looked through one of the monstrous stack traces emitted by an XPage with an exception, you've probably seen this very call:

java.lang.Exception
    controller.home.getOutput(home.java:18)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
    java.lang.reflect.Method.invoke(Method.java:611)
    com.sun.faces.el.PropertyResolverImpl.getValue(PropertyResolverImpl.java:96)
	...

That's reflection in action. The EL resolver found the object and then used reflection to determine how it should get the "output" property (most likely the instanceof operator) and then, determining that it was talking to a plain bean, constructed the name "getOutput", asked the object's class for that method, and invoked it.

Like most things in Java, reflection gets more complicated and powerful from here; there are facilities for dealing with generic types, creating new instances, reading annotations, making private properties/methods accessible, and so forth. But the basics are simple and worth knowing: it's all about asking an object what it is and what it is capable of. Once you're comfortable with that, the rest of the pieces will fall into place as you encounter them.

My Black Magic for the Day

Fri Jul 04 18:47:34 EDT 2014

One of the overarching goals for my model framework is to get the job of specifying business logic out of the XPage. So far, most of my work in the area revolved around building in the ability to override getters/setters, establish relationships, and so forth. However, a big problem remains: the XPage still needs to be told things about the data that are really the model's job, not the XSP markup's. Namely, validation.

A little while ago, I "solved" this by adopting Hibernate Validator and building it into the framework. This allows very declarative specification of requirements and also let me build the validation into the model's save event. If a field is marked as required in the model, no matter what the XPage says, the object cannot be saved if the value is empty. So: mission accomplished, technically!

But it's not a great user experience: though I made it so that you get proper Faces messages about what the problem was, the error wasn't tied to the control that caused it, nor could the page do any client-side validation to avoid server round-trips. The solution I found for this and several other problems is, as happens very frequenty, a technical path Tim Tripcony started down a few months ago. Specifically, it's the esoteric "binding" property of each control on the XPage, which is a way of telling the control to set itself as the value of a given binding - say, on the page controller - to provide easy access to it without having to crawl the component tree.

I realized that I could use this with a specially-crafted set of objects to tell the controller and model framework exactly what is going on:

<xp:inputText binding="#{controller.components[task].Summary}"/>

That looks weird at first, but the meaning becomes clear: tell the controller that that text box represents the "Summary" property of the "task" model object. Once that binding happens, the controller can take care of a lot of work that would otherwise have to be done manually:

  • Set the value="#{...}" binding
  • If the model says the value is required, set required="true", allowing for client-side validation and an Aria attribute to be set
  • If the model property specifies another known validation type (say, that it's an email address), add in an appropriate server- and client-side validator. For unknown types, add in a generic validator that will respond to any requirement
  • If the property is a Collection type, specify a multipleSeparator property
  • If the property is an enumeration and the control is a multi-value control (say, a xp:comboBox or xp:radioGroup), automatically add xp:selectItems for each entry
  • Add appropriate converters and other assistant components, such as a date/time picker for Date fields

This could be taken much further, to the extent that there could potentially be a single generic xp:input-type control (or a placeholder CC) and then the controller would construct a control based on the model and client needs - this is a drum NTF has banged before. It could also apply to objects other than my model framework's, but that would take an appropriate adapter for each.

Not only does the XSP code get much trimmer, but the validation and type-specification code in Java is clear and to the point:

public class Task extends AbstractDominoModel {

	@NotEmpty String summary;
	@NotNull TimeFrame timeFrame;
	TaskType type;
	
	public static enum TimeFrame { Normal, Rush, Urgent }
	public static enum TaskType { Normal, Question }

	// ...
}

This feels like a nice step forward in the direction of putting concerns in their right places while also reducing the total amount of code. I'd call that the right kind of victory for app development.

The code for this lives in the framework project inside the XPages Scaffolding repository and the work of the component manipulation is in this class:

https://github.com/jesse-gallagher/XPages-Scaffolding/blob/6d7a9dc59ca070e74a5bd157eb49500b61717e57/frostillicus.framework.plugin/src/frostillicus/xsp/controller/ComponentMap.java

Things I Rarely Use: sessionScope

Thu Jul 03 20:20:06 EDT 2014

Tags: xpages
  1. Things I Rarely Use: sessionScope

As this post's title implies, I'm considering making this a series on XPages anti-patterns, but no promises there.

In any event, this is a topic that's been stewing in my brain for a little while: my antipathy towards the session scope in XPages. Now, don't get me wrong: other than the "not reset on logout" thing that may be fixed by now, I have no technical qualms with sessionScope; it does what it says on the tin. However, I've often found that many people use it very frequently, whereas I have found fewer and fewer uses over time where it is appropriate.

To set the stage, I use the various scopes in roughly this order by descending frequency:

  1. viewScope
  2. applicationScope
  3. flashScope
  4. requestScope
  5. sessionScope

The main things that I use sessionScope for are things that truly make sense only for the current browser session, such as the current date range to view in a log-viewing app. Other than that, I generally don't use it for:

Caches

Though it's not wrong, per se, to use the session for this, I've found it better overall to use the applicationScope, either directly (applicationScope.put("someCachedValue", whatever)) or by putting a Map keyed by username in there. The latter gets the same user-specific cache benefits of sessionScope (and more reliable, too, due to the potential for switched authentication) while also having the benefit of keeping the cache if the user logs in from another device. This is particularly potent with Anonymous. This is not a hard-and-fast rule, though - you may decide otherwise for cache-size or other reasons.

Primary Navigation or Context

Unlike the previous one, this is a hard-and-fast rule: do not use sessionScope for important page context. The worst would be something like having an "open document" button that puts the desired document UNID (or, worse, note ID) in sessionScope and then navigates to the page. Never do this! Though XPage URLs are a continuing problem, they're still the correct place for target-document information. The rule of thumb is that you should be able to copy the URL any time, paste it into another browser, and be in basically the same place.

Secondary Context

By this I mean things like the active linksbar category for the current page. I've seen things like having a navigation bar link that sends the user to a certain page while also setting a sessionScope variable to indicate the active menu bar. This is a huge problem for a number of reasons: it's a maintenance nightmare (having to code every link to do this), it's just asking for bugs (links setting the wrong or no value), and it breaks completely when the user bookmarks the page or comes back after session expiration. It's technically better than the previous crime, but only barely. The correct place for this information is handled somewhere in the page structure, though the specifics get murky. I generally take a page from the Extension Library example DB and use a "navigationPath" properly on my layout control to define a slash-delimited hierarchy of navigation context.

Page-to-Page Context

I'm thinking of things like a task-tracking system where you're looking at a Client document and want to add a Task to them, providing the Client document's ID for context. This is another area where the URL is the correct choice: ending up with a URL like "/task.xsp?clientId=whatever" makes the intent ("create a new task for client with ID 'whatever'") clear and stable across visits.


Overall, I think of sessionScope as the Petyr Baelish of XPage features: there are some cases where you have to deal with it, but you should generally consider it extremely unreliable and untrustworthy.

XPages Data Caching and a Dive Into Java

Wed Jul 02 16:39:54 EDT 2014

Tags: java

One of the most common idioms I run into when writing an app is the desire to cache some expensive-to-compute data in the view or application scope on first fetch, and then use the cached version from then on. It usually takes a form like this:

public Date getCachedTime() {
	Map<String, Object> applicationScope = ExtLibUtil.getApplicationScope();
	if(!applicationScope.containsKey("cachedTime")) {
		// Some actual expensive operation goes here
		applicationScope.put("cachedTime", new Date());
	}
	return (Date)applicationScope.get("cachedTime");
}

That works well, but it bothered me that I had to write the same boilerplate code every time, and I wondered if I could come up with a better way. The short answer is "no, not really". But the longer answer is "sort of!". And though the solution I came up with is kinda pathological and is generally unsuitable for normal humans and not worth the thin advantages, it does provide a good example of a couple of more-advanced Java concepts that you're likely to run across the more you get into the language. So here's the cache function in question, plus a "shorthand" version and an example:

@SuppressWarnings("unchecked")
public static <T> T cache(final String cacheKey, final String scope, final Callable<T> callable) throws Exception {
	Map<String, Object> cacheScope = (Map<String, Object>) ExtLibUtil.resolveVariable(FacesContext.getCurrentInstance(), scope + "Scope");
	if (!cacheScope.containsKey("cacheMap")) {
		cacheScope.put("cacheMap", new HashMap());
	}
	Map<String, Object> cacheMap = (Map<String, Object>) cacheScope.get("cacheMap");
	if (!cacheMap.containsKey(cacheKey)) {
		cacheMap.put(cacheKey, callable.call());
	}
	return (T) cacheMap.get(cacheKey);
}

public static <T> T cache(final String cacheKey, final Callable<T> callable) throws Exception {
	return cache(cacheKey, "application", callable);
}

public Date getFetchedTime() throws Exception {
	return cache("fetchedTime", new Callable<Date>() {
		public Date call() throws Exception {
			return new Date();
		}
	});
}

This code begs a question: what in the name of all that is good and holy is going on? There are a number of Java concepts at work here, some of which you've likely already seen:

  • Generics. Generics are the class names in angle brackets, like Map<String, Object> and Callable<Date>. They're Java's way of taking a container or producer class and making it usable with any class types without having to cast everything from Object.
  • Overriding methods. This is a small one: you can declare the same method name with different parameter types, which is often useful for "shorthand" versions of methods that allow for default values after a fashion. In this case, the short version of "cache" defaults to using the application scope by name.
  • The Callable interface. This is an interface in the java.util.concurrent package and is meant as a utility for multithreading purposes, but it also serves our needs here. Basically, it's an interface that means "this contains code that can be executed by using the call method with no arguments".
  • Anonymous classes. This is that business with "new Callable...". Java calls those anonymous classes and what they are are classes declared and instantiated inline with the code, without having a "proper" class declaration somewhere else. They're called "anonymous" because they have no name of their own - just the interface or class they implement/extend. In this case, I'm saying "make a new object that implements Callable and is used for this purpose only". I could make a standalone class, but there's no need. If you're familiar with closures from good languages, anonymous classes can be used like a really crappy version of those.
  • Generic return value declarations. The "<T> T" and "Callable<T>" bits build on normal generic use for when declaring a method. The first one, is brackets, basically says "okay Java, rather than returning a known object type, I'm going to let the user use anything, and for this purpose we're going to call it T". So from then on, an occurrence of T in that method body refers to whatever the programmer using the method intends. You can see in the getFetchedTime that I'm using a Callable<Date>; Java picks up on that "Date" name and conceptually substitutes it for all the Ts in the method. I'm essentially saying "I'm going to use the cache method, and I want it to accept and return Dates". Another call to the method could be to cache a List<String> or a SomeUserClass, while the method itself would remain the same.

So is all this worth it for the task at hand? Probably not. There are SOME advantages, in that it's easy to change the default caching scope, and in practice I also used a map that auto-expires its entries over time, but for normal use the first idiom is fine. But hey, it sure provided a whole torrent of Java concepts, so that's worth something.

Another Round of URL Fiddling

Thu Jun 19 17:59:51 EDT 2014

Tags: domino urls

I was working on another installment of "Be a Better Programmer", but the result isn't where I want it to be yet, so it'll have to wait. Instead, I'll share a bit about my latest futzing around when it comes to improving the URLs used in an XPages app. This has been a long-running saga, with the latest installment seeing me stumbling across a capability that had been right under my nose: the ViewHandler's ability to manipulate the URLs generated for a page. That method worked, but had the limitation that it didn't affect navigation between pages.

As it turns out, there's a slightly-better option that covers everything I've tried other than navigation rules specified in faces-config.xml (but who uses those in XPages anyway?): the RequestCustomizerFactory. This is one of the various classes buried in the Extensibility API and present in the XSP Starter Kit, but otherwise little-used. In the Starter Kit stub (and in a similar commented-out stub in the ExtLib), it can be used to add resources to a page without needing to specify them in code - say, for a plugin to add JS or CSS libraries without being specified in a theme.

However, there are other methods in the RequestParameters object that would appear to let you shim in all sorts of settings on a per-request basis - different Dojo implementations, different theme IDs, whatever "debugAgent" is, and so forth. The one that interests me at the moment is the UrlProcessor. This is aptly named: when a URL is generated by the XPage, it is passed through this processor before being sent to the browser. This appears to cover everything other than the aforementioned stock-JSF-style navigation rules: link value properties, form actions, normal navigation rules, view panel generated links, etc..

Following my previous desire, I want to make it so that all links inside my task-tracking app Milo use the "/m/*" substitution rule I set up for the server. The method for doing that via a UrlCustomizer is pretty similar to the ViewHandler:

package config;

import java.util.regex.Pattern;

import javax.faces.context.FacesContext;

import com.ibm.xsp.context.RequestCustomizerFactory;
import com.ibm.xsp.context.RequestParameters;

public class ConfigRequestCustomizerFactory extends RequestCustomizerFactory {

	@Override
	public void initializeParameters(final FacesContext facesContext, final RequestParameters parameters) {
		parameters.setUrlProcessor(ConfigUrlProcessor.instance);
	}

	public static class ConfigUrlProcessor implements RequestParameters.UrlProcessor {
		public static ConfigUrlProcessor instance = new ConfigUrlProcessor();

		public String processActionUrl(final String url) {
			String contextPath = FacesContext.getCurrentInstance().getExternalContext().getRequestContextPath();
			String pathPattern = "^" + Pattern.quote(contextPath);
			return url.replaceAll(pathPattern, "/m");
		}

		public String processGlobalUrl(final String url) {
			return url;
		}

		public String processResourceUrl(final String url) {
			String contextPath = FacesContext.getCurrentInstance().getExternalContext().getRequestContextPath();
			String pathPattern = "^" + Pattern.quote(contextPath);
			return url.replaceAll(pathPattern, "/m");
		}

	}
}

The method of adding this customizer to your app directly is, however, different: instead of being in the faces-config file, this is added as a "service", as mentioned in this handy list. For an in-NSF service, you accomplish this by adding a folder called "META-INF/services" to your app's classpath (you can add it in Code/Java) and a file in there named "com.ibm.xsp.RequestParameters":

In this file, you type the full name of your class, such as "config.ConfigRequestCustomizerFactory" from my example. You'll likely have to Clean your project after doing this to have it take effect (and possibly in between each change to the code).

Now, my current use is very limited; the UrlProcessor has free reign for its transformations and is passed every URL generated by the XPage (except hard-coded HTML, unsurprisingly) - you could change URLs like "/post.xsp?documentId=foo" to "/blog/posts/foo" without having to code that explicitly in your XPage. You could write a customizer that looks up all Substitution rules for the current Web Site from names.nsf and automatically transforms URLs to match. You could go further than that, trapping external links to process in some way in the "processGlobalUrl" method. The possibilities with the other methods of the customizer go much further (and are largely undocumented, to make them more fun), but for now just fiddling with the URLs is a nice boon.

The frostillic.us Framework

Mon Jun 09 15:40:17 EDT 2014

Tags: framework

For a while now, I've maintained a project called XPages Scaffolding on OpenNTF and GitHub. This project is the NTF that I use when creating a new XPages application and acts as a storehouse for my "bag of tricks", things like my model framework, controller classes, and various goodies I've picked up over the years, like a JSFUtil class and a flashScope. For a while, I've figured that, once this stuff is in proper shape, I'd extract it into an OSGi plugin and get it out of the NSF. Last week, I decided to take the plunge.

Something surprised me about the process: not only did I gain the benefits of a cleaner NSF and a nicer environment for editing the code, but it really solidified my focus for what I want it to be and gave it a real sense of purpose. The newly-dubbed Framework is geared towards turning an NSF app into two main things: a data-access API available via Java and REST and an XPages front-end that is first-among-equals for accessing that API and follows defined structural conventions.

The Model Framework

The model framework is the newest part of the project and the REST API in particular is only days old, but it's rapidly becoming the most important aspect and is likely to be the spiritual core. By providing a way to define models in a way that is simple, consistent, and (theoretically) storage-agnostic, a large part of the work of creating a new application is made significantly easier to write and understand. The models provide numerous characteristics built-in that would previously have been implemented as a series of script libraries, XAgents, and UI components:

  • Collection access. The Manager classes let the XPage care only about getting a collection of "my Tasks", rather than "the 'Tasks by Assignee' view filtered to just the category of @UserName()".
  • Property control and side effect handling. Model objects allow handling side effects where they belong, so setting, for example, the Client field to a new value needing to reset Project to blank is done there, not on every XPage implementing those fields.
  • Validation. I'm currently trying out integrating Hibernate Validator into the framework to allow for declarative constraints on a model's properties. It shouldn't have to be the XPage's job (solely) to know how to validate an email address or ensure that a username is at least N characters long. By declaring it at the model level, it frees up code elsewhere while also allowing to constraints to function when accessing models programmatically.
  • REST API. This is the new golden child that has brought this clarity of purpose to the framework. Having "for free" REST access to the model objects in an app removes a ton of potential work from the programmer and also opens up tremendous opportunity for integration. Previously, allowing access to an app's data meant rewriting all of the business logic, either in the foreign app (accessing the data via DAS or legacy Domino APIs) or in XAgents designed to serve up JSON. Now, when you write the business rules for your XPages app, you're also writing a method for external access. Things like a JS-based or mobile app move from "possible with lots of work" to "may as well". It also means you don't have to choose between having either an XPages app or an interoperable API.

The XPages Components

The XPages side of the framework is still something of a grab bag, filled with the aforementioned small utilities, controllers, my dying-on-the-vine messaging framework, support classes for writing in-NSF servlets, and a number of useful converters. In the process of plugin-ifying these, I've made some refinements, such as turning the converters into real JSF components, redubbing "JSFUtil" as "FrameworkUtils" and making it work in a non-Faces OSGi environment, and integrating my @ManagedBean implementation.

The transition has also given me the freedom to be a bit more brash about changes, making backwards-incompatible tweaks that I've been meaning to do for years, making the different parts of the framework a bit more integrated, and a number of other things I have in mind to try out.

But though this side is less integrated than the model side, it still represents a consistent way to write XPages applications: model objects for data access, controllers for primary logic, servlets instead of XAgents when appropriate, SSJS relegated to glue code in Custom Controls, and a consistent, simple naming scheme for Java classes favoring simple "local" package names like "controller" or "model" over fully-qualified ones like "com.somecompany.appdev.domino.xpages.apps.someapp.controllers" when appropriate.


All in all, I'm pretty excited about the changes I've been making. For as long as I've been working with XPages, I've been searching for the "right" way to write them, and I feel like I'm finally approaching an answer I can feel comfortable with.

And not only does my XSP code feel better and less cluttered, but it makes the platform as a whole feel better. It's always been the case that server-based app-dev lets you use whatever environment you want, though modern web development has modified that situation somewhat. It's still true that your framework doesn't necessarily matter, but it should be able to adhere to common contracts to function in an interoperable world. Much like other things I want the platform to do, the model framework in particular brings Domino into a role where the NSF-based app is the central dispatch point for a multi-platform environment. Don't want to use NSF for data storage? Plug in a different back end. Don't want to use XPages for the UI? Use the REST API and get the same transparent data access.

I think there's good potential with this setup.