SNTT: Reconstructing DateRanges

Thu Feb 27 09:53:46 EST 2014

Tags: sntt

In the OpenNTF API chat, I was reminded yesterday of how terribly broken DateRange retrieval is in Java. Specifically, though you can create date ranges and use them in view lookups, retrieving them from documents or view entries is FUBAR. To wit:

Field Value 02/27/2014, 02/28/2014, 02/27/2014 - 02/28/2014, 01/01/2014 12:00 AM - 01/02/2014 12:00 PM
doc.getItemValue("SomeField") [02/27/2014, 02/28/2014, 02/27/2014, 02/28/2014, 01/01/2014 12:00:00 AM EST, 01/02/2014 12:00:00 PM EST]

Note: this is consistent with LotusScript
doc.getItemValueDateTimeArray("SomeField") [02/27/2014, 02/28/2014, null, null]
session.evaluate(" SomeField ", doc) [02/27/2014, 02/28/2014, 02/27/2014, 02/28/2014, 01/01/2014 12:00:00 AM EST, 01/02/2014 12:00:00 PM EST]
entry.getColumnValues().get(columnIndex) [02/27/2014, 02/28/2014, 02/27/2014, 02/28/2014, 12/29/**** 12:22:46 PM EST, 10/03/**** 04:53:38 PM EDT]

Note: the final values are inconsistent across multiple executions

So it appears that getItemValueDateTimeArray chokes and gives up when it encounters date ranges, instead just plopping a null value in the Vector. View entries appear to wander off into some invalid-data wilderness, perhaps not properly parsing the ITEM_VALUE_TABLE attached to the entry. Or maybe it's in the ITEM_TABLE. I don't remember; it's complicated. In any event, view entries are a mostly-lost cause.

Document item values, though, are salvagable. Since getItemValue returns the start/end values and getItemValueDateTimeArray returns nulls in the spots that represent DateRanges (which are always at the end, but that's incidental), the two can be matched up to reconstruct the real value. I wrote a method to do just this - it doesn't do any checking to make sure that the item value actually contains DateTimes (and would throw a ClassCastException if it contains something else), it should do the job when you know the item contents:

@SuppressWarnings("unchecked")
private List<Base> noSeriouslyGetItemValueDateTimes(final Session session, final Document doc, final String itemName) throws NotesException {
	List<Base> result = new Vector<Base>();

	List<DateTime> dateTimes = doc.getItemValue(itemName);
	List<DateTime> dateTimesArray = doc.getItemValueDateTimeArray(itemName);
	int foreignIndex = 0;
	for(DateTime dt : dateTimesArray) {
		if(dt != null) {
			result.add(dateTimes.get(foreignIndex++));
			dt.recycle();
		} else {
			DateTime dt1 = dateTimes.get(foreignIndex++);
			DateTime dt2 = dateTimes.get(foreignIndex++);
			DateRange range = session.createDateRange(dt1, dt2);
			result.add(range);
		}
	}

	return result;
}

I'll probably add a similar method to the OpenNTF API (or maybe fix getItemValueDateTimeArray), but this should do for now.

My Current Model Framework, Part 2: An Example

Fri Feb 21 15:27:19 EST 2014

Tags: xpages mvc
  1. My Current Model Framework, Part 1
  2. My Current Model Framework, Part 2: An Example

To go along with the updated release of my Scaffolding project yesterday, I've created an example database created with that template and containing a basic use of my model framework:

model-framework-example.zip

This demonstrates a few things about the framework:

  • Setting up the two classes that go with each object type - the object itself (e.g. model.Department) and the "manager" class that handles fetching objects and collections (e.g. model.DepartmentManager) and adding the collections to faces-config.xml.
  • Tying the manager class to the views in a database using views with a common prefix. In this case, they point to the current database, though I recommend storing the data in another DB.
  • Adding relations between objects. A Person object is tied to a given Department by way of the getDepartment method, while a Department lists its people via the getPeople method.
  • Using the collections on an XPage with xp:viewPanel controls, including showing "columns" that are not in the view - the objects automatically fetch from the document when the column isn't present (which is inefficient but useful sometimes).
  • Attaching a model object to an XPage using a xp:dataContext and using a controller class to save it.

I have a few ideas in mind to improve day-to-day use of the model framework (for example, I may set up proper data sources for individual objects so they can tie into the normal save events), so they may change over time, but this is how I develop most apps today.

Couchbase StateManager for XPages, Part 2

Fri Feb 21 10:17:33 EST 2014

  1. Couchbase StateManager for XPages, Part 1
  2. Couchbase StateManager for XPages, Part 2

I had the opportunity to dive a little back into the StateManager I wrote the other week to try out a theory. The first thing I noticed was that there was a minor problem: it didn't work at all. Specifically, the code I had didn't actually store the whole proper state of the view, so it ended up being regenerated anew each time; the fact that this didn't cause an error was what led me astry.

Fortunately, I was able to scrounge together enough code to get it to work properly, bringing the tree and viewScope along for the ride:

CouchbaseStateManager.java

The impetus of revisiting this was to test whether this setup would be enough to accomplish a fun goal: by having the view state serialized to a commonly-available location, you should be able to switch servers in between actions (e.g. partial refreshes) and still have it work. And indeed, it does! I set up a round-robin load balancer for two of my Domino servers, which more or less switches between Arcturus and Ceres on each hit. In my test page, you can see a refresh count (stored as an instance member of the page's controller class, which is in viewScope) incrementing when you click the button:

https://roundrobin.frostillic.us/tests/ccluster.nsf

You can also see a value stored in "clusterScope", which is an object pointing to the same Couchbase cluster, and so it is similarly available on both servers.

This is pretty promising! It's not the sort of thing you'd do with any old app (importantly, applicationScope and sessionScope are not shared between the servers), but by pairing this with SSO, you could make an app that is resilient and scalable, with an arbitrary number of app servers behind a rotating load balancer without the need of sticky sessions.

Domino the Identity Server

Tue Feb 11 09:10:16 EST 2014

Tags: domino

As seems to happen a lot lately, my fancy was struck earlier by a Twitter conversation, this time about the use of Domino as a personal mail server. Not only do I think there's potential there, but it should go further and be a drop-in replacement for personal mail, calendar, and contacts storage.

I think there's tremendous value in controlling your own domain and the services on it, without being permanently attached to someone else's name for an email address (your school, your company, your ISP, Google). This is good not only for personal freedom, since it lets you pack up and move at will, but also for security, since a large third-party mail service is a particularly juicy target.

Unlike Domino's inherited-but-abandoned place as the preeminent NoSQL server and replicating app-dev platform, Domino is just barely shy of being this server. You could already hit the three main services reasonably well by using the Notes client or iNotes, but actual humans shouldn't have to do that. It's already (more or less) there for mail with IMAP, while support for CardDAV for contacts and CalDAV+public iCalendar feeds would round it out for the other two pillars. Technically, the only things standing in between the existing open-source WebDAV plugin for Domino and this imagined future are the complexities of plugin development and the RFC.

The other main aspects that could make this great are further refinements to Domino's existing capabilities: a bundled spam filter (say, one of the open-source tools that can do the job already) and a strong configuration focus on creating an SSL-secured public-facing server. Non-SSL variants of IMAP, POP (if you must - that could be removed entirely), and HTTP should be off by default and the configuration should encourage you to acquire SSL certificates with your own private keys (the Server Certificate Admin would need a revamp for proper key size and ciphers), as well as S/MIME certificates to tie with each user for signed/encrypted mail outside the Notes client. Though Domino's history with the NSA is... checkered, it's still remarkably well-positioned to provide a secure foundation to deter snooping eyes. Certainly, running a Domino server own your own or a rented/virtual server is leagues better than a fully-managed service in this respect.

Having those features in place and smoothly integrated with a nice setup assistant would make for a very compelling product: an all-in-one, easy-to-install server that runs on several modern OSes and handles secure replication across physical locations at already-actually-affordable prices. Admittedly, I don't know how compelling that product would be for IBM's accountants, but it's certainly compelling for me, and the world could use more decentralization like this.