Self-Aggrandizement for Fun and Profit

Mon Nov 05 21:38:36 EST 2012

As I alluded to in my previous post, I decided to set up a "portfolio" site to house a list of projects I've made or collaborated on and my recently-updated resume:

http://portfolio.frostillic.us

The site itself is intentionally quite simple: it's meant to house clear content, while further details are available on linked pages. Nonetheless, despite its simplicity, it's allowing me to further refine a couple things I've been tinkering with lately:

  • Bootstrap. Collaboration Today came out of the gate with a very clean implementation of a responsive Bootstrap design, and so I've been following suit by using Bootstrap for my non-data-driven sites (OneUI still feels like a better choice for complex applications in XPages). This portfolio provides a perfect testing ground for thoroughly incorporating the standard Bootstrap elements and making sure everything looks good and works properly on mobile devices.
  • Bootstrap as a Theme. This goes along with including Bootstrap generally, but I figured I'd take this occasion to start making a clean Theme to handle including the appropriate files and applying useful styles that I come across. Currently, this mostly means button styles, but I could see this expanding and potentially including renderers so that you could apply Bootstrap in much the same way that you do OneUI and standard and ExtLib components (like navigators) would adapt accordingly.
  • Cleaner URLs. I mentioned this in the aforementioned previous post, but I want to look for ways to keep XPage URLs as clean as possible. For this database, I'm taking a cautious route: using Domino web rules and giving the database a little knowledge about them, rather than exploring the possibility of running the whole site from a servlet. For a simple database, this is working well, with a basic from/to map and a simple manager bean.
  • Aggressive Open-Sourcing. Most non-work apps I've written lately have found their way to GitHub, but I decided I wanted to further drive the point home on the portfolio site. Towards this end, I included a "View page on GitHub" link in the footer of each page that links to the current master branch version of the XPage.
  • Page Controllers. I mentioned this a bit before, but I'm including my "page controller" idea in the portfolio, at least for editing documents. I created an AbstractDocumentController class that is meant to be a parent class for controllers used on pages with a single document data source. It just provides a couple convenience methods and hooks to override in type-specific cases or use directly in the basic case.
  • Another Simple View/Document Wrapper. This one isn't really anything new, but it's another example of how frequently it's useful to write a model class and manager instead of dealing entirely with the views and documents directly on the XPage with SSJS. The models make it clear what the important data is and the resultant XPage is pleasantly clean.

All in all, this has proven to be a good exercise in writing a focused, simple XPages app with an eye towards extreme cleanliness.

Taking a Swing at the URL Problem

Sun Nov 04 19:20:03 EST 2012

Tags: xpages urls

In the new portfolio web site I'm setting up for myself, I've decided to see what I can do about Domino's, and XPages' specifically, tendency towards ungainly URLs. An XPage URL, particularly an auto-generated one from, say, a view panel, can quickly become filled with undesirable elements - namely, ".nsf", ".xsp", "$$OpenDocument", "action=", and "documentId=". They all make sense and serve important purposes for the server, and to a certain extent URLs other than the main one don't matter, but I want a clean address bar, dang it.

The approach I'm trying now involves creating a managed bean named "url" that implements Map<String, String>. Its get() method takes a normal URL of the kind that you would usually write for a page and returns a cleaned-up version if it can find it, and the original URL otherwise. So a link to, say, the contact page looks like this:

<xp:link text="Contact" value="${url['/Contact.xsp']}"/>

I also set up a "link" custom control to act as a drop-in replacement so I don't have to do that EL bit everywhere. The code itself generates an internal map based on a view of simple From/To "Alias" documents in the DB, though I'm considering having it peek into names.nsf to find any applicable Web Rules more dynamically. The net effect is that I can use that bit of EL or the custom control and hand it a "normal"-style database-relative XPage URL and it'll clean it up if it can or, worst case, pass it through directly.

I can imagine some improvements, beyond the switch to looking at names.nsf instead. For one, I should make it handle "partial" replacements, so that I could map, say "/whatever.nsf/Posts/postid" to just "/posts/postid". I could go beyond that, too, making it do regular expressions to allow it to translate arbitrarily-complex routes beyond what just checking Web Rules could do.

I'm not certain that this is necessarily the best way (the REALLY best way would be to hook into whatever code handles all URL generation in the app), but it has a nice simplicity to it and I figure it's worth a shot.

Improving My Development Process: Source Control

Mon Oct 22 16:50:00 EDT 2012

I think it's fair to say that most professional programmers know that they should use source control, but, unless you work for a company that mandates it, you treat it like flossing or going to the gym. However, unlike your personal health and well-being, using source control is very important and can improve your life noticeably.

I'm a recent convert, in part due to Domino's historic hostility to proper source control. However, since 8.5.3 and its inclusion of the surprisingly good Source Control Enablement, there's no more excuse to slack. If you haven't already, read/watch the following things (and shame on you):

But beyond the basics of "make sure to check in changes with useful notes", I want to figure out the best way to do Domino development in this brave new source-controlled world. Mainly, I think I'm going to try to adopt a model similar to a shipping application: longstanding "write once" branches for significant versions, lengthy but temporary branches for development of the next version, throwaway branches for pie-in-the-sky ideas (like whenever I want to try to re-do my forum app's data access layer), and deployment via Source Control Enablement's "New Database From..." functionality.

That last part is huge, especially now that it's so easy to point an XPage app to a different database for its data access. I'm going to try more of an app/data separation in the future - I'm not sure I'll stick with it, but I think it could be very useful in deploying a new just-about-live version of an app alongside the "real" live one.

Regardless of the specific form my development process takes, I'm aiming to integrate source control thoroughly, to the point where NOT using source control feels "dirty", the same way that modifying a production app directly does. Fortunately, it doesn't take much to reach that point - just one instance of a client asking "is there any way we can go back to how it was working at the start of the week?" and being able to do it and you'll never look back.

A Couple Things I've Been Trying Out Lately

Tue Oct 16 09:22:18 EDT 2012

Tags: xpages

I'm always trying to figure out new tricks and (groan) patterns for my XPages development, and I've had a couple trends and experiments lately that I think are worth mentioning.

First off, I've been doing a lot of source control stuff lately, but that's a topic for another post, currently in crummy-draft form.

Beyond that, I think I'll just start a list:

  1. The joys of ExtLibUtil. Historically, I've had a general "JSFUtil" class (with the name and original code copied from here), but I've stopped copying that around from DB to DB and instead have started only copying the methods I really need, instead looking first at the ExtLibUtil class. If you, like me, were slow to hear about this bundle of magic, I suggest you take a look.
  2. Using the DominoDocument class in a bean. This one I'm not sure of, but I figured I'd give it a shot. DominoDocument is one of the classes that the XPages environment uses to wrap a lotus.domino.Document object and make it more or less persist across serialization. I decided to try using this (and maybe the View equivalent later) directly on the theory that it might be a bit easier to use and maybe even faster. So far, it's been a bit of a hassle, but I do enjoy having the various DataObject methods available for passthrough for my bean for EL use.
  3. Dynamic form generation. This is along the lines of something I was discussing in a chat the other day - the notion of having some more default "scaffolding" for XPages, where it could pick up more of the existing database elements without having to actually write the form XPage (or drag the fields over). For a simple data-driven app, having an XPage that generates type-appropriate fields (including keyword values from drop-downs and the like) could save a lot of time up front.
  4. "Controller" classes to back XPages. I've started more often making classes meant to have a bit of knowledge about a specific XPage (say, Document.xsp paired with DocumentController.java) and putting almost all code in there. So, instead of having a bit of SSJS on the save button to handle saving the document, putting a confirmation in the flashScope, and handling a redirection (ideally by returning a string), I do something like <xp:eventHandler ... action="#{documentController.save}"/> and write all the code in Java. This is still slightly awkward, but it's another way to move code out of the XPage itself, aiming to go EL-only as much as possible.

Most little tweaks like these aren't huge on their own, but they all combine to make significant quality-of-life improvements. It's a great feeling to see my XSP markup getting leaner and easier to read day by day.

Forms 'n' Views

Mon Sep 10 19:33:03 EDT 2012

One of my (many) for-fun projects lately has been a design-element editor named "Forms 'n' Views". Though it's not really release-quality, it's been coming together enough to toss it up on GitHub and make a post about it. Basically, it's meant to serve a couple purposes:

  • Help mitigate the "Windows problem" - when all you want to do is make a quick change to a legacy design element (say, a stylesheet), but doing so would mean firing up a Windows VM, launching Designer, and opening the DB. For quick edits, the amount of time that takes wildly eclipses (heh) the time spent actually coding.
  • Experiment with a data-focused way to edit forms and views. The legacy editors are geared towards a Notes client target, dedicating most of their space to aspects that have no meaning when the design element is intended just for backing an XPage.
  • Eventually, provide a way to grant "sudo"-style access to other users to modify certain design elements without granting full designer/manager access, setting up WebDAV, or exposing a poor web designer to Designer.
  • Let me experiment with a different setup for an XPages app - Forms 'n' Views consists of a Dojo BorderContainer- and TabContainer-based UI on a single XPage, which loads up tabs containing custom controls on the fly. None of it is unexplored territory, but it's good to write different kinds of apps sometimes.
  • Let me try out some more backing-class architectures. Each editor is backed by a DOM representation of the exported DXL, which is manipulated through wrapper classes and then re-imported back directly. Things like getting lists of columns are done via XPath queries without storing the data redundantly.

In its current incarnation, it's taken on the pale complexion of Dojo's "claro" theme - I've been going back and forth between that and the Notes-like "soria" theme:

Forms 'n' Views

It should do for now, but I'll likely fiddle with it more to make it look better.

In any event, this has been a fun project so far, and hopefully it'll shape up into a useful tool.

Building XPages servlets with FacesContext access

Thu Sep 06 10:05:00 EDT 2012

I have a confession to make: I'm not crazy about XAgents. Don't get me wrong - they do everything they're supposed to and do it well. However, it's always kind of bothered me that you take a visual design element like an XPage and turn off all the higher levels to get back down to the core servlet. Plus, it muddies the list of XPages in the DB - some are actual XPages, some are just wrappers for scripts. So my objection is essentially pedantry.

However, the fact that my objection is wildly exaggerated has never stopped me from sinking a lot of time into finding the "right" answer before, and it hasn't stopped me now. When what I want to build is, say, an Excel exporter for a particular type of document in a reporting DB, what I really want is a basic servlet that exists only in the database and has access to the surrounding XSP environment and custom classes. Fortunately, between a post by Sven Hasselbach, the referenced Chinese-language developerWorks article, the XSP Starter Kit, and a bit about facesContext.release() on a JSF-focused article and reinforced by the FacesContextServlet class from the ExtLib, I made it work.

The developerWorks article covers the bulk of the work - creating the Factory, setting up the file in META-INF, etc.. After that, you can set up your servlets by extending (using the Starter Kit method) DesignerFacesServlet. It turns out that the important thing to remember is to close out your context when you're done - I ran into a lot of trouble from not doing this, which would break XPages visited after the servlet. As an example, here's the test class I ended up building while figuring out how to make it not blow up my application:

import java.io.*;
import java.util.*;
import com.ibm.commons.util.StringUtil;
import com.ibm.xsp.webapp.DesignerFacesServlet;
import javax.faces.context.FacesContext;
import javax.servlet.*;
import javax.servlet.http.*;

public class TestServlet extends DesignerFacesServlet implements Serializable {
	private static final long serialVersionUID = -1152176824225969420L;

	@SuppressWarnings("unchecked")
	@Override
	public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
		// Set up handy environment variables
		HttpServletRequest req = (HttpServletRequest)servletRequest;
		HttpServletResponse res = (HttpServletResponse)servletResponse;
		ServletOutputStream out = res.getOutputStream();
		FacesContext facesContext = this.getFacesContext(req, res);

		try {
			res.setContentType("text/plain");

			out.println("start");

			// The sessionScope is available via the ExternalContext. Resolving the variable
			//	would work as well
			Map<Object, Object> sessionScope = facesContext.getExternalContext().getSessionMap();
			sessionScope.put("counter", sessionScope.containsKey("counter") ? (Integer)sessionScope.get("counter") + 1 : 1);
			out.println("Counter: " + sessionScope.get("counter"));

			// A query string map is available via the request. This method, as opposed to
			// 	getting the "param" variable, returns arrays of strings, allowing things like
			//	"?foo=bar&foo=baz" properly
			Map<String, String[]> param = req.getParameterMap();
			for(String key : param.keySet()) {
				out.println(key + " => " + StringUtil.concatStrings(param.get(key), ';', false));
			}

			out.println("done");

		} catch(Exception e) {
			e.printStackTrace(new PrintStream(out));
		} finally {
			out.close();

			// It shouldn't be null if things are going well, but a check never hurt
			if(facesContext != null) {
				facesContext.responseComplete();
				facesContext.release();
			}
		}
	}
}

I set up my ServletFactory to use this one for "/test", and so it's available via a URL like "/database.nsf/xsp/test?foo=bar". As with an XPage, you can also chain more path bits on after the servlet name, like "/database.nsf/xsp/test/some/other/stuff" and get to that via req.getPathInfo() - though with the caveat that, unlike with an XPage, the servlet path is included in the path info, so it would return "/xsp/test/some/other/stuff".

So long as I don't run into any other app-exploding problems, I plan to go this route for non-UI requests like exports and actions. When I have a use for it, I'll also go down the related path of writing custom services, for which the ExtLib provides an extensive foundation.

A Custom Control for dojox.widget.Toaster

Wed Sep 05 09:27:00 EDT 2012

Tags: xpages dojo

Update: Looks like Chris Toohey beat me to this by a couple months: http://www.dominoguru.com/pages/04092012113950.html

Marky Roden did a presentation at MWLUG that included, among other things, a demonstration of Pines Notify, a jQuery plugin that provides Growl-style notifications - something that could come in tremendously handy in a lot of situations.

I wanted to use something like this, but I decided to check to see if there's an equivalent in Dojo already, so I don't have to start including jQuery as well. Fortunately, there is... ish. dojox.widget.Toaster serves a similar purpose, though it takes its design cues from the little "toaster" notifications common on Windows. However, their default appearance is the worst thing in the entire world:

GAH MY EYES

Fortunately, that can be cleaned up with a little CSS to be a crummy version of Growl:

A little better

With a bit more work and attention to detail, it could end up pretty classy. I think it's still not as featureful as Pines Notify (no "clickthrough" options, its handling of multiple messages with different timeouts is not nuanced, etc.), but it's serviceable.

The API to use this widget is actually pretty straightforward: you run a bit of code at page load to create a toaster object to listen to a specific channel name (e.g. "/save/success") and then publish messages whenever you want something to appear. The code for sending a message is pretty simple, and there are two forms, depending on whether or not you want to include additional parameters:

dojo.publish("/test/channel", ["This is message one, lasting five seconds"])
dojo.publish("/test/channel", [{ message: "This is message two, lasting 10 seconds", duration: 10000 }])

I decided to wrap the instantiation and required resources up into a custom control and make another demo DB:

http://frostillic.us/tests/djToaster.nsf

The "toaster.css" page is the CSS I wrote to override the standard behavior. The margins are intended for the top-right positioning, but could be changed readily to equivalents for other corners.

The control exposes five properties: messageTopic (the channel name, required), defaultType ("message", "error", etc.), duration (in milliseconds), positionDirection (the position and slide direction, defaulting to up from the bottom right), and separator (the text that appears between two simultaneous messages).

Quick-and-Dirty CKEditor Toolbar Setup for XPages

Tue Sep 04 19:35:00 EDT 2012

Tags: ckeditor

Update: Looks like I was late to the game on this as well: http://www.intec.co.uk/xpages-8-5-2-rich-text-extending-the-ckeditor/

A while back, I got annoyed by the lack of a "Source" button in the default rich text editor in XPages. After a bit of digging, I found that there is indeed one (not to mention a whole world of CKEditor toolbar plugins and enhancements) - just not by default. I think there's a way you can pick from a couple named "stock" toolbar layouts, but I ended up going the route of defining my own, naming each button in a group.

In CKEditor, at least pre-3.6 (and I guess it works later too), toolbars can be defined inline via a JSON array-of-arrays in the "toolbar" property of the editor. A hopelessly simple toolbar definition would look something like this:

[
	["Bold", "Italic", "Underline", "Strike", "-", "TextColor", "BGColor" ],
	["Indent", "Outdent"]
]

That would define two button groups with the named controls present. The "-" is a way to manually place a separator - think of them like non-breaking spaces: they look the same as the divider between groups, but will not cause the group to be split onto a second line if the toolbar is too wide for a single row.

For my purposes, I went a bit nuts:

[
	["Format", "Font", "FontSize"],
	["Bold", "Italic", "Underline", "Strike", "-", "TextColor", "BGColor", "-", "JustifyLeft", "JustifyCenter", "JustifyRight", "JustifyBlock", "NumberedList", "-", "BulletedList"],
	["Indent", "Outdent"],
	["Subscript", "Superscript"],
	["RemoveFormat", "-", "MenuPaste", "-", "Undo", "Redo", "Find", "LotusSpellChecker", "-", "Image", "Table", "Link", "Flash", "-", "PageBreak", "HorizontalRule", "SpecialChar", "Blockquote", "Smiley", "ShowBlocks"],
	["Maximize", "Source"]
]

Inside an XPage, you can set this using the "attrs" property in 8.5.3 - though "dojoAttributes" would probably work fine in 8.5.3 and earlier as well:

<xp:inputRichText value="#{doc.Body}">
	<xp:this.attrs>
		<xp:attr name="toolbar"><xp:this.value><![CDATA[
			[
				["Format", "Font", "FontSize"],
				["Bold", "Italic", "Underline", "Strike", "-", "TextColor", "BGColor", "-", "JustifyLeft", "JustifyCenter", "JustifyRight", "JustifyBlock", "NumberedList", "-", "BulletedList"],
				["Indent", "Outdent"],
				["Subscript", "Superscript"],
				["RemoveFormat", "-", "MenuPaste", "-", "Undo", "Redo", "Find", "LotusSpellChecker", "-", "Image", "Table", "Link", "Flash", "-", "PageBreak", "HorizontalRule", "SpecialChar", "Blockquote", "Smiley", "ShowBlocks"],
				["Maximize", "Source"]
			]
		]]></xp:this.value></xp:attr>
	</xp:this.attrs>
</xp:inputRichText>

It looks like the syntax changed for 3.6, but not too much.

If you want to look into more specifics, you can take a look at the examples and un-minified code in (data)/domino/html/ckeditor/_samples and _source.

A Couple Updates to My Domino-One-Offs Repository

Tue Sep 04 18:25:00 EDT 2012

Tags: xpages java

I realized earlier that I let a couple of the classes in Domino-One-Offs stagnate relative to the versions I currently use. Since originally posting my convenience XML library and, more usefully, the DynamicViewCustomizer, I've tweaked both in my various projects to add more features I ended up needing.

The DynamicViewCustomizer has gone further down the path of Notes-client fidelity at the expense of a bit more overhead, doing things like setting column widths (except where the column is set to extend to the window width, either specifically or by virtue of being the last column, as appropriate). It's still not perfect, as I ran into a bit of trouble with, I think, HTML in category columns (and you can see commented-out remnants of various other changes), but it's potentially useful.

For my "man, I hate dealing with all these stupid orthogonal Java XML libraries" XML library, I've added a number of functions to support my Forms 'n' Views app (coming Soon™), namely better attribute handling, a simple NodeList wrapper (that actually acts like a List), and a basic getXml() method for when you just want a string version.

Finally, I tossed in the current version of my SortableMapView class, meant to gobble up Views or ViewEntryCollections and make them sortable by all columns. That one uses Lombok, but I think you could just remove the bits about making it List-compatible and still be fine.

An Extended Document Data Source To Support MIMEBean

Wed Aug 22 20:02:00 EDT 2012

Tags: mime xpages java

Ever since I personally came up with the idea of storing serialized Java objects in Notes documents via MIME, I've been trying to use the technique all over the place, since it's basically the best thing since sliced bread.

My latest notion was that the pattern would be all the cooler if the serialized Java objects could be referenced directly in EL, so you could do something like #{doc.LineItems[3].cost}, pulling directly from a more-or-less normal Domino document. I decided to give implementing this a shot, since it would also have the side benefit of introducing me to writing JSF components/complex types.

The path I took sure feels like the long route (lots of manual doubling up of property definitions and proxying methods), but it seems to work: I have a "mimeDominoDocument" data source that acts just like a normal document source except it transparently serializes and deserializes Java objects. It's not exactly a perfect implementation (the setValue() method has a rather naive method of guessing which objects should be serialized and which shouldn't, and I didn't handle the case of setting a value to an object and then using, say, getItemValueString()), but it should be fine for demo and basic purposes.

I set up an example database with pages for the appropriate code here: /tests/mime.nsf.