Tuesday, January 05, 2016

DSAPI for Domino

This post is about to make short summary about DSAPI filter. I've finished my project some time ago and it looks like I'm not going to do any work with it in near future.

What is DSAPI?

The Domino Web Server Application Programming Interface (DSAPI) is a C API that lets you write your own extensions to the Domino Web Server. DSAPI extensions, or filters, are notified whenever a particular event occurs during the processing of a request.
I've written few articles about DSAPI before and now it is time to publish my work/project on github. You can find it here: domino-dsapi-handler. I did not have time to make a documentation for it (and I'm not sure I will do it, without funding), but all sources are there.

In this post I will highlight most important things you need to know if you are going to build your own DSAPI filter.

Initialization

Domino calls the initialization function when the filter is loaded. The filter is loaded when the Domino HTTP server task is started or when the HTTP task is restarted with the Domino console command 'tell http restart'.
 DLLEXPORT unsigned int FilterInit(FilterInitData* filterInitData) {  
  // init events you want to handle  
  filterInitData->eventFlags = kFilterRewriteURL | kFilterResponse | kFilterTranslateRequest;  
  // another code  
  return kFilterHandledRequest;  
 } // end FilterInit  

Terminate filter

The filter may also define a termination entry point. Domino will call this function whenever the filter is about to be unloaded. The filter can use this function to clean up resources it allocated
 DLLEXPORT unsigned int TerminateFilter(unsigned int reserved) {  
  return kFilterHandledEvent;  
 }     // end TerminateFilter  

HttpFilterProc

The Event Notification function does the actual work of the filter. Domino calls the Event Notification function whenever a particular event occurs during the processing of an http request. When Domino calls the filter's Event Notification function it passes information about the request and the event being processed. On each call the filter can decide to handle the event, with or without an error return, or decline to handle the event.
 DLLEXPORT unsigned int HttpFilterProc(FilterContext* context, unsigned int eventType, void* eventData) {  
      switch (eventType) {  
           case kFilterTranslateRequest:  
                return QueryRewrite(context, (FilterMapURL *) eventData);  
           case kFilterRewriteURL:  
                return RewriteURL(context, (FilterMapURL *) eventData);  
           case kFilterResponse:  
                return ResponseHeaders(context, (FilterResponseHeaders *) eventData);  
           default:  
                return kFilterNotHandled;  
      }  
 }     // end HttpFilterProc  

The rest of logic you can read yourself in SEOUrlHandler.c file. I've added information about how to compile DLL in readme on github. However If you have any question regarding some details let me know either via email or as a comment to this post. I will be glad to help.

Related topics
Rewriting URL in Domino using DSAPI
Solution for Lotus Domino to the trailing slash problem
Replacement for DSAPI in Java/XPages

Used materials
Domino Web Server Application Interface (DSAPI)

Monday, January 04, 2016

Format datetime object in Lotus Script

Sometimes datetime output become tricky in Lotus Notes.

F.x. imagine you have code like this and you have german or any another locale on user's PC.
 Set dt = New NotesDateTime("")  
 Call dt.SetNow  
 msgbox Format$(dt.LSLocalTime, "dddd, dd. MMMM yyyy")  

Out would be
Tuesday, 22. December 2015

But what if you want output in german i.e.?
22. Dezember 2015

In such case you may want to use LS2J approach to display it properly to user

Below you will find a solution that either allow to set locale or use default locale.
 Option Public  
 Option Declare  
 UseLSX "*javacon"  
 Sub Initialize   
  On Error GoTo errhandler  
  Dim jSession As New JavaSession  
  Dim jCalendarClass As Javaclass, jLocaleClass As JavaClass, jSimpleDateFormatClass As JavaClass
  Dim jCalendar As Javaobject, jLocale As Javaobject, jSDF As JavaObject, jDate As Javaobject  
  Dim jError As JavaError  
  Dim dt As New NotesDateTime("")  
  Call dt.SetNow  
  'in order to initiate date - we have to use Calendar object  
  Set jCalendarClass = jSession.GetClass("java.util.Calendar")  
  Set jCalendar = jCalendarClass.getInstance()  
  Call jCalendar.set(Year(dt.DateOnly), month(dt.DateOnly) - 1, day(dt.DateOnly))  
  'initialize date object  
  Set jDate = jCalendar.getTime()  
  'IMPORTANT  
  'create locale (here we specify langauge/country code)   
  Set jLocaleClass = jSession.GetClass("java.util.Locale")  
  Set jLocale = jLocaleClass.CreateObject("(Ljava/lang/String;Ljava/lang/String;)V", "de", "DE")  
  'also you can use local settings, if you need that - enable line below  
  'Set jLocale = jLocaleClass.getDefault()  
  'output format  
  Set jSimpleDateFormatClass = jSession.GetClass("java.text.SimpleDateFormat")  
  Set jSDF = jSimpleDateFormatClass.CreateObject("(Ljava/lang/String;Ljava/util/Locale;)V", "dd. MMMM yyyy", jLocale)  
  'result  
  MsgBox jSDF.format(jDate)  
  done:  
  Exit Sub  
  errhandler:  
  Set jError = jSession.GetLastJavaError()  
  MsgBox "JavaError was " & jError.errorMsg  
  jSession.ClearJavaError  
  Resume done  
 End Sub  

Related topics:
Locale settings for date and time in IBM Domino and Notes

Tuesday, October 27, 2015

Locale settings for date and time in IBM Domino and Notes

Recently we setup 2 new IBM Domino servers and today I found an issue related to how we display time in our application. The 12-hours format was used (with AM or PM). I've checked OS date settings and they were right so I started to google and found out that in order to change locale settings to 24-hours you have either update notes.ini with a ClockType variable or change register.

I went with notes.ini (feel more safe with it). Below few variables that control date/time format output.
 DateOrder=YMD  
 DateSeparator=.  
 TimeSeparator=:  
 CLOCKTYPE=24_HOUR  

It is also possible for windows OS to change register (but I personally do not like that).
 HKEY_USERS\.DEFAULT\Control Panel\International\iDate  
 HKEY_USERS\.DEFAULT\Control Panel\International\iTime  
 HKEY_CURRENT_USER\Control Panel\International\iDate  
 HKEY_CURRENT_USER\Control Panel\International\iTime  

You may find more information about it in article Timely information in NOTES.INI

Related topics:
Format datetime object in Lotus Script

Monday, October 19, 2015

Using preceding-sibling and following-sibling in xpath

In this article I will show few examples about how to use following-sibling and preceding-sibling

Our XML example we are going to use.
 <div id="cities">  
 <country>France</country>  
   <city>Paris</city>  
   <country>UK</country>  
   <city>London</city>  
   <city>Manchester</city>  
   <city>Liverpool</city>  
   <country>Denmark</country>  
   <city>Copenhagen</city>  
   <country>Ukraine</country>  
   <city>Kiev</city>  
   <city>Odessa</city>  
 </div>  

Taking all city elements after element UK

 /div/country[.='UK']/following-sibling::city  
 <city>London</city>  
 <city>Manchester</city>  
 <city>Liverpool</city>  
 <city>Copenhagen</city>  
 <city>Kiev</city>  
 <city>Odessa</city>  

Taking all city elements before element Denmark

 /div/country[.='Denmark']/preceding-sibling::city  
 <city>Paris</city>  
 <city>London</city>  
 <city>Manchester</city>  
 <city>Liverpool</city>  

Let's increase difficulty little bit and try to use preceding-sibling and following-sibling in the brackets []

Taking all city elements following till first country is UK

 /div/city[following-sibling::country='Denmark']  
 <city>Paris</city>  
 <city>London</city>  
 <city>Manchester</city>  
 <city>Liverpool</city>  

Taking all city elements from bottom till first country is Denmark

 /div/city[preceding-sibling::country='Denmark']  
 <city>Copenhagen</city>  
 <city>Kiev</city>  
 <city>Odessa</city>  

Let's increase difficulty even more and start using both preceding-sibling and following-sibling in one xpath.

Taking all city elements between two elements

In this example I'm going to get cities after UK and before Ukraine.
 /div/city[preceding-sibling::country='UK' and following-sibling::country='Ukraine']  
 <city>London</city>  
 <city>Manchester</city>  
 <city>Liverpool</city>  
 <city>Copenhagen</city>  

Wednesday, October 14, 2015

Setup Play Framework and TypeSafe on centOS

I'm going to setup simple project based on Play Framework together with Cassandra on two centOS servers.

I'm going to do 3 steps during that process:
  1. Install Java
  2. Install Typesafe activator
  3. Create test project.

Installing Java

//1. go to opt folder
cd /opt

//2. download java
wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u60-b27/jdk-8u60-linux-x64.tar.gz"

//3. extract java archive
tar xzf jdk-8u60-linux-x64.tar.gz

//4. installing java
cd /opt/jdk1.8.0_60/
alternatives --install /usr/bin/java java /opt/jdk1.8.0_60/bin/java 2
alternatives --config java

//5. recommended options: setup javac and jar
alternatives --install /usr/bin/jar jar /opt/jdk1.8.0_60/bin/jar 2
alternatives --install /usr/bin/javac javac /opt/jdk1.8.0_60/bin/javac 2
alternatives --set jar /opt/jdk1.8.0_60/bin/jar
alternatives --set javac /opt/jdk1.8.0_60/bin/javac

//6. setup variables so we can access java from everywhere
export JAVA_HOME=/opt/jdk1.8.0_60
export JRE_HOME=/opt/jdk1.8.0_60/jre
export PATH=$PATH:/opt/jdk1.8.0_60/bin:/opt/jdk1.8.0_60/jre/bin

//7. checking java version
java -version

//8. delete java archive
rm jdk-8u60-linux-x64.tar.gz

Installing Play Framework / TypeSafe


Example is about current version, which is 1.3.6
//1. go to tmp folder and download typesafe activator
cd /tmp
wget https://downloads.typesafe.com/typesafe-activator/1.3.6/typesafe-activator-1.3.6.zip

//2. unzip and move to opt folder
unzip typesafe-activator-1.3.6.zip
mv activator-dist-1.3.6 /opt

//3. delete zip file, we do not need it anymore
rm typesafe-activator-1.3.6.zip

//4. create soft symbolic link from /opt/activator-dist-1.3.6/activator to /usr/local/sbin/activator
ln -s /opt/activator-dist-1.3.6/activator /usr/local/sbin/activator

//5. set variables so we can use activator from everywhere
export PATH=/usr/local/sbin/activator:$PATH

Create helloworld project


Time to create our first project. Play Framework provides many templates, we are going to use play-java (it has already web interface and some code, so we can discover it).
//1. create folder www in /var (we are going to keep projects there).
cd /var
mkdir www
cd www

//2. have a look on current templates
activator list-templates

//3. create a new project based on play-java template
activator new helloworld play-java

//4. go into newly created project and run it
cd helloworld
activator run

If activator run properly, you should see something like this:


Now you are ready to open project in browser. Type 127.0.0.1:900 and boooom, we have it ready!


I'm going to play with centOS little bit more (before I start to look on code). I already have some minor issues I want to optimise.