By now, many (if not all) of you have heard about, and, perhaps, even already installed and begun playing with, the recently released XPages Extension Library. There are a plethora of reasons to be excited about this project, but most can be folded into two categories of awesome:
New controls for you to use and love
Let's face it: the majority of XPage developers will never write their own controls. Their employer subscribes to the "do more with less" philosophy, so they're behind schedule on ten different projects because they're the only Domino developer at their company who hasn't already been laid off. They want components that already work that they can just drag onto a page, set a couple properties, and have the page do what the component descriptions imply they'll do. If this description fits your situation, but you're excited by the notion of the Extensibility API, it's likely that your excitement is based in the knowledge that, like ASP developers have been able to do for years, you'll now be able to take advantage of functionality that doesn't ship with the product because somebody else wrote extension components, not because you plan to write any yourself. That's what this library provides... and it's free.
The Extension Library bundles together a sizable collection of immediately useful controls that you can use in any XPage application the same way you would use controls that are already native to the platform: specifically, the icons show up in the palette regardless of what NSF you're in... you don't have to copy these to every application like you do with Custom Control design elements. To get an idea of just how much extension this library represents, consider that Domino ships with 38 pre-defined native controls - Panel, Repeat, Edit Box, and so forth. The version of the Extension Library currently installed on my machine (which, admittedly, is newer than the version that was released yesterday) adds 68 new controls. This library doesn't just add a couple of "Hello World" examples of how one might use the Extensibility API... this nearly triples the amount of controls available to you, and each of these controls is truly useful. Just to further illustrate the point, I'll call out two of my favorites as examples:
The Application Layout control will be a favorite with anyone who likes the looks of OneUI, but hates having to remember what CSS classes to apply to all of the many elements that make up the layout specification. Just drag one control to your page, and everything that makes up the layout portions of OneUI are properties of this single control. So you can specify legal text, footer text, title bar tabs, bread crumbs, etc.... all as hierarchical properties of a single control. It's almost as simple as having a wizard for your layout: the property grid guides you through defining the layout of your page, so you can literally design the entire layout for your application in about 5 - 10 minutes.
Real-world examples to inspire your own extensions
As I mentioned, the controls aren't simply "Hello World" examples of using the Extensibility API, they are powerful examples of using the Extensibility API. So if you do get the urge to strap on your Java boots and try creating your own controls, you can start by analyzing how IBM writes controls - everything from the very simple "Keep Session Alive" control (which just allows you to specify an interval at which the page should ping the server to keep the viewScope active in case the user has left the page idle for hours but still expects to not lose their in-progress data when they return) to the REST services that will allow you to render a view as a Dojo grid that supports in-view editing (this wasn't included in the initial release, but it works on my machine, and will be included in a subsequent release). If you're like me, you'll find it's much easier to start diving into this by first looking at the way IBM approaches "real" use cases, and then model your own controls after their approach, than to stare blankly at a javadoc and try to guess how it all fits together.
With that context established, I've been askedbyseveralfolks to share my approach to storing control definitions directly in an NSF, bypassing the plugin installation process. Since I'm so fond of lists, here are two reasons why this can be useful:
Some admins adhere stubbornly to the principle of not allowing any modifications to a server, to the point of missing out on the spirit of that principle: maximizing the end user experience. Naturally, if a server has been mucked with in a way that negatively impacts reliability, that is A Bad Thing™. Conversely, however, if an admin refuses to put a JAR file on the server simply because it's not part of the standard Domino installation, and "that's against our policy", even though that particular JAR would allow a developer to provide users a better application in less time, this also is A Bad Thing™. Nevertheless, if you are at the mercy of such an admin, this will allow you to provide enhanced functionality to your users without the admin having to violate their sacred policy.
While installation of a control library is fairly easy (step one, install it as an Eclipse plugin into Designer, just like you'd install any other Eclipse plugin; step two, add any JAR files contained in the plugin to the plugins folder on the Domino server), when you're writing your own controls, the testing process is horribly tedious... tweak your code, build the plugin, uninstall it from Designer, restart Designer, reinstall the plugin, restart Designer, test, repeat until it works. Fun. This is, of course, assuming that you're not one of the three people on the planet who have figured out how to correctly configure Lotus Expeditor in a standalone copy of Eclipse (NOTE: I am not one of those three people). Hence, this allows you to reduce that to a mere two steps (apparently this post was brought to you by the number 2... and the letter X): write some code, test it. Much, much simpler. When the control is working the way you want it, then you can move it out of the NSF and into a real control library, so you don't have to copy it to every NSF... just install the library. But in the meantime, you can test changes immediately after you make them without having to go through all the hassle of treating it as a real plugin.
To stretch the binary nature of this post just a bit further, there are really two types of files that comprise any component's definition: Java and XML. A Java class (and any other classes it might reference) defines the control's behavior, and XML files expose the existence of these controls to Designer (and the XPages runtime). The XML files can, again, be subdivided into two types: faces-config.xml and .xsp-config files.
If you've gone spelunking in the Package Explorer, you've likely already stumbled upon both of these types of XML files, because Designer automatically creates these for you as you're developing your application. The faces-config.xml file is created in WebContent/WEB-INF, and while I've never actually seen Designer contribute any content to it, it inserts a commented section where it would place its own contributions if needed. So if you're defining managed beans, for example, this is the file where you'd store that definition... so be sure to place that definition outside of that commented section. Any .xsp-config files automatically generated by Designer will be located in the CustomControls folder. Whenever you edit an XPage, you're really editing a .xsp XML file that tells Designer what Java to automatically generate for you. When you edit a Custom Control, however, you're really editing two XML files - the corresponding .xsp file, and a .xsp-config file that tells Designer that control exists. In fact, the existence of that .xsp-config file is really the reason that the icon for the Custom Control shows up in Designer; if the Java file that corresponds to the control didn't exist, it still wouldn't show up, of course, but even if it did and Designer hadn't created the .xsp-config file, the control would exist but Designer wouldn't know that.
Hence, the easiest way to include extension controls in an NSF without properly installing a control library is to simply create a linked source folder: right-click the application's folder in the Package Explorer, then select Build Path, Link Source. Browse to the top-level source folder (typically called "src") for the control library, set a folder name that will be unique in the NSF, and click Finish. In the case of the Extension Library described above, at a minimum you'll probably want to link the core plugin ("extlib"), "extlib.domino", and "extlib.oneui", but there's some other cool stuff in there as well (for instance, "extlib.dwa" includes the iNotes Calendar view as a control... let that one sink in for a moment...).
Because both the Java classes and the corresponding XML files are contained in subfolders of your linked source folder, as soon as your application finishes rebuilding (which will take a while, especially if you're linking to several of these plugin folders), you'll see the icons for the controls show up in your palette. Be warned, however: since a lot of these controls are fairly sophisticated, actually using them without properly installing the plugin is going to be hit or miss. There's a lot of other stuff going on behind the scenes that the OSGi framework allows which you can't really take advantage of unless it's treated as a true plugin. But here's something that might help: if you locate the faces-config and xsp-config files for each of the plugins you linked to (in each case, they'll be stored in a META-INF folder inside the src folder), drag them into WebContent/WEB-INF in the NSF. This ensures that they're actually stored inside the NSF and not just in the workspace folder in your Notes installation. I've found that, for some of the controls in the Extension Library, this is perfectly sufficient. But here's another word of warning: if you do take this linked source approach - at least with the Extension Library, which contains approximately 800 Java classes - every time you make any change to any XPage, the build process is going to be sloooooow, because you've introduced an additional layer of complexity into what Designer has to do in order to determine exactly what code the application contains. So you've circumvented the admins. Great. You've also just punched your productivity in the face if you don't have an SSD.
There is good news, however: on an individual control basis, there's a much better way. Add your own src folder to WEB-INF, designate it as a src folder, and create your control classes within that folder. Then add a .xsp-config file for the control to WEB-INF and, if needed, define its renderer in the faces-config.xml that's already there in the same folder. That works like a charm.
Much less obvious caveat: if you're configuring your control this way for testing purposes - for instance, you've already got a plugin library installed, and you're just developing a new control that you want to add to it - this works fine as long as the control is an extension to a native component (UIComponent, UIInput, or one of the core controls that ship with Domino). If, however, you're extending an extension (maybe you dig IBM's Dialog implementation but want to automate the addition of OK and Cancel buttons), the Java class for the base component must be directly in the application's build path - not in the plugin dependencies - even though at runtime the classloader would be able to find it. If Designer can't find it in the build path, the icon won't show up in the palette. Yes, I learned this the hard way.
locating XPage components with XspQuery
Sun, Apr 14th 2013 12:00a Tim Tripcony Several years ago, I wrote a utility Java class designed to make it easy to search for components within the current XPage instance based on various criteria. I've found it enormously useful, and, apparently, so has Keith Strickland, because he added it to org.openntf.xsp.extlib, complete with a few refinements. As an example of how you might use this, examine the following line of code:
List requiredFields = new XspQuery()
.loc [read] Keywords: ldd
your how is not your what
Wed, Apr 3rd 2013 11:36a Tim Tripcony I've noticed a pattern emerging when I'm asked for help with XPages. Here's a representative conversation:
"I'm trying to do [X] and it's not working. How can I do that?"
"What are you trying to accomplish?"
"I already told you. I'm trying to do [X]."
"No, that's how you're trying to do it. What are you trying to do?"
For example, replace "[X]" with "reach into a repeat control from outside it" (since this has become the most frequent topic I'm asked about [read] Keywords: xpages application
my new favorite quote
Sat, Mar 23rd 2013 5:20p Tim Tripcony "We go about our daily lives understanding almost nothing of the world. We give little thought to the machinery that generates the sunlight that makes life possible, to the gravity that glues us to an earth that would otherwise send us spinning off into space, or the atoms of which we are made and on whose stability we fundamentally depend. Except for children (who don’t know enough not to ask the important questions), few of us spend much time wondering why nature is the way it is; where the [read] Keywords: wiki
Taking the scary out of Java in XPages: Prologue
Tue, Feb 26th 2013 9:50p Tim Tripcony The discussion following my last post made stark the need for greater availability of information that makes the nature of Java more accessible to Domino developers. Credit for the title of this post goes to Declan, who is considering writing a series of blog posts on this topic. I will be doing the same; hopefully there will be a fair amount of duplication. As David Leedy is fond of stating, it's a good thing when several people share the same information, because that makes it easier for the [read] Keywords: domino
Passthru vs. component - my perspective
Sat, Feb 16th 2013 9:40p Tim Tripcony Paul Withers posted a thorough article explaining the differences between namespaced XPage components (e.g. ) and their corresponding passthru elements (e.g. ), providing numerous examples of what actually happens when these objects are constructed. I've always heard (and often repeated) that passthru elements are more efficiently processed than their namespaced equivalents, so Paul's post inspired me to offer my own perspective.
Simply put, there's practically no difference... but there a [read] Keywords: acl