Friday, January 08, 2016

Typical mistakes with String in Java

Just few typical mistakes developers do when dealing with Strings. It's common stuff and everybody knows that, but for some reasons I still find such things (even written by myself :-)).

1. Checking empty string


In old days (version 1.5 and lower) we used String.equal(""), but 1.6 brought us String.IsEmpty which is better and faster.
 // wrong/slow  
 if (name.equals("")) {  
 // correct/fast
 if (name.isEmpty()) {

2. Concatenation


Method String.concat creates new String object, it's OK to use it when you do operation only once, otherwise use operator + += operators (see below why).
 String s = "Hello ".concat("new").concat(" world!"); // "Hello new world!"  
Using operators + and +=, they do not use String.concat method but StringBuilder and it's important to know what it means to us.
 String s = "Hello " + "new" + " world!"; // "Hello new world!"
What actually happens when you use + operator is StringBuilder used:
 String s = new StringBuilder().append("Hello ").append("new").append(" world!").toString(); // "Hello new world!"
So conclusion - it's ok to use concat if you do one time operation, for any other situation I would recommend to use + or +=.

3. String Formatting


Very often in order to format string people either concatenate the string to achieve result or do replace or invent something else. I do it as well sometimes (what a shame!). Instead we should use String.format method to do that.
 int n = 10;  
 // wrong  
 String s = "I have " + Integer.toString(10) + " books";  
 // wrong  
 String s = "I have #num books".replace("#num", Integer.toString(10));  
 // correct  
 Strig s = String.format("I have %d books", n);  

I would be glad to hear other typical mistakes we do with String object! So please share your experience.

Thursday, January 07, 2016

SOAP and passing session

Here is an example how to pass session using SOAP envelope approach. I was starlight with it for some time.

That is why people use REST our days :) and not SOAP approach.

   // Create SOAP Connection  
   SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();  
   SOAPConnection soapConnection = soapConnectionFactory.createConnection();  
   // connect to webserivce
   SOAPMessage soapResponse = soapConnection.call(connect(username, password), url);

   // read cookie from response and use it when send another requests
   MimeHeaders session = soapResponse.getMimeHeaders(); 
   String sesisonCookie = session.getHeader("Set-Cookie")[0];

   SOAPMessage soapResponse2 = soapConnection.call(customerGetAll(sesisonCookie), url);
   soapConnection.close();

Here is how we add cookie to soap request

   SOAPBody soapBody = envelope.getBody();
   SOAPElement soapBodyElem = soapBody.addChildElement("Customer_GetAll", "m");
   soapMessage.getMimeHeaders().addHeader("Cookie", sesisonCookie);
   soapMessage.saveChanges();

Wednesday, January 06, 2016

Java web-consumer in Domino and cookie session

Recently I've faced with few mistake that drain hours from me. I had to make integration with web-serivce. I imported WSDL file and got java classes generated, than I according to documentation I checked connect method with credentials...
Error connecting to 'endpoint' on port '443', SSL invalid certificate, may need to cross-certify
Spend some time and found very detailed answer on stackoverflow: Create cross certificate for Domino Java agent?

Tried connect method again - it worked! Gonna be easy task now (I thought). However nothing else except connect method worked. All other method of consumer either did nothing or returned null to me. I was confused, spend few hours and than contacted web-service provider, they were not familiar with Java and provided me example in PHP that worked as expected.

My issue was I had to set SESSION_MAINTAIN_PROPERTY to true for my proxy object.

 SecretServiceLocator service = new SecretServiceLocator();  
 SecretPortType port = service.getSecretPort();  
 ((javax.xml.rpc.Stub)port)._setProperty(javax.xml.rpc.Stub.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);  

SESSION_MAINTAIN_PROPERTY

Standard property: This boolean property is used by a service client to indicate whether or not it wants to participate in a session with a service endpoint. If this property is set to true, the service client indicates that it wants the session to be maintained. If set to false, the session is not maintained. The default value for this property is false.
Once I set session maintain to true - everything started to work.

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