We Have The Technology: The org.openntf.domino API

Thu Mar 21 21:16:14 EDT 2013

As Nathan and Tim posted earlier today, a number of us have been working recently on a pretty exciting new project: the org.openntf.domino API. This is a drop-in replacement/extension for the existing lotus.domino Java API that improves its stability and feature set in numerous ways. The way I see it, there are a couple main areas of improvement:

Plain Old Bug Fixes

doc.hasItem(null) crashes a Domino server. That's no good! We've fixed that, and we're going through and fixing other (usually less severe) bugs in the existing API.

Modern Java

Java has progressed a long way since Domino 4.x, but the Java API hasn't much. Our API is chock full of Iterators, proper documentation, generic type definitions, preference for interfaces over concrete classes, and other trappings of a clean, modern API. Additionally, Nathan put together some voodoo programming to take care of the recycle thing. You read that right: recycle = handled.

New Features

In addition to cleaning up the existing functionality, we're adding features that will be useful every day. My favorite of those (since I'm implementing it myself) is baked-in MIMEBean-and-more support in get/replaceItemValue:

Set<String> stringSet = new HashSet<String>();
stringSet.add("foo");
stringSet.add("bar");
doc.replaceItemValue("Set", stringSet);

doc.replaceItemValue("Docs", database.getAllDocuments());

NoteCollection notes = database.createNoteCollection(true);
notes.buildCollection();
doc.replaceItemValue("Notes", notes);

doc.replaceItemValue("ExternalizableObject", new MimeType("text", "plain"));

List<String> notAVector = new ArrayList<String>();
notAVector.add("hey");
doc.replaceItemValue("TextList", notAVector);

doc.replaceItemValue("LongArray", new long[] { 1L, 2L, Integer.MAX_VALUE + 1L });

That's all legal now! We have more on the docket for either the initial release or future versions, too: TinkerPop Blueprints support, easy conversion of applicable entities to XML and JSON, fetching remote documents from DXL or JSON files, proper Logging support, and more.

 

As we've been developing the new API, we've already found it painful to go back to the old one - it doesn't take long to get spoiled. And fortunately, the transition process will be smooth: you can start by just replacing one entry point for your code (say, changing "JavaAgent" to "org.openntf.domino.JavaAgent" in an agent), then advance to swapping out your "import lotus.domino.*" line for "import org.openntf.domino.*" line, and then start using the new methods. All the while, your existing code will continue to work as well or better than before.

We hope to have a solid release available around the beginning of next month, and in the mean time I highly encourage you to check out the code. Download it, give it a shot, let us know how it works for you and if you have anything you'd like us to add.

A Mini-Vacation With Ruby and the Domino Data Service

Sat Mar 02 17:52:16 EST 2013

Tags: ruby

Since I've been neck-deep in LotusScript and Java for the past couple weeks, I decided to take a bit of a sanity break today and play around with Ruby. Specifically, I wrote a skeletal wrapper for the Domino Data Service in the ExtLib and the first steps of a Rails app using it a bit. I don't expect this to actually be useful down the line, or even necessarily to get any more work put into it, but it was a fun diversion.

The API takes the same general shape as the normal Domino API, except you start with a database, which can take connection and credential parameters (though the credentials don't actually work for some reason). So to access the testing database I created, I do this:

db = DHTTP::Database.new(
  :server => "api.frostillic.us",
  :path => "tests/http.nsf"
)

In the Database class, I implemented a way to get all views or to get a view by name, while views let you get entries, which in turn contain their values and a way to get documents, which provide the usual item access. For example:

db.views.each do |view|
    puts "Found view: #{view.title}"
end

view = db.get_view("TestView")
view.entries.each do |entry|
	puts "Column values: #{entry.column_values}"
	puts "Doc body: #{entry.document.Body}"
end

It's not particularly amazing, nor is it particularly efficient, but it does the job: it supports the service's paging for view entries and converts Date/Times to Ruby Times for document fields, so it could be used for light read-only use.

Then I set up an extremely bare-bones Rails app that uses the objects in the most direct and ugly way possible, but, again, it works:

class TesterController < ApplicationController
  def index
    db = DHTTP::Database.new(
      :server => "api.frostillic.us",
      :path => "tests/http.nsf"
    )
    @views = db.views
  end
  
  def view
    @title = params[:title]
    db = DHTTP::Database.new(:server => "api.frostillic.us", :path => "tests/http.nsf")
    @view = db.get_view(@title)
  end
end

The two pages just spit out lists of either the views or the view entries:

<ul>
<% @views.each do |view| %>
    <li><%= link_to(view.title, :action => 'view', :title => view.title) %></li>
<% end %>
</ul>

...and...

<ul>
<% @view.entries.each do |entry| %>
    <li><%= entry.column_values.inspect %></li>
<% end %>
</ul>

I think the Domino REST API could be really useful. When I looked into it a while ago, I ran into trouble wherein the view entry counts didn't reflect entries hidden via reader fields, which is probably still the case, but other than that I imagine it could be put to real use. It brings it more in line with the other modern NoSQL databases, which generally use HTTP/JSON-based APIs as well. Combine that with Apache for load balancing and failover and suddenly you have a really compelling modern database back-end for other platforms.

If you're interested in looking at the code, I tossed the API up on GitHub: https://github.com/jesse-gallagher/Domino-HTTP-API-for-Ruby