Wednesday, 14 March 2012

1st LotusSquash of 2012, Deventer, 29 march



LotusSquash: playing squash with other Lotus geeks - a friendly training session open for players of all levels and Lotus geeks of all levels - a quarterly event organised around the country.
Non Lotus geeks are welcome too ;-)

It is also an alternative, nice and sporty way of networking and chatting about IBM Lotus stuff. Watch for updates via twitter #lotussquash.
Let us know if you want to join via twitter or post a comment here.

Next LotusSquash:
Date: thursday 29 march
Time: 19:00 hrs
Where: Sportbedrijf Deventer
Address: Piet van Donkplein 1, 7422LW Deventer (NL)
Organised by: Clear IT Consulting

Wednesday, 21 December 2011

agent.RunOnServer - cannot create automated object

The other day I had to make some changes to process an incoming html page containing client data from a paid service.
To limit the access to this service, it can only be called from the domino servers. And is currently done  through a scheduled agent.
But now some users also need to be able to call the service on demand. To keep the restriction of calling only from a domino server I created a lotusscript button that runs the process via an agent.RunOnServer call.
This agent is reusing the code from the scheduled agent and does a CreateObject of the MSXML service to handle the incoming html/xml.
It constantly failed with an error message "cannot create automated object" on the console.
After some searching and a tip by Dennis van Remortel I found a technote (21088529) through the LDD forum that explained this error and how to work around it. It notes it affects releases 5, 6 & 6.5, but appearantly it is still valid for 8.5.x as well!!

The workaround is to create another agent that is called from the client button with the RunOnServer method an to have this agent call the original agent with the Run method.

Tuesday, 22 November 2011

XSnippets - do not reinvent the wheel


A gem for code sharing was launched about a month ago on OpenNTF, XSnippets
. It contains small re-usable chunks of code related to Xpages.
The UI is very simple and userfriendly and finding that codefragment you need in your next project should not be a problem. The code snippets are even colour coded.

Hopefully all those great contributors of code to the Notes Domino community will gradually copy their pieces of code to this site. That would make XSnippets the place to look first and avoid reinventing the wheel.

Monday, 10 October 2011

Xpages Internationalisation

Working in Europe for a multinational, providing a multi-lingual website is not an option, it is a must. So the option for internationalisation in Xpages is very welcome.
The standard xpages localisation option (in the application properties) creates a properties file per specified language per custom control/xpage. Works great, but it does create a lot of maintenance work if things needs changing afterwards or when you add a language.
There is another option available which is not as automated like the xpages localization, but in the long run will probably turn out to be more flexible when doing maintenance or adding an extra language.
Here is how it works:

- For every language create a properties file, a flat text file with the extension .properties and make them available to the application through the "file resources". For ease of use name these files something like english.properties, dutch.properties, etc. In the properties files add name-value pairs separated by the equals sign (=) for labels, buttons etc. in your applocation that you want translated.
     login_text=Login
     logout_text=Logout
     menu_text=Menu
     ....

- In a custom control that loads on every page in the application, e.g. an initialisation custom control, in the resources properties add a resource bundle, name it something like "lang" and compute the location to the desired language properties file, e.g. using the browser language setting or for testing as simple as below..
     return "/dutch.properties";

- Next go through all the xpages and custom controls and change the fixed text of labels, buttons, etc. by a value from the properties file set in the resources.
     lang.login_text

- After setting all the necessary entries in the properties file for the default language, create the file resources (copy) for the other languages. To spot not translated labels in the application, you can prefix them with the target language.
     login_text=[EN]Login
     logout_text=[EN]Logout
     menu_text=[EN]Menu
     ....

This process is best done at the end of the development phase of a project and work with a default language until than.

Used sources:
xpages101.net

LND Application dvlp wiki

Wednesday, 28 September 2011

Keep view position between (x)pages

By default xpages doesnot keep the position of the view (pageno.) when going to another page. So when you go back to the view page from another page, the view will display from the first entry (and page) again. Not very userfriendly if you had just left it from page 3.
You will have to make the view page remember its position by storing the number of the first row on the page in a scoped variable.
In the "beforeRenderResponse" event add the following code:

   var c = getComponent("viewPanel");
   if (c) {
       sessionScope.put("viewFirst"+view.getPageName()
, c.first);
   }
"viewPanel" is the id of your view control of course.
And in the view control's All properties - first - add the code:

   var vwFirst = sessionScope.get("viewFirst"+view.getPageName());
   if (vwFirst) return vwFirst;

This will also work when displaying data tables through a repeat control.

Used sources:
xpageswiki.com 

 

Monday, 19 September 2011

LotusSquash - 29 september 2011 postponed to 27 october


LotusSquash: playing squash with other Lotus geeks - a friendly training session open for players of all levels and Lotus geeks of all levels - a quarterly event organised around the country.
Non Lotus geeks are welcome too ;-)

It is also an alternative, nice and sporty way of networking and chatting about IBM Lotus stuff. Watch for updates via twitter #lotussquash.
Let us know if you want to join via twitter or post a comment here.

Next LotusSquash:
Date: thursday 29 september postponed to 27 oktober
Time: 19:00 hrs
Where: Squash & Cardiofit Centrum Zwolle
Address: Dobbe 69, 8032 JX Zwolle (NL)
Organised by: TooConnect Software Solutions

Tuesday, 13 September 2011

Final version of DbLookupArray & DbColumnArray

Time to post the final version (I think) of the DbLookupArray and DbColumnArray functions, which I started blogging about a couple of months ago.
To date these functions only worked on the current database. So now I have added the option to also execute on another database on another server (beware that proper authorisation is in place).
The server will only be used when a database name is provided. In both cases, if omitted, the current server/database is used.
And the final added option is to be able to request the results back in a sorted order.

DbLookup
 /**  
  * Returns @DbLookup results as array and allows for cache  
  * @param server -name of the server the database is on (only used if dbname not empty, if omitted, the server of the current database is used)  
  * @param dbname -name of the database (if omitted the current database is used)  
  * @param cache -"cache" for using cache, empty or anything for nocache  
  * @param unique -"unique" for returning only unique values, empty or anything for all results  
  * @param sortit -"sort" for returning the values sorted alphabetically  
  * @param viewname -name of the view  
  * @param keyname -key value to use in lookup  
  * @param field -field name in the document or column number to retrieve  
  * @return array with requested results  
  */  
 function DbLookupArray(server, dbname, cache, unique, sortit, viewname, keyname, field) {  
      var cachekey = "dblookup_"+dbname+"_"+@ReplaceSubstring(viewname," ","_")+"_"+@ReplaceSubstring(keyname," ","_")+"-"+@ReplaceSubstring(field," ","_");  
      // if cache is specified, try to retrieve the cache from the sessionscope  
      if (cache.equalsIgnoreCase('cache')) {   
           var result = sessionScope.get(cachekey);  
      }  
      // if the result is empty, no cache was available or not requested,  
      //  do the dblookup, convert to array if not, cache it when requested  
      if (!result) {  
           // determine database to run against  
           var db = "";  
           if (!dbname.equals("")) { // if a database name is passed, build server, dbname array  
                if (server.equals("")){  
                     db = new Array(@DbName()[0],dbname); // no server specified, use server of current database  
                } else {  
                     db = new Array(server, dbname)  
                }   
           }  
           var result = @DbLookup(db, viewname, keyname, field);  
           if (result && unique.equalsIgnoreCase("unique")) result = @Unique(result);  
           if (result && typeof result == "string") result = new Array(result);  
           if (result && sortit.equalsIgnoreCase("sort")) result.sort();  
           if (result && cache.equalsIgnoreCase('cache')) sessionScope.put(cachekey,result);  
      }  
      return result;  
 }  
DbColumn
 /**  
  * Returns @DbColumn results as array and allows for cache  
  * @param server -name of the server the database is on (only used if dbname not empty, if omitted, the server of the current database is used)  
  * @param dbname -name of the database (if omitted the current database is used)  
  * @param cache -"cache" for using cache, empty or anything for nocache  
  * @param unique -"unique" for returning only unique values, empty or anything for all results  
  * @param sortit -"sort" for returning the values sorted alphabetically  
  * @param viewname -name of the view   
  * @param column -column number to retrieve  
  * @return array with requested results  
  */  
 function DbColumnArray(server, dbname, cache, unique, sortit, viewname, column) {  
      var cachekey = "dbcolumn_"+dbname+"_"+@ReplaceSubstring(viewname," ","_")+"_"+@ReplaceSubstring(column," ","_");  
      // if cache is specified, try to retrieve the cache from the sessionscope  
      if (cache.equalsIgnoreCase('cache')) {   
           var result = sessionScope.get(cachekey);  
      }  
      // if the result is empty, no cache was available or not requested,  
      //  do the dbcolumn, convert to array if not, cache it when requested  
      if (!result) {  
           // determine database to run against  
           var db = "";  
           if (!dbname.equals("")) { // if a database name is passed, build server, dbname array  
                if (server.equals("")){  
                     db = new Array(@DbName()[0],dbname); // no server specified, use server of current database  
                } else {  
                     db = new Array(server, dbname)  
                }   
           }  
           var result = @DbColumn(db, viewname, column);  
           if (result && unique.equalsIgnoreCase("unique")) result = @Unique(result);  
           if (result && typeof result == "string") result = new Array(result);  
           if (result && sortit.equalsIgnoreCase("sort")) result.sort();  
           if (result && cache.equalsIgnoreCase('cache')) sessionScope.put(cachekey,result);  
      }       
      return result;  
 }  

Used sources:
xpageswiki.com