XPages gotcha: mode=”concat” in your themes

Suppose you have an XPage with a repeat control on it to show a list of documents. In the repeat you generate an <xp:button> for every document. Based on the status of the document you decide to give the button a different color, so you make the styleClass property of the button computed:

<xp:repeat
  id="repeat1"
  rows="30"
  var="entry">

  <xp:this.value><![CDATA[#{javascript:
    print("computing repeat value");
    return ["style1", "style2"];
  }]]></xp:this.value>

    <xp:button
      value="Label"
      id="button">
        <xp:this.styleClass><![CDATA[#{javascript:
          print("computing styleClass:");
          print( typeof entry);
          return entry
        }]]></xp:this.styleClass>
    </xp:button>

</xp:repeat>

That’s (roughly) the code you’d have to write. And guess what: it all works. Everyone’s happy!

Screen Shot 2014-08-28 at 15.35.03So you decide to enhance the looks of your application and include Bootstrap. Bootstrap requires the btn class on all buttons for styling. Being an expert XPage developer you create a theme for your application, add the Bootstrap CSS file and add a control definition to give all buttons that btn class:

<control>
  <name>Button.Command</name>
  <property mode="concat">
     <name>styleClass</name>
    <value>btn</value>
  </property>
</control>

You reload the page, thinking you’re done and guess what: errors!

That’s roughly what I’ve been looking at today and at some point thinking I lost my sanity.

The print() statements in the code above were added by me to show the order of execution. Without the <control> definition in the theme I saw this on the server console:

> computing repeat value
> computing styleClass:
> string
> computing styleClass:
> string

Exactly what I expected! But… after adding the <control> definition I saw this:

> computing styleClass:
> undefined
> computing styleClass:
> undefined
> computing repeat value

Notice the subtle, yet very important, difference in the order of computing: with the <control> definition the styleClass is computed before (!) the repeat value, making it impossible to let the button style depend on the repeat value. This behaviour is caused by the mode=”concat” part, that should combine the value of the styleClass with the one set in the theme.

The Bootstrap4XPages plugin has that same <control> definition in it, so if you’re using that you will likely run into this some day.

The solution I came up with for now is to add a new <control> definition to the theme, setting it to override any inherited settings and setting the mode to the default (‘override’). Set the themeId to the new <control> name and it all works again:

<control>
  <name>Button.NoConcat</name>
  <property>
  <name>styleClass</name>
    <value>btn</value>
  </property>
</control>

and:

<xp:button value="Label" themeId="Button.NoConcat"></xp:button>

I have no idea why it behaves this way and would have never guessed that a <control> breaks anything but the UI in my app. If anyone can share some light on this: please do!

Getting HTML from any RichText item

HTML_logoLast week I blogged about sending the contents of a RichText field (including images and attachments) as an HTML mail. Today’s task was related: get the contents of a RichText item as HTML, knowing that the contents can be stored in the item as either MIME or standard RichText.

With the wrapDocument() function I showed you last week you can easily get MIME contents as HTML. It turns out that with some small changes you can use the same method to let Domino convert ‘standard’ RichText into HTML. You probably saw this in action already: create a document with RichText in the Notes client and edit it on the web. What’s new is that this method allows you to do it programmatically.

The trick is in the DominoRichTextItem class: it has two constructors to create it: using either a MIMEEntity or by giving it a RichTextItem. That’s all the info I needed to update my previous function:

/*
 * Wraps a lotus.domino.Document as a com.ibx.xsp.model.domino.wrapped.DominoDocument, including a RichText item
 *
 * @param doc document to be wrapped
 *
 * @param richTextItemName name of the rich text item containing standard RichText or MIME  contents that need to be wrapped
 */
private static DominoDocument wrapDocument(final Document doc, final String richTextItemName) throws NotesException {</code>

  DominoDocument wrappedDoc = null;

  Database db = doc.getParentDatabase();

  //disable MIME to RichText conversion
  db.getParent().setConvertMIME(false);

  //wrap the lotus.domino.Document as a lotus.domino.DominoDocument
  //see http://public.dhe.ibm.com/software/dw/lotus/Domino-Designer/JavaDocs/DesignerAPIs/com/ibm/xsp/model/domino/wrapped/DominoDocument.html
  wrappedDoc = DominoDocument.wrap(doc.getParentDatabase().getFilePath(), doc, null, null, false, null, null);

  //see http://public.dhe.ibm.com/software/dw/lotus/Domino-Designer/JavaDocs/DesignerAPIs/com/ibm/xsp/model/domino/wrapped/DominoRichTextItem.html
  DominoRichTextItem drti = null;

  Item itemRT = doc.getFirstItem(richTextItemName);

  if (null != itemRT) {

    if (itemRT.getType() == Item.RICHTEXT) {

      //create a DominoRichTextItem from the RichTextItem
      RichTextItem rt = (RichTextItem) itemRT;
      drti = new DominoRichTextItem(wrappedDoc, rt);

    } else if (itemRT.getType() == Item.MIME_PART) {

      //create a DominoRichTextItem from the Rich Text item that contains MIME
      MIMEEntity rtAsMime = doc.getMIMEEntity(richTextItemName);
      drti = new DominoRichTextItem(wrappedDoc, rtAsMime, richTextItemName);

    }
  }

  wrappedDoc.setRichTextItem(richTextItemName, drti);

  return wrappedDoc;

}

Using this function you can wrap any document and get the HTML from a RichText item:

View view = db.getView("someview");
Document doc = view.getFirstDocument();

DominoDocument ddoc = wrapDocument(doc, "Body");
DominoRichTextItem drti = ddoc.getRichTextItem("Body");

String html = drti.getHTML();
System.out.println(html);

Create HTML emails from RichText fields with embedded images and attachments

If you want to send formatted (HTML) emails from Domino you have a couple of options.

Starting with version 9, there’s a simple action that allows you to send HTML mail by just configuring some options. You can also use Tony McGuckin’s emailBean snippet to send an HTML mail from an XPage directly, including embedded images and/or attachments. And there’s also the SSJS snippet I wrote to send an email from any backend SSJS script.

Unfortunately, none of these could do what I wanted: send an HTML mail with the contents based on a RichText field (stored as MIME), including any embedded images. With the standard photo upload option available in the XPage embedded CKEditor it’s real easy to add embedded images. Tony’s emailBean snippet came close, but it requires a DominoDocument object as a parameter and thus only works when used directly on the XPage where you create the content. In my case, I either wanted to pick a set of documents to be send or use a scheduled agent to do that.

So I investigated how I could create a DominoDocument from a standard document object.

First stop: this snippet that uses the .wrap() function of the DominoDocument object to wrap a standard document. That worked, but didn’t add the RichText fields to the wrapped document. So I dived deeper and found the JavaDocs for the DominoDocument here. Turns out that there is a getRichTextItem() function that returns a DominoRichTextItem. That object, the DominoRichTextItem, is also used in the emailBean code. The JavaDocs for the DominoRichTextItem describe that you can use a MIMEEntity to create one. The newly created DominoRichTextItem can then be attached to the wrapped DominoDocument.

Here’s the XSnippet I just added to wrap a document, including MIME.

For this to work you need to enable the “Store contents as HTML and MIME” option of the RichText field that you’re storing the HTMl in. When you’ve done that you can use the emailBean to create and send the email:

function sendEmailFromRichText() {
  DominoDocument wrappedDoc = wrapDocument(docMail, "body");

  //now we can pass the wrapped document, including the MIME contents to the EmailBean
  EmailBean emailBean = new  EmailBean();

  emailBean.setSendTo("someone@somewhere.com");
  emailBean.setSubject("Here's a mail");

  emailBean.setDocument(wrappedDoc);
  emailBean.setFieldName("body");

  emailBean.setBannerHTML("<p>Hi, "  + sendTo + "</p>");
  emailBean.setFooterHTML("<p>Kind regards, "  + senderName + "</p>");

  emailBean.setSenderEmail("i@dontexist.com");
  emailBean.setSenderName("Name of the sender");

  emailBean.send();
}

/*
 * Wraps a lotus.domino.Document as a com.ibx.xsp.model.domino.wrapped.DominoDocument, including the RichText item
 * 
 * @param doc document to be wrapped
 * @param richTextItemName name of the rich text item containing the MIME contents that need to be wrapped too
 */
private static DominoDocument wrapDocument( final Document doc, final String richTextItemName ) throws NotesException {
     
  DominoDocument wrappedDoc = null;
       
  Database db = doc.getParentDatabase();
     
  //disable MIME to RichText conversion
  db.getParent().setConvertMIME(false) ;
 
  //wrap the lotus.domino.Document as a lotus.domino.DominoDocument
  //see http://public.dhe.ibm.com/software/dw/lotus/Domino-Designer/JavaDocs/DesignerAPIs/com/ibm/xsp/model/domino/wrapped/DominoDocument.html
  wrappedDoc = DominoDocument.wrap(doc.getParentDatabase().getFilePath(), doc, null, null, false, null, null);
     
  //get the RichText field containing the MIME contents as MIME
  MIMEEntity rtAsMime = doc.getMIMEEntity("mailingBody");
     
  //add the RichText field to the wrapped document
  //see http://public.dhe.ibm.com/software/dw/lotus/Domino-Designer/JavaDocs/DesignerAPIs/com/ibm/xsp/model/domino/wrapped/DominoRichTextItem.html
  DominoRichTextItem drti = new DominoRichTextItem(wrappedDoc, rtAsMime, richTextItemName);
     
  wrappedDoc.setRichTextItem(richTextItemName, drti);
     
  return wrappedDoc;
     
}

Considering a Domino upgrade to 9.0.1 FP1 or 9.0.2? Beware of custom Java security policies

If you have custom Java security policies in place on your Domino server (either through a modified java.policy or java.pol file) you might want to read this before you upgrade.

When I want to change to Java security policy on a Domino server I create a java.pol file in the jvm/lib/security folder and add everything I want. That folder also contains the default java.policy file, but you don’t want to add your changes in there: that file tends to get overwritten when doing a server upgrade.

Yesterday I got a report from a customer of an error message they received when using one of my applications. That error message (java.lang.reflect.InvocationTargetException) sounded like something was wrong with the Java security policy in place. I checked and was right: the java.pol file was gone! They recently upgraded from 9.0.1 to 9.0.1FP1 so I suspected that to have caused it. Strange, because with previous upgrades I’m sure that the file wasn’t touched.

So I tested it myself: I monitored the jvm/lib/security folder while installing the fix pack on a 9.0.1 (Windows 32 bit) server. What I saw is that during the install Windows explorer automatically redirects me from that folder to the Domino program folder, so it looks like the incremental installer completely deletes and reinstalls that folder.

Browsing through the fix list database I found this: SPR #KLYH9FNKLW: the JVM is upgraded in 9.0.1FP1 to 1.6 SR15FP1. That’s what probably caused this changed behaviour. That fix is also in 9.0.2 (not released yet) so I guess you’ll see the same behaviour when upgrading to that version. Just something to be aware of…

XPages Debug Toolbar – now as a plugin

In preparation for the session with Phil Riand on Bootstrap4XPages last week at IBM Connect (slides) I’ve been doing quite some work on the Bootstrap4XPages plugin. That got me pretty good up to speed with the subject of OSGi plugin development, so I decided to take another shot at a thing that had been on my todo list for way too long: create a plugin version of my XPages Debug Toolbar.

So I watched the NotesIn9 episode by Tim Tripcony on creating a global custom control again, applied what he described to the toolbar custom control and, to my surprise, it worked! As of last week the XPages Debug Toolbar version 4 can be downloaded from OpenNTF and installed server wide. That means easy access to it from all your applications and no need anymore to more copying all those design elements manually.
This is the Debug Toolbar v4
It turned out that the plugin version also solves one of the biggest annoyances of the toolbar: because of the XPages classloader architecture, you needed to “Clean” your applications way too often to deal with ClassCastExceptions (DebugToolbar incompatible with DebugToolbar).

Included also in release 4:

  • The number of toolbar messages and errors are now also shown when the toolbar is collapsed.
  • Easy access to global objects from the Inspector tab (view, database, facesContext, …).
  • Couple of minor UI changes. Or, more popular phrased, “Optimised for Retina screens!”.
  • Scope variables that use a number as a key (yes, that is allowed) are now correctly shown.
  • Built-in XPages Request Processing Lifecycle explorer (written by Tony McGuckin)
  • You can now dump a list of all design note signers.
  • Because it’s now a plugin, you can also log messages from the beforePageLoad event.
  • And as always: “various performance and scalability enhancements”. No, really.

I need to shout a big “THANK YOU” here to Christian Guedemann from Webgate Consulting. He helped me to optimise the code and refactored a huge chunk of SSJS code to Java. Great job and thanks!

Unfortunately this release has an issue that will be apparent the minute you install it: it shows up twice in the Designer controls palette. At IBM Connect last week we tried to solve that with some IBM help (thanks Tony McGuckin!),Look, it's a bug! but it looks like this is an issue in the Designer code that will hopefully be solved in a future version (that’s a hint if anyone from the Designer developer team reads this :-). Apart from the double palette entry, I’ve seen no other drawbacks.

Distributing components like this through an OSGi plugin is definitely the way forward and comes with a lot of advantages, so I would highly encourage you to install this version! If you want to try it out first, check out the demo.

Improve your Domino SSL configuration, make your server more secure

Recently, Stephen Wissel tweeted a link to the Qualys SSL Labs SSL Server Test. That site allows you to enter the URL of an (internet facing) server that has SSL enabled and can then perform a deep analysis of the SSL configuration of that server. You may or may not know that Secure Sockets Layer comes in different flavours: v2, v3, TLS (Transport Layer Security; SSL’s successor), and more. Also, an SSL configuration can support various Cipher Suites (some of which are less secure than other) or can be vulnerable for things like the BEAST attack. So it’s not like SSL is on or off: there’s a bit more nuance to that.

Most people reading this will probably now run off to the SSL Server Test and enter the URL to their IBM Domino server. So did I the first time I read about it. Go ahead, I’ll wait…

I guess you were expecting a straight A-grade, but were suprised (or shocked) you didn’t. My first score (on a vanilla Domino server) was an F. That shocked me, so I did a bit of research. I found out that just like in school you don’t get an A for free.

So what can you do to get a better score on a Domino server? Here are two of my personal recommendations:

Disable insecure negotiation

Described here and here this allows for a man-in-the-middle attack and is enabled by default in Domino. Easy fix: add SSL_DISABLE_RENEGOTIATE=1 to your notes.ini.

Disable older, less secury ciphers

Recent browsers support more secure ciphers (AES), but Domino by default still allows older, weaker ciphers (DES, RC4). You can configure what ciphers Domino should support:

  • Open your names.nsf and open the server or internet site document for your server/ site.
  • Go to the Security tab and click Edit
  • In the SSL security section click the Modify button in the SSL ciphers field
  • Disable the SSL ciphers you don’t want to allow anymore. The only two I have enabled are: RC4 encryption with 128-bit key and SHA-1 MAC AES encryption with 256-bit key. There is some debate on if you should enable RC4. I have enabled it, but leave the choice up to you.

Restart your server and run the SSL test again. That looks a lot better, doesn’t it? Now you can go to bed feeling a bit safer.

Disclaimer: I’m no security expert, but after performing some research I think you’re safer with these easy changes (and so do the Qualys SSL Labs). Please correct me if I’m wrong. Of course I won’t take any responsibility for any of these recommendations.

Import Excel files and calculations with POI 4 XPages

Adding an export to Excel used to be a pain in the old days. But now, with XPages and the highly recommended POI4XPages library*, that has gotten really easy and is a feature I can just throw in to any project. And yes I know: spreadsheets… But fact is that a lot of the people I work with are still very much Excel oriented: so why not service them?

I had a requirement the past week to add some calculations on a generated Excel file: creating totals and hiding cells based on others. I thought that was dead easy: add some formulas to the template and done. Exported some data and… nothing. The formulas were there in the spreadsheet, but it didn’t recalculate them based on the data. Sure, I could recalculate it manually after the sheet is opened, but that’s just annoying. Changing the calucation settings in Excel also didn’t fix that.

So I decided to look at the POI API docs and found a method called setForceFormulaRecalculation. That looked like it would do what I needed. As of version 1.1. POI4Xpages comes with a binding called postGenerationProcess: a very powerful feature that gives you access to the generated workbook object, right before it is send to the browser. Only thing I needed to do was to add this snippet to that binding and the formulas were calculated:

workbook.setForceFormulaRecalculation(true);

Import Excel files

Besides creating them, Apache POI is able to read Excel files too. Since POI4XPages is build on top of Apache POI, I was wondering if I’m able to read Excel files in XPages too, with only having the POI4XPages library installed on my Domino server. I only have a requirement for the Office Open XML format (.xslx) that’s supported since Excel 2007.

And guess what: it worked right out of the box. Only thing you need is piece of Java code:

File excel = new File ("C:/spreadsheet.xlsx");
fis = new FileInputStream(excel);</code>

XSSFWorkbook wb = new XSSFWorkbook(fis);
XSSFSheet ws = wb.getSheetAt(0);

int rowNum = ws.getLastRowNum() + 1;
int colNum = ws.getRow(0).getLastCellNum();
String [][] data = new String [rowNum] [colNum];

for (int i = 0; i &lt;rowNum; i++) {
  XSSFRow row = ws.getRow(i);
  for (int j = 0; j &lt; colNum; j++) {
    XSSFCell cell = row.getCell(j);
    String value = cell.toString();
    data[i][j] = value;
    System.out.println("Value of cell in row " + 
      i + ", col " + j + ": " + value);
  }
}

fis.close();

Here’s what this code is doing:

I’m creating a FileInputStream based on a file on my file system. Of course I can also use a document attachment for that using the getInputStream() method of the EmbeddedObject class. With that FileInputStream I create a new POI XSSFWorkbook and then retrieve the first worksheet. The XSSFWorkbook also has a method to retrieve a worksheet by name. I then get the number of rows and columns and loop through them.

* POI4XPages is part of the OpenNTF Essentials. Check it out if you haven’t!

New demo on Bootstrap4XPages: Reusable fields with validation

form_validationI just released a new demo on Bootstrap4XPages.com. This one is about reusable fields and form validation: I show you how you can create a custom control with a dynamic field binding that you can (re)use to create Bootstrap styled fields. Although I’ve written the article for use with Bootstrap, the same method can also be used with any other framework.

Next on my todo list: upgrade the site to use Bootstrap 3.

New demos on Bootstrap4XPages: Select2 and Alerts

In case you haven’t seen them yet: I’ve added two new articles/ demos on Bootstrap4XPages.

The Alerts article shows how you can use the XPages built-in FacesMessages functionality to show Bootstrap-styled alerts to users. It also allows you to add the message on one page, navigate the user to another and show the message on that page using the multi-page messages PhaseListener described here.

The Select2 article shows you how to integrate the excellent Select2 plugin into your XPages. Select2 can be described as a combobox-on-steroids/ value picker that allows you to search in all options, work with remote data (using Ajax requests), do multiple selects and format the results using HTML.

Happy Bootstrapping!

(oh and I’m working on a couple of more articles, so stay tuned…)

Getting your Git projects back in Domino Designer

Since a while now I’m using source control in Domino Designer and I love it! I’m using eGit because I like that it’s integrated directly into Designer.

I recently needed to re-install Designer and found out that all on-disk projects needed to be re-added to Designer too. In this post I’ll share a way on how you can restore those and restore the connection with the NSF´s.

First thing you need to do after installing Designer is to re-install the eGit plugin. By default, eGit stores the GIT repositories on Windows in a directory called “git” in the users’ home folder (c:users<your name>)*. An uninstall of Designer will not remove that folder, so my on-disk projects were still there. Note: add this folder to your backups!

import_gitNext add your databases to Designer and organize them using working sets. You then need to get the Git projects back in Designer: go to the Package Explorer, right click somewhere in it and choose “Import”. Enter “git” in the search dialog and select the “Projects from Git” option. Select the Git repository (folder) that contains your project (or click “Add” to select the location of the repository on the file system). In the next screen, leave the “Import existing projects” option enabled and select the “Working Directory” folder. Click “Next” and Designer will show you the on-disk projects it contains. Select the ones you would like to import. I would suggest to select the working set you chose for your database, but for some reason I wasn’t able to select it, so I added the Git project to the working set afterwards using the method described here . Click “Finish”.

You’re now ready to restore the link from your databases/ applications with the on-disk project: right-click on a database and select Team Development > Associate with Existing On-Disk Project. In my situation I have the latest design sitting in my database, so I choose the “Export from database.nsf to selected on-disk project” option. If you want the on-disk project to be leading, choose the “Import …” option. Select the on-disk project you just imported and hit Finish. Done. Now back to work!

By the way: it looks like there’s a bug the eGit version used in Designer that causes eGit’s repository views to sometimes be completely blank. No fear: click the menu icon next to the view and select “Refresh”.

* Side-note: if you create an on-disk project for a database, all files are stored (by default) in <notes data>workspace<project name>. If you then add that local on-disk project to eGit using Team > Share project, the entire folder is moved to the default eGit folder at c:users<your name>git<new repo name>.