Table of Contents
Introduction
Part One – The Application
Part Two – XPages Advanced 1
Part Three: XPages Advanced Database Separation
Part Four: XPages Advanced Document Wrapper
Part Five: XPages Advanced MVC Controller
Part Six: Use of OpenNTF Domino API
Part Seven: OSGi Application Development Introduction
Part Eight: OSGi JAX-RS REST Access with ODA
Part Nine: OsgiWorlds
Part Ten: Vaadin
Part Eleven: OsgiWorlds Document Wrapper
Part Twelve: Key Date Page
Part Thirteen: Application Structure
Part Fourteen: Calendar View
Glossary
This is not a part of the series I had planned. But after I talked about the blog posts from Toby Samples about using JAX-RS for HTTP Servlets to provide more secure and tailored REST access to an NSF, I was conscious that this begged the question about how to use OpenNTF Domino API in such a servlet application. It’s not an area I have much experience of. I’ve not developed JavaScript web applications and outside of Domino my preference would be CrossWorlds (as I’ll cover later in this series). So I’ve not had the need for REST access and only done brief investigation of JAX-RS, which is quite obviously the best practice approach and much easier than trying to compose responses with strings. But thanks to Toby’s GitHub project, I’ve managed to create a simple servlet outputting the current username.
Following Toby’s steps gives a simple plugin (bear in mind there have been more developments of that repository since the initial release, so you might wish to refer directly to the initial commit. Also, if you use a pde launch configuration and have the Extension Library installed, you may get an error message saying it’s finding multiple SL4J bindings, as I did. It seems that this was being contributed twice, from Extension Library and the core, so I had to remove the org.apache.wink project that’s part of ExtLib from my Eclipse workspace and from the launch configuration.
Toby’s example just outputs the current username, as a simple “Hello World” demo. The method of getting the current user’s session is ContextInfo.getUserSession()
which returns a lotus.domino.Session. But with OpenNTF Domino API, we need an org.openntf.domino.Session. In XPages, the easiest way to get that is to resolve the variable session
of godmode is enabled, otherwise to resolve openSession
. Outside of XPages, however, you can’t just cast ContextInfo.getUserSession()
to an org.openntf.domino.Session object. Instead, outside of XPages, you need to use Factory.getSession(SessionType.CURRENT)
to retrieve the current session. However, if you tried that in the demo, it would throw the error org.openntf.domino.utils.Factory is not initialized for this thread, as some have encountered.
At this point it worth going into greater depth on what’s happening in XPages with sessions and why resolving variables actually makes best sense. Firstly, with vanilla XPages, if you’ve looked at scoped variables, you’ll know session
and database
get stored in requestScope
. Those variables obviously have to get re-applied on every request, because Domino objects are not serializable. So, not surprisingly, OpenNTF Domino API adds openSession
and openDatabase
objects to requestScope and, if in godmode, overrides the session
and database
objects. These are applied every time an XPage interacts with the XPages runtime and, before this is done, the process initialises the Factory and adds in the current user session, the signer session and the signer with full access session. (For those who want to know more, they’re applied as implicit objects by FacesContextFactories via either domino-faces-config.xml or OpenntfDominoXspContributor.) So why go to the Factory class to get the session, when the whole process has given you easy access via the implicit variables?
But outside of XPages – whether in a plugin or elsewhere, the Factory will not have been initialised for the thread: no current user session will have been added. So basically we need to do that.
In CrossWorlds, that’s done through a filter, but the ability to use a filter doesn’t work in Domino’s OSGi context (that was my first attempt for OsgiWorlds). In OsgiWorlds, we’ll see that’s done in a VaadinServlet, because every request from the browser to Vaadin has to go through that servlet. In a JAX-RS application, everything also goes through a servlet, defined in the web.xml with the following code in Toby’s example:
This passes everything through Apache Wink’s RestServlet. We can extend that, and I’ve created an XSnippet for it, which is basically a copy of a REST servlet class Nathan has already created in the org.openntf.domino.rest plugin for access via Graph. That reference in the web.xml will need re-pointing to the class you add.
The ODADataServlet class basically uses three methods: doInit() which starts the ODAPlatform (one per “application”, so one for this plugin), doDestroy() which stops the ODAPlatform, and doService() which does the processing. This first initialises the Thread based on configuration to enable all fixes and automatically convert fields to MIME if they hit 32k limit. Then it initialises the Factory using a new DasCurrentSessionFactory. This basically wraps ContextInfo.getUserSession()
into an org.openntf.domino.Session, which basically means your code can use Factory.getSession(SessionType.CURRENT)
to retrieve the current session. From there, you’re into the OpenNTF Domino API, so nothing needs converting.
So there’s no reason for REST servet developers to avoid using OpenNTF Domino API as well.
Postscript earlier today I tweeted that it depended on Nathan’s pending pull request to Extension Library. I’ve realised since that’s not the case.
Here is the com.paulwithers.demoServlet I created as a basic POC.
NOTE: The DasCurrentSessionFactory constructor has changed in ODA 3.0. If you’re using that version, use this version of com.paulwithers.demoServlet.
I also read the blog post from Toby Samples and I have successfully created a OSGI servlet plugin and deployed it to the Domino server. But I would also like to use the OpenNTF Domino API in this plugin. What is the best/correct way to add ODA to my Eclipse project?
Regards,
Torben
On the dependencies tab of your plugin.xml, I added org.openntf.domino and org.openntf.domino.xsp. Then the classes are available and it will just need to find the org.openntf.domino and org.openntf.domino.xsp plugins when it runs.
Thank you. It works now.
Regards,
Torben
After further investigation, DasServlet is the wrong class to extend in custom servlets. Instead extend com.ibm.domino.services.AbstractRestServlet
Hi Paul,
A great article series. I am learning so much! Newbie question: I downloaded your sample and loaded into my UpdateSite.nsf. What url would I hit to launch the servlet? I must be missing something small. Thanks for your help.
It took me a little time when I looked at it again recently. Try “http://my.server.com/mydemoservletpath/rest/helloworld”. The “mydemoservletpath” is defined by the “contextRoot” element in the plugin.xml. The “rest” part is defined in the “servlet-mapping” in WebContent\WEB-INF\web.xml (using “/*” would remove that part, if you wanted, but I think it’s usually included because the web app / OSGi plugin would provide other functionality). The “helloworld” part is defined by the @Path annotation of the HelloWorldResource.java class.
Anyone reading this part should take into account the lessons learned that mean ODADataServlet should extend AbstractRestServlet instead of DasServlet and the HelloWorldApplication class should extend RestService. See https://www.intec.co.uk/from-xpages-to-web-app-part-sixteen-osgi-jax-rs-rest-access-with-oda-revisited/
Hello Mr. Withers,
When I imported your project in eclipse, I get an Error in the ODADataServlet in the line:
Factory.setSessionFactory(new DasCurrentSessionFactory(), SessionType.CURRENT);
The error says that the DasCurrentSessionFactory must match with the argument DasCurrentSessionFactory(HttpServletRequest).
If I set these line with Factory.setSessionFactory(new DasCurrentSessionFactory(request), SessionType.CURRENT);
and deploy the osgi plugin to mi domino server and load the url http://myserverdomain/mydemoservletpath/rest/helloworld
I am getting the {“message”:null} result and in the console I am getting the following error:
[0EF4:000C-0F30] 08/11/2016 09:30:15 p.m. HTTP JVM: at org.openntf.domino.xsp.session.DasCurrentSessionFactory.createSession(DasCurrentSessionFactory.java:58)
[0EF4:000C-0F30] 08/11/2016 09:30:15 p.m. HTTP JVM: at org.openntf.domino.utils.Factory.getSession(Factory.java:954)
[0EF4:000C-0F30] 08/11/2016 09:30:15 p.m. HTTP JVM: at com.paulwithers.demoservlet.HelloWorldResource.getMessage(HelloWorldResource.java:25)
I am missing something? (I am using ODA 3.0 in eclipse) Can you point me in the right direction please?
Thanks,
Luis
UPDATE:
If I downgrade the ODA version from 3.0 to 2.0 it works perfect, but if I upgrade ODA to 3.0 again it fails in the line:
Factory.setSessionFactory(new DasCurrentSessionFactory(request),SessionType.CURRENT);
If I look in the source code of DasCurrentSessionFactory, it now requires a HttpServletRequest parameter, but If I put the request as a parameter in the DasCurrentSessionFactory it fails.
How can I fix it in order to use the ODA 3.0 version?
Thank you in advance,
Luis
Factory.setSessionFactory(new DasCurrentSessionFactory(null), SessionType.CURRENT);
is what is required with ODA 3.0 and above. The parameterised version was added in 3.0 and the old version removed. That’s what I’ve used in production ODA servlets.Thank you very much Mr. Withers, it is works perfect now. Also I was looking in the ODA 3.0 source code and I saw that if I pass a null parameter, these class will create a new lotus session and wrap into a org.openntf.domino.Session.
Thanks again for let me now the correct way of use these class.
Luis