How I Added File-Download Support To My Model Framework

Sat Apr 12 13:33:24 EDT 2014

Tags: xpages java

Unlike the last few posts, this one isn't as much a tip or tutorial as it is an attempt to share my suffering by detailing the steps I took recently to add file-download and -upload support to my current model framework.

The goal of my framework overall is to retain the benefits of normal Domino document data sources (arbitrary field access, ease of use in simple cases, and compatibility with standard XPage idoms) while adding on useful new abilities (getters/setters, relationships with other objects, abstraction between the XPage and the actual location of the data). Most of this work is easy - by implementing DataObject, my objects worked well with EL bindings and most of the work was focused on hooking up Domino Document objects in a similar way to IBM's DominoDocument class.

However, some of the more esoteric controls are not so easy, and the file controls were chief among them. As I tinkered, I found that you can't directly point a xp:fileDownload control to a normal data source and get it to work well. You can get it to list a single file, but I wasn't able to get it to recognize more than one through traditional means.

In my tinkering, I discovered that there are two main paths for the control: the traditional one and a more-complicated one, which makes a lot of assumptions about the nature and availability of the referenced data source. Importantly, unlike normal bindings (which take your expression, say #{doc.body}, have the EL processor resolve it, and deal with the final resolved entity), the control actually treats the EL expression as a String, splits it in two on the "." character, and looks up the variable on the left side plus ".DATASOURCE". This "doc.DATASOURCE" idiom matches the behavior of data-source controls on an XPage, which make themselves or an associated object available by that name. If the control finds an object by that name and if it implements DataSource (a common interface used by these controls), it assumes that the source contains a DataContainer object that also implements DocumentDataContainer specifically.

Phew, okay, so far so good. It makes some inconvenient sense that the control would expect its referenced value to conform to the norms of the built-in data sources, so I wrote controls to do just that (previously, I got by using normal EL references from managed beans). However, I still ended up getting ClassCastExceptions at runtime: it turned out that the control also uses a nebulous factory object to attempt to convert the received value into a data type it expects, specifically DominoDocument. Unfortunately, unlike the interfaces I implemented already, subclassing DominoDocument was not something I was willing to do. So I was back to digging.

What I found was that this attempted conversion was happening due to an object implementing com.ibm.xsp.model.DataModelFactory, which has the job of taking an intermediate value used in the control (a com.ibm.xsp.model.FileDownloadValue, which contains a single-entry HashMap containing the object and requested field name) and returning the attachment data as an instance of DataModel. In addition to writing the code to do this, there's another wrinkle: the way the factory is found. The way I found to access this is thoroughly awkward: if I use the deprecated method getFactoryLookup() on the application instance, I can then retrieve the default factory by a key ("com.ibm.xsp.DOMINO_DATAMODEL_FACTORY"), wrap it in a new object that knows about my model objects, and replace it in the lookup.

Once I did all that, I was off to the races! Sort of! There remained another problem: the "delete attachment" icon on the control. I discovered that the way this icon works is that it composes an action that tracks down an adapter that knows how to communicate with the associated model object and sends it a deleteAttachments(...) call. As before, the way it "tracks down" the adapter is to look up another factory ("com.ibm.xsp.DESIGNER_DOMINO_ADAPTER_FACTORY") and ask it to provide an appropriate adapter. So again I wrote my own variant of this to intercept calls dealing with model objects and carefully placed it, Indiana-Jones-style, in place of the default factory.

The net result is that it works! I can point a file-download control at a model object (as long as that object was specifically instantiated in a data source control and is referenced directly in "object.field" format) and have it list all of the attachments in the field, along with a functioning delete action if desired. The file-upload control was, fortunately, much easier: when I realized I could swap out most of the guts of my model object with a back-end DominoDocument (now that the OpenNTF API takes care of data conversions for me), I was able to just proxy the upload calls to it and let it do the heavy lifting.

Now, there's only one nagging problem remaining: inline image uploads in rich text controls. But still, even if I never get that part working, the file manipulation will be enough. And, importantly, I've paved the way for me to be able to do use the same controls with model objects that aren't associated with Domino at all, should I desire to do so down the line.

Loading Resources via Themes

Thu Apr 10 13:36:51 EDT 2014

Tags: themes xpages

In today's TLCC XPages webinar, Marky Roden had a great presentation discussing resources and design definitions to help speed up Designer. If you didn't catch it live, it's worth tracking it down when it's available.

I'd like to build on what he was talking about a bit by explaining how to use themes to load resources in a way that also prevents Designer slowdown while having the secondary benefit of being clean design (with some caveats that I'll get into).

If you're not familiar with themes, they're the oddball XML design element introduced alongside XPages, and they serve a number of purposes. One of them, which Tim Tripcony explained well is that you can use them to set properties of your XPages controls - so if you want to, say, apply the CSS class of "btn" to all buttons, you can use a Theme to do that instead of writing it into every <xp:button/> control. They can also be used, though, to load resources in much the same way as you do on an XPage or Custom Control directly. The default theme you get includes some comments that point in this direction, but they use the horrible multi-line syntax. It turns out that you can use a shorter syntax that mirrors the normal XSP markup. Say you have a resource section like this:

<xp:this.resources>
	<xp:styleSheet href="/style.css"/>
	<xp:styleSheet href="/fixes.css"/>
	<xp:styleSheet href="/ieonly.css" rendered="#{context.userAgent.IE}"/>

	<xp:dojoModule name="dojo.behavior"/>
	<xp:script src="/behavior.js" clientSide="true"/>
	
	<xp:metaData name="viewport" content="width=device-width, initial-scale=1.0"/>
	<xp:linkResource href="#{facesContext.externalContext.requestContextPath}/feed.xml" rel="alternate" type="application/rss.xml" title="RSS Feed"/>
</xp:this.resources>

To convert that to theme syntax, you just chop off all the "xp:" and "this." bits:

<theme extends="webstandard">
	<resources>
		<styleSheet href="/style.css"/>
		<styleSheet href="/fixes.css"/>
		<styleSheet href="/ieonly.css" rendered="#{context.userAgent.IE}"/>

		<dojoModule name="dojo.behavior"/>
		<script src="/behavior.js" clientSide="true"/>
		
		<metaData name="viewport" content="width=device-width, initial-scale=1.0"/>
		<linkResource href="#{facesContext.externalContext.requestContextPath}/feed.xml" rel="alternate" type="application/rss.xml" title="RSS Feed"/>
	</resources>
</theme>

Once you apply that to your app in the Xsp Properties, it will be as if you included the resources on the XPage directly, but you avoid the Designer slowdown problem and the XSP load time itself will be (imperceptably) faster. As an important bonus, it separates the concerns nicely: the theme's job is to handle describing the client-only stuff, and accordingly you get to delete some code from your XPages. One less thing to worry about during normal development.

Now, as I mentioned, there are some caveats, and themes are not appropriate in all cases.

  • Most importantly, the resources loaded by themes are not available during programmatic page load. This is not normally a big deal, since the page loading doesn't care about CSS files or client JavaScript anyway, but it DOES matter for two types particularly: SSJS libraries and property bundles. If you have code that needs to access them during initial processing (either in ${}-bound properties or in places like before/afterPageLoad events), you should include them on the XPage directly.
  • There's no good UI for modifying themes. You kind of have to just know how they work. I believe there's a thorough treatment in Mastering XPages, but other than that you're on your own until you learn.
  • Since Designer doesn't load them, it also doesn't help you when specifying style classes. If you're in the habit of using the "Style" properties pane to pick classes from linked stylesheets, this will break that.

But even with those caveats in mind, I'm a huge fan of themes (for this and other uses) and use them constantly. The code cleanliness, performance improvements, and structural advantages are well worth the caveats.

The Collections Framework as Education

Sun Apr 06 19:15:59 EDT 2014

While I've been formulating the followup to my last post, I've also been thinking about how wonderful the Java Collections framework is. I've been singing its praises for a long time (as have others), but what's stood out to me lately is how well it encapsulates many of the most important foundational concepts of Java.

One of the reasons Java appears so intimidating and foreign to Notes developers is that the way many are introduced to it - as an auxiliary for XPages - involves learning a torrent of unrelated concepts simultaneously: strict variable typing, object equality and comparison, class casting, managed beans, recycling (though this is just as important in SSJS), confusing recycling with memory management, static methods, inheritance, interfaces, exceptions, abstract classes, database access, serialization, concurrency, and so forth. If you focus on the Collections framework specifically, though, you can learn many of the important basics in a clear way. And as a bonus, these are critical concepts shared with other, better OO languages.

Interface vs. Implementation

One of my favorite lecture topics is the value of separating interface and implementation. Unfortunately, most of the time, the values are unclear - if you're only going to make one class, is it valuable to have an interface? - and it seems like pedantry. The Collection classes, however, bring this value into sharp focus. The core interfaces correspond to elemental data structures of Computer Science and tell you everything you need to know to use them, e.g.

  • List: a collection of objects in the order stored by the user, accessed by index.
  • Map: a collection of objects accessed by a key of any type specified by the user.
  • Set: a collection of unique objects in either arbitrary or, for SortedSets), automatically-sorted order.

These interfaces describe everything you need to know about the object and do so so well that there's rarely any need to specify the actual class at all outside of creation. The differences between the actual classes are, quite literally, implementation details: some focus on single-thread performance (like ArrayList), some serve specialized cases (like EnumMap or IdentityHashMap), some implement multiple useful interfaces (like LinkedList), and some are geared towards multi-threaded use (like the java.util.concurrent objects).

Job-Based Polymorphism

Not only does the Collection framework provide an example of a cleanly-designed interface/implementation separation, but it also provides examples of why this pays off. One of the handiest tricks is the way most of the objects (other than Map) participate in mutual-translation schemes. By this I mean that you can take one Collection and pass it to another (either in the constructor or via addAll) and build a second collection of the same objects, but obeying the rules of the new collection.

For example, say you have a List of usernames that you retrieved from a call to view.getColumnValues(...) and now you want to sort and unique-ify them (basically like @Sort(@Unique(...))). Well, there's a collection type for that: the SortedSet, of which TreeSet is the common implementation. Rather than manually building a unique, sorted List (even using helper methods), you can accomplish this with TreeSet's constructor. You can then add in names from other sources and maintain the same unique-and-sorted guarantee without any additional code:

SortedSet<String> names = new TreeSet<String>(view.getColumnValues(1));
names.addAll(doc.getItemValue("SomeNamesField"));
names.addAll(someNameMap.values());

Because those methods only care that the incoming values are in a Collection, the fact that some may be in Lists, in Sets, or in some other entirely-unknown type that implements Collection is completely irrelevant. As it should be.*

Reusability

This benefit is so inherent to the framework that I almost forgot to include it. Largely by the nature of the task being performed but also by virtue of proper coding, the collection objects are so reusable that they feel like part of the language, even though they're just objects like any you write. They're built to be generic and used in ways far outside of the original ken of their creators. Both the implementations and interfaces can be spread far and wide, such as with my database model collection class that also acts as a List.

Takeaway

Not all of these benefits are going to be useful in all of your code, and it will be very infrequent that you have a reason to write your own framework of this type. By learning the contours of this framework, though, you can advance your knowledge of Java and object-oriented programming generally by leaps and bounds. It will help you write cleaner code and to identify similar concepts used elsewhere.

* For example, did you know that viewScope is not a HashMap but actually a class called "javax.faces.component.UIViewRoot$ViewMap"? That's how much the implementation doesn't matter.

An XPage As A Tree

Tue Apr 01 23:05:41 EDT 2014

Tags: xpages plato

I'd like to take a blog post or two to discuss an aspect of XPages that isn't directly applicable to normal XPage development, but which can be a conceptual shift that causes a lot of things to fall into place: the tree nature of an XPage. This has nothing to do with Java, SSJS, beans, or JSF phases. It barely even has much at all to do with web pages.

You've likely heard that XPages aren't really XML - that they're actually Java, created from the "simpler" XML you write. This is true, and it drives home the important point that an NSF is now best viewed as a Java "enterprise" application. However, this isn't actually the best way to look at it; the best way is that an XPage is a tree of objects.

If you've had a Computer Science education, you'll know the tree as one of the foundational data structures used in almost all programming. If you haven't and you're not familiar with trees, it will pay tremendously to learn a bit about it - most sources I've found are either painfully mathy (like Wikipedia's article) or tied to the instruction of a specific language (often a Lisp dialect), but this page of a Python tutorial looks promising. This tree nature helps explain why XML is the tool of choice for writing XPages: XML is a tree-description language.

So an XPage is a tree. Specifically, it's a tree of user-interface objects, each of which contains methods, properties, events, and zero or more child objects. Let's take an example XPage, using ExtLib controls because they are more descriptive:

<?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"
	pageTitle="Test Page">

	<xe:formTable formTitle="Some Form">
	
		<xe:formRow label="Field One">
			<xp:inputText/>
		</xe:formRow>
		
		<xe:formRow label="Field Two">
			<xp:radioGroup>
				<xp:selectItem itemLabel="Foo"/>
				<xp:selectItem itemLabel="Bar"/>
			</xp:radioGroup>
		</xe:formRow>
		
	</xe:formTable>
	
	<xp:button value="Click Me"/>
	
</xp:view>

Ignore your default impulse to think "ah, I know what that looks like!". At this point, it doesn't "look like" anything, other than:

  • UIViewRootEx2 (pageTitle="Test Page")
    1. UIFormTable (formTitle="Some Form")
      1. UIFormLayoutRow (label="Field One")
        1. XspInputText
      2. UIFormLayoutRow (label="Field Two")
        1. XspSelectOneRadio
          1. UISelectItemEx (itemLabel="Foo")
          2. UISelectItemEx (itemLabel="Bar")
    2. XspCommandButton (value="Click Me")

The fact that it will eventually be rendered as a OneUI HTML form table won't come into play until renderers are involved (which will be a likely followup post). For now, it's best to think of this as a hierarchical description of a user interface in the abstract. At this point, the only thing standing between the XML code above and looking like this is a nontrivial amount of work:

Okay, the XML code and the related objects don't say anything about the appearance of the resultant interface, so what do they say? They define the state and behavior of the UI and how it responds to user interaction. Again, this will almost definitely consist of an HTML page and the user clicking in the browser to send POST requests to the server, but this is still entirely incidental to the XPage. Conceptually, it's all about a handful of UI controls in a hierarchy, with properties, methods, and events, each looking after itself and, as requested, producing its children. The text box's job is to know that it can contain a string value along with potential hooks for validators, converters, and event handlers - that's it. Nothing about the specifics of HTML or JavaScript.

This also helps conceptualize a specific user's page state. When a user starts interaction with a page, what happens is that the server tracks down the page root class that corresponds with the requested page and asks it to create itself and any applicable children. So you end up with any number of these object trees floating around, each corresponding to an individual interaction session (in our case, a loaded page in a browser tab, but you could also think of it as a loaded process of an application). Interacting with the page consists of calling methods on these objects - setValue, click (which is weird), etc. - and causing them to respond and mutate appropriately.

So where does the HTML come in? That's a topic for another post, but the fact that it hasn't entered yet is the point here: XPages are trees of active objects describing a Platonic ideal interface and the framework has a secondary effect of producing HTML.

Life in Other Worlds

Tue Mar 25 20:17:58 EDT 2014

I've found the reaction to BlueMix to be pretty interesting. Unsurprisingly, the main question in our community has been "how does this relate to Domino?" The answer is pretty clear: it doesn't.

That's not really a bad thing! About half of the problems a platform like BlueMix solves - app packaging, multi-server availability, data-store access - are either non-issues on Domino or are done much more easily with it than with other app servers. The other advantages, well... IBM could likely shoehorn Domino into a service like that if they cared to, but they clearly don't.

Instead, I think this is a good opportunity to look at BlueMix for what it is (or appears to be from my only-partially-informed perspective): a competitor to Heroku and (half of) Windows Microsoft Azure. This is a great thing, because those platforms are amazing. What they do is one conceptual level above what someone like Linode does: in addition to abstracting away the physical machine your app is hosted on, they also abstract away the OS and server stack, presenting you (the developer) with an idealized world free of sysadmins and DBAs.

The best way to get a feel for what this means is to embrace it on its own terms: pick an environment wholly unrelated to Domino, close Notes and Designer, and try out one of the supported frameworks. It should come as no surprise that I find Ruby on Rails to be a perfect way to do this. Specifically, Michael Hartl's Rails tutorial not only brings you up to speed with modern Rails programming, but it also provides an introduction to Heroku, showing you how to use their free tier to publish your apps using Git (seriously, Heroku uses Git to publish - it's amazing). Node.js is also absolutely worth your time: it's a programming environment unlike any other and gives you an excellent new perspective on client/server interaction on the web. It looks like BlueMix doesn't do Python or PHP, which is just as well. Please don't use PHP.*

Particularly if it's been a while since you did any non-Domino or non-Java development, it could be a very useful experience - different ways to structure apps, different tools (no need for Eclipse, for example), different conceptual models of programming. You may not stick with it (for all my bluster about Ruby, I'm still writing Domino apps), but it'll keep your brain healthy. Too much of any one type of programming makes you calcified and causes you to miss out on the rest of the world. I know I, for one, plan to do more of this type of exploratory exercise.

* One of the greatest features of these app platforms is that they solve one of the main problems keeping people on PHP: it's just so freaking easy to deploy an app written in PHP, whereas deploying a Ruby/Java/Python/etc. app has traditionally been much harder. By abstracting away the app server, the playing field is leveled and you can choose the better tool.

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. Nov 17 2013 - My Current Model Framework, Part 1
  2. Feb 21 2014 - 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. Jan 29 2014 - Couchbase StateManager for XPages, Part 1
  2. Feb 21 2014 - 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.

Couchbase StateManager for XPages, Part 1

Wed Jan 29 15:08:55 EST 2014

  1. Jan 29 2014 - Couchbase StateManager for XPages, Part 1
  2. Feb 21 2014 - Couchbase StateManager for XPages, Part 2

The other day, I attended Tony McGuckin's Connect session on XPages scalability (a companion to his earlier Masterclass on performance) and I was inspired to try out a thought I had: could it work to use Couchbase to further push the bounds of XPages scalability?

If you're not familiar with Couchbase, it's a product similar to CouchDB, which is in turn essentially Domino-the-DB-server re-done for modern needs. Last summer, I wrote some data sources to use Couchbase data in an XPages app in much the same way that you use Domino documents and views.

In addition to Couchbase's nature as a document database, it has another layer from its lineage as a continuation of Membase: its basis is a key-value store, suitable for caching or storing data in a very fast and scalable way. This capability is potentially a perfect match for the needs of XPages state holding: when an XPage is stored in between requests, it's really just taking a Java object and storing it by key either in memory or on disk. By taking Couchbase's key-value capability and using it for this, you end up with something that may (pending testing) really crank up the scalability.

So I wrote a class to do it, and so far, so good: it stores and retrieves the XPages properly and even automatically obeys session timeout to clean up unneeded entries. When I get home, I plan to convert it into a plugin, but for now I've uploaded the Java file:

CouchbaseStateManager.java

To use it, install the Couchbase Java Client (I dropped it in jvm/lib/ext, since adding them as Jars in the NSF was trouble), copy that class into your NSF in the "frostillicus" package, and modify your faces-config.xml and xsp.properties files similar to:

faces-config.xml

<faces-config>
  <application>
    <state-manager>frostillicus.CouchbaseStateManager</state-manager>
  </application>
  ...
</faces-config>

xsp.properties

frostillicus.couchbase.statemanager.uris=http://10.211.55.2:8091/pools
frostillicus.couchbase.statemanager.bucket=default
frostillicus.couchbase.statemanager.username=
frostillicus.couchbase.statemanager.password=

Once you have it up and running, you'll start seeing serialized views being stored in your Couchbase bucket (which is basically like an NSF) keyed by replica ID and the unique XSP view ID:

I'm looking forward to trying this out in a real setup, where I have the XPage running on one server and pointed at a cluster of multiple Couchbase servers elsewhere. This should really play to the strengths of both: it would use JSF's capabilities to take a little work off of the plate of the XPage server while letting Couchbase do its job of spreading the data across its cluster, caching in memory, and so forth. Barring unfixable performance pitfalls, this could push XPages performance and scalability even further.