How to quickly get a nice looking month-calendar together with SmartNSF
Update Feb 28th, 2017: It turns out that Klaus Bild and Christian Güdemann had a presentation at IBM Connect 2017 diving into SmartNSF. I recommend you to head over to see the slides from the session DEV-1478 – Your App Deserves More – The Art of App Modernization for even more details!
Have you ever wanted to get a nice looking month-calendar based on your Domino data? Sure you have! Perhaps something like this;
Here you see the end-result (go to June to see some data if interested).
Many others have done similar things to make Domino stuff its data into calendars of different kinds, so the only new thing here is that by using SmartNSF, I want to show that it is really easy to get the JSON you want!
The fullcalendar.io has an event property which can be filled in by code, or by retrieving JSON from somewhere. Below you see a sample of JSON outputted from my Domino-database;
The only needed names are start, end and title. The others are just there for extra use such as url that will kick in when you click on a calendar event.
How get the JSON you want? Many possibilities exists, from using agents, XAgents or real servlets. While both agents and XAgents can achieve what you want, several issues arise, such as load on the Agent Manager on the server (agents) and invoking unnecessary phases (XAgents). When SmartNSF surfaced (more in a sec!) I personally was working along with my own implementation on real servlets, much based on the fantastic work by Eric McCormic and the blog-posts A Saga Of Servlets-series (also kudos to Jesse Gallagher which as far as I understand it, paved the ground for many similar projects with this fantastic blog-post).
My idea was to have a a generic servlet which read configuration information from documents inside the database and exposing the configurations as servlets.
Meet SmartNSF! Download it fra OpenNTF and install it on your server (I use my so-called update-site database, making it a breeze to add SmartNTF to the server along with other important plugins such as XPages Extension Library) and onto your Domino Designer. If you don't see the File -> Application -> Install menu, then ensure that your Designer preferences has the Enable Eclipse plug-in install enabled;
When installed, you have installed a plug-in which instantly let you define routes that let your URIs point to real resources in your database. Below you see my test route defined;
(Click to see a larger image!)
If you have the Designer-perspective set to Forms and Views, you will see the new XRest API Routes as a new design element in your database (marked by 1 in the screen shot above). Behind the scenes this design element is actually the WEB-INF\routes.groovy file. Below you see its whereabouts in the NSF when you have the Java-perspective activated in the Designer;
Marked by 2, you see that I have defined a GET-type route with the name of rentals;
This is the URL that I will use to get my JSON as a REST Service like
The /xsp/.xrest/ is the URI-part which triggers the SmartNSF's handler. Don't like the look? Create a internet site subsitution rule to hide it.
Note that I can specify a strategy too, and here the SELECT_ALL_DOCUMENTS_BY_VIEW will select all documents by a specified view name. And yes, the Domino view name as an alias of xrestRentalsView in my case (marked by 3). Just to water your mouth, the other strategies are SELECT_DOCUMENT_BY_UNID,SELECT_DOCUMENTS_BY_SEARCH_FT, SELECT_DOCUMENTS_BY_FORMULA, SELECT_ALL_DOCUMENTS_FROM_VIEW_BY_KEY and SELECT_ATTACHMENT! Did I mention that SmartNSF also supports full CRUD (Create, Replace, Update and Delete)? Each route can also be limited to work with certain ACL roles, meaning that you for example can have a set of routes available to everybody to read, while you need to be logged in to create, update or delete
Now over to the JSON. Marked by 4 you see a set of mapJson-statements;
The first attribute is either the field-name or element-name. The strategy SELECT_ALL_DOCUMENTS_BY_VIEW in my case will enumerate all documents present in the view xrestRentalsView, and it has direct access to all the fields in the documents. Examples of real field names in my case is txtOrganizationName, txtEventStartDate and txtEventEndDate. By specifying real names, you grab the field content directly. One example of such mapping is:
mapJson 'txtEventStartDate', json:'start', type:'STRING'
Note the type. If have found STRING, INTEGER, DOUBLE, MIME, DATETIME, DATEONLY, TIMEONLY, ARRAY_OF_STRING, ARRAY_OF_INTEGER, ARRAY_OF_DOUBLE and ARRAY_OF_DATETIME!
Note that the name can be other strings too, if you for example use a formula. In that case you would typically use the attributes isformula and formula too as shown for the mapJson id, description and url. Note that the formula can be a normal Notes @formula For id I have used @Text(@DocumentUniqueID). For the description, I have just used the field name, as I wanted to have a tooltip-like popup in the calendar (didn't work by the way). Finally the url-element has a much larger formula building up the URL.
All in all, the definition for a simple GET-servlet is my opinion very easy to program, and easy to understand!
The SmartNSF-plugin on the server automatically detect that an update has been saved to the database and rebuild the servlet-logic behind the scenes automatically.
How to make it display the JSON-data on a webpage?
Simply by uploading all the files from the fullcalendar zip file to the NSF! Several ways exists on how to do this. I have a little tool for this making it easy to import any file and directory into Notes and place it in into correct folders in Notes. However, you don't need such a tool. One way is to follow the steps described here or another way, without using any tools, is to open the database in the Designer's Java-perspective. Then you can both create your own folders and simply drag and drop the whole directory from your file system. Below you see my database with the Resources-folder expanded to the first level;
If you expand the Files-folder you see my files imported directly to the Files-folder;
Note the fullcalendar302-prefix (by the way, all the underscores is slashes in the file). This is the way my tool easily can keep files apart from each others and group files which belongs together.
In the fullcalendar-zip file you find a demo-folder, and if you look at the json.html (which uses PHP, but that doesn't matter in our case. I just wanted to see how fullcalendar grabbed JSON data from an URL) file you see the following;
I have marked the url-parameter. By switching to my newly generated URL for the JSON (http://www.berganvel.no/web/bsutleie.nsf/xsp/.xrest/rentals) the code almost worked instantly; The Chrome browser told me that I had a problem with 'XMLHttpRequest cannot load http-blabla No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access!. Below you see the Chrome Developer exposing this problem (press F12 to have Chrome expose the developer tools);
The error all relates to the Cross Origin Resource Sharing (CORS) protection (see much more here). Briefly this means that a web page won't load resources with XMLHttpRequest unless it has the same origin. In my case a local file open tries to fetch data from www.berganvel.no.
As soon as I uploaded my edited demo html file to my Domino database and tried to load the page it worked instantly!
The edited demo file look like this now;
Note that I, marked by 1, ensure that I load the fullcalendar-files from my 'fullcalendar302-folder (this may very well be different in your implementation). Marked by 2 is my new URL grabbing all my calendar data as JSON from SmartNSF's servlet.
Also note that I specified locale: 'no' to get Norwegian.
Furture improvements to my code
As you see I have not used XPages or anything other than SmartNSF to get this rolling. A future improvement could of course be to wrap the page into XPages, or build something in perhaps some more modern techniques. By using the CRUD possibilities in SmartNSF, I could allow end users to a lot their own events, and store the documents via REST in my database.
Conclusion; SmartNSF is one of the coolest things to surface in the Notes/Domino arena for a long time! Thanks Christian Güdemann for this wonderful contribution!!
PS! Cool to see that SmartNSF was both mentioned in the Opening General Session of IBM Connect 2017. At the end it was also mentioned as one potential candidate to include in a feature pack!