Tim Tripcony’s incinerate function elegantly batch recycles Domino Objects in Java

I recently was surfing through Stackoverflow and I hit a response from Tim Tripcony on this post: What is the best way to recycle Domino Objects in Java Beans

He published a small helper function to recycle an arbitrary number of Domino objects. It’s so simple, and so well written, that I thought it deserved a post of its own. Here it is in all its glory:

[sourcecode language=”java”]
private void incinerate(Object… dominoObjects) {
for (Object dominoObject : dominoObjects) {
if (null != dominoObject) {
if (dominoObject instanceof Base) {
try {
((Base)dominoObject).recycle();
} catch (NotesException recycleSucks) {
// optionally log exception
}
}
}
}
}
[/sourcecode]

And it’s used like this:
[sourcecode language=”java”]
Database wDb = null;
View wView = null;
Document wDoc = null;
try {
// your code here
} catch (NotesException ne) {
// do error handling
} finally {
incinerate(wDoc, wView, wDb);
}
[/sourcecode]

I find the function elegant in many ways; the function and the variables are clearly named, Tim uses variable-length argument lists (thats the Object… part with the ellipsis), the new for-each iteration, plus there is some humour. Thanks, Tim.

SSJS is an abomination born out of IBM’s misguided condescension

Scott Souder was recently extolling the skill of the IBM developers and added as an aside “these are not your average domino developers”. I flinched at the statement and thought defensively “does he mean me?”

The more I think of it, though, and it becomes obvious that this is a central assumption that affected the design of XPages. It’s even there, in the introduction to the mastering XPages book.

I would like to humbly submit to IBM that domino developers nowadays are not an unskilled community, and that its modeling of who domino developers are needs some updating, in the hope that this will positively affect further design decisions. We’re not the Samanthas of the programming world.

It’s immediately obvious at any notes gathering that we are not the youngest community – I rarely see anybody in their twenties, for instance. It’s therefore obvious that we are all experienced. Even those without a computer science background (and this applies to me) has learnt, the hard way, that it’s the maintenance and debugging of code which is complex, not the writing. I learned, the hard way, that copy-pasting code is a shortcut which kills you a couple of years later. I learned that structuring code cleanly, with small functions doing a single thing, ends up being far easier to maintain than two thousand lines of procedural code. Making the switch from procedural code to object oriented code helped tremendously, along with the concept of separating business logic from the displaying logic.

XPages was confusing to me at the beginning. It seemed like a step backwards. Squirreling bits of JavaScript into the XML code, into what clearly should strictly be a presentation layer, mixing business logic with presentation logic, after spending years moving code from buttons and hotspots in forms into script libraries? It doesn’t make sense – until you understand the central assumption of IBM, which was that we would not get Java. Too difficult. The dumbo domino developers will never get it. They only get quick-and-dirty RAD.

Then, in the course of my XPages learning curve I stumbled into managed beans, and everything clicked into place. This is where the beauty lies, this is where I can put my layered, easily debuggable, easily testable code. It’s easy to bind to the XML source, and the Expression Language is concise and powerful. And yet these sections are under-documented, the know-how gleaned from stack overflow and numerous blog entries on the subject made by us, dummy domino developers.

In the face of the obvious scarcity of resources that IBM has devoted to the Notes platform, it is such a crying shame to have invested so much into SSJS and the whole formulation of formula language as JavaScript functions. (An impressive achievement, but a misguided one in my opinion).

The resources could have been better spent elsewhere. Learning java is but one of the challenges of learning XPages, and it’s a challenge for which there are tons of documentation.

There’s often a picture made about misguided security in IT – a brand-new lock on a rotten door doesn’t increase your security. Here there is a parallel with misguided condescension – Removing Java out of the learning curve is just a small contribution to making XPages simpler. There’s a plethora of new stuff that we must learn, we must get our heads around conflicting terminology (e.g. Notes View, JSF View, Eclipse View), a lot of functionality comes from knowing that the CSS class you need is called ‘lotusInlinelist lotusUtility’, there are missing tools such as JUnit, refactoring, renaming so you end up having to do a lot of things manually…

SSJS annoys me because of the underlying assumption – I am dumb.

SSJS also annoys me architecturally. It breaks the MVC model pretty badly. It probably also affects performance and scalability (although I have no figures to support this)

And it’s also a misnomer: It’s not at all JavaScript being run on the server (like node.js would do, blindingly fast on top of Google’s V8 engine). At runtime it’s really running as Java. Guess why it takes so long to build your projects? Our poor computers have to interpret the ‘JavaScript’ and translate this into Java code. And your guess is as good as mine when it comes to the new versions of JavaScript – will IBM update too, to ECMA 5 Strict, say?

My tip: circumvent SSJS as soon as you can and go straight to Java.

Powerful searches in DDE: Regex for ‘all bar that don’t start with foo’

Regexes are wonderful. There’s a learning curve, and they are very cryptical to be able to read, let alone write, but once you get the hang of it they are wonderful.

I was doing some refactoring and I wanted to see all instances of a function called ‘AddButton’ – and my results got saturated with another function ClickAddbutton.

Which Regex to use to ask for ‘Show me all AddButtons but ignore ClickAddButton’?

The trick here is to use negative lookbehind:

(?<!textIDontWantPrefixed)TextIAmLookingFor

so in my example this was what to input in the search box in DDE:

(?<!Click)AddButton

This is the way it works:

1. Search for ‘AddButton’

2.When you’ve found ‘AddButton’, look if there is a naughty prefix (‘Click’) which invalidates the search.

This is the lookbehind part. It’s slightly confusing because a lookbehind is going to look at the bits to the left of the word, which one would typically call ‘before’. The regex convention is that forwards is the direction of parsing and behind is the other direction.

3. if the naughty prefix isn’t there, return a match.

That’s the negative part.

Voilà!

P.S. an excellent tool for Regexes is RegExBuddy (Windows only though). Really recommended, saved me loads and loads of time. I wouldn’t do regexes without it.

Finding comments from Tim or Jens in forums and blogs

Every now and then, on my searches in the interwebs, I find a comment or an answer by Tim or Jens, and different emotions hit me:

There is a moment of shock, a ‘speaking from the dead’ frisson, then sadness at their deaths, and then, also, gratitude and a sense of wonder that they are still helping me out.

Jens never missed an event, be it in Switzerland or abroad (where the both of us were sometimes the only attendees coming from Switzerland). I found him to be exact, friendly, helpful and in the last few years he had been a driving force within SNOUG, the Swiss notes user group and had organised a few weeks before his death a very enjoyable day for us locals.

I only met Tim in person once, at the ILUG in Cardiff (where he delivered his infamous Star-Wars themed session with Paul Withers). Blattschuss. What a wonderful session.

I regularly read his blog, and I was always impressed about his creative energy, always pushing at the boundaries of what is possible, and I always wondered – Where does he find the time for all of this?

We had a long chat walking to the restaurant and I discovered that he also sung in his spare time – a hobby that I share with him, and Julian Woodward. I had imagined us singing a trio together, for a laugh and hopefully for a bit of a surprise. He was enthusiastic about the idea. It would have been lovely, he had such a deep bass voice, almost effortless, Julian is a Tenor, and I am a baritone, so it would have been perfect.

Tim was also surprisingly accessible, and, his evident acumen notwithstanding, never made me feel silly. His explanations always left me thinking ‘so that’s how you do it’ instead of the unfortunately far more common ‘that went miles over my head, I’d better just nod as if I understood’.

At the moment I just feel grateful to have such a wonderful job, to have so many talented persons pooling their knowledge without any financial reward, to work in an environment that is so fast-paced, and being able to discover such persons as Jens and Tim.

calling Word’s Find and Replace using LotusScript

There are two syntaxes to call OLE objects, one is using := like this:

Set myRange = ActiveDocument.Content
myRange.Find.Execute FindText:="hi", ReplaceWith:="hello", Replace:=wdReplaceAll

Unfortunately LotusScript does not know how to deal with this, so you have to list the arguments exhaustively and in their correct order, including arguments which one does not really need.

Usually I can figure the syntax pretty quickly, but this one was really fiddly, so here is my function in all its glory.

I’ve tested it on Notes 9.0.1 and Word 2010, German version – YMMV.

[code language=”vb”]
‘/*************************************************************************************
‘ * Function FindAndReplaceWithinWordOLEObject:A function to find and replace some string within an inputted word document.
‘ * This function has been written because the OLE Call to the function is complicated and LotusScript does not
‘ * allow this syntax : .Execute FindText:="hi", ReplaceWith:="hello", Replace:=wdReplaceAll
‘ * @param varWordDocument a Word Document. (e.g. Application.ActiveDocument)
‘ * strFindThis the string I want to replace
‘ * strReplaceWithThis the replacement string
‘ * @return true if successful.
‘ * @author Andrew Magerman/Magerman/NotesNet
‘ * @version May 9, 2014
‘ *************************************************************************************/
Function FindAndReplaceWithinWordOLEObject(varWordDocument, strFindThis As String, strReplaceWithThis As String) As boolean

On Error GoTo ErrorHandling

Print "version 7"

‘documentation of these values at end of function
Dim FindText As Variant
Dim MatchCase As Variant
Dim MatchWholeWord As Variant
Dim MatchWildcards As Variant
Dim MatchSoundsLike As Variant
Dim MatchAllWordForms As Variant
Dim Forward As Variant
Dim Wrap As Variant
Dim SearchFormattting As Variant
Dim ReplaceWith As Variant
Dim ReplaceZeroOrOneOrAll As Variant

FindText = strFindThis
MatchCase = True
MatchWholeWord = False
MatchWildcards = False
MatchSoundsLike = False
MatchAllWordForms = False
Forward = True

‘The folowing are the valid constants for Wrap
‘Const wdFindStop = 0
‘Const wdFindAsk = 2
‘Const wdFindContinue = 1
Wrap = 1

SearchFormattting = True
ReplaceWith = strReplaceWithThis

‘The folowing are the valid constants for ReplaceZeroOrOneOrAll
‘Const wdReplaceAll = 2
‘Const wdReplaceNone = 0
‘Const wdReplaceOne = 1
ReplaceZeroOrOneOrAll = 2

FindAndReplaceWithinWordOLEObject = varWordDocument.Content.Find.Execute(FindText, MatchCase, MatchWholeWord, MatchWildcards, MatchSoundsLike, MatchAllWordForms, Forward, Wrap, SearchFormattting, ReplaceWith, ReplaceZeroOrOneOrAll)

Exit Function
Errorhandling:
Call LogError()
FindAndReplaceWithinWordOLEObject = false
Exit Function
%REM
expression .Execute(FindText, MatchCase, MatchWholeWord, MatchWildcards, MatchSoundsLike, MatchAllWordForms, Forward, Wrap, Format, ReplaceWith, Replace, MatchKashida, MatchDiacritics, MatchAlefHamza, MatchControl)
expression Required. A variable that represents a Find object.

Parameters

FindText
Optional
Variant
The Text To be searched for. Use an empty String ("") To search For formatting only. You can search For special characters by specifying appropriate character codes. For example, "^p" corresponds To a paragraph mark And "^t" corresponds To a Tab character.

MatchCase
Optional
Variant
True To specify that the find Text be Case sensitive. Corresponds To the Match Case check box In the Find And Replace dialog box (Edit menu).

MatchWholeWord
Optional
Variant
True To have the find operation locate only entire words, Not Text that Is part of a larger word. Corresponds To the Find whole words only check box In the Find And Replace dialog box.

MatchWildcards
Optional
Variant
True To have the find Text be a special search operator. Corresponds To the Use wildcards check box In the Find And Replace dialog box.

MatchSoundsLike
Optional
Variant
True To have the find operation locate words that sound similar To the find text. Corresponds To the Sounds Like check box In the Find And Replace dialog box.

MatchAllWordForms
Optional
Variant
True To have the find operation locate all forms of the find Text (For example, "sit" locates "sitting" And "sat"). Corresponds To the Find all word forms check box In the Find And Replace dialog box.

Forward
Optional
Variant
True To search forward (toward the End of the document).

Wrap
Optional
Variant
Controls what happens If the search begins at a point other than the beginning of the document And the End of the document Is reached (Or vice versa If Forward Is Set To False). This argument also controls what happens If there Is a selection Or range And the search Text Is Not found In the selection Or range. Can be one of the WdFindWrap constants.

Format
Optional
Variant
True To have the find operation locate formatting In addition To, Or instead of, the find text.

ReplaceWith
Optional
Variant
The replacement text. To Delete the Text specified by the Find argument, Use an empty String (""). You specify special characters And advanced search criteria just As you Do For the Find argument. To specify a graphic object Or other nontext item As the replacement, move the item To the Clipboard And specify "^c" For ReplaceWith.

Replace
Optional
Variant
Specifies how many replacements are To be made: one, all, Or none. Can be Any WdReplace constant.

MatchKashida
Optional
Variant
True If find operations match Text With matching kashidas In an Arabic-language document. This argument may Not be available To you, depending On the language support (U.S. English, For example) that you have selected Or installed.

MatchDiacritics
Optional
Variant
True If find operations match Text With matching diacritics In a right-to-left language document. This argument may Not be available To you, depending On the language support (U.S. English, For example) that you have selected Or installed.

MatchAlefHamza
Optional
Variant
True If find operations match Text With matching alef hamzas In an Arabic-language document. This argument may Not be available To you, depending On the language support (U.S. English, For example) that you have selected Or installed.

MatchControl
Optional
Variant
True If find operations match Text With matching bidirectional control characters In a right-to-left language document. This argument may Not be available To you, depending On the language support (U.S. English, For example) that you have selected Or installed.

MatchPrefix
Optional
Variant

True To match words beginning With the search string. Corresponds To the Match prefix check box In the Find And Replace dialog box.
MatchSuffix
Optional
Variant
True To match words ending With the search string. Corresponds To the Match suffix check box In the Find And Replace dialog box.

MatchPhrase
Optional
Variant
True ignores all white Space And control characters between words.

IgnoreSpace
Optional
Variant
True ignores all white Space between words. Corresponds To the Ignore white-space characters check box In the Find And Replace dialog box.

IgnorePunct
Optional
Variant
True ignores all punctuation characters between words. Corresponds To the Ignore punctuation check box In the Find And Replace dialog box.

Return Value
Boolean

%END REM

End Function
[/code]

Installing OpenNTF Essentials with local web preview

This took some time (OK, it took me day and it was painful), so here are some hints :

  • If you have uploaded the updatesite-runtime.nsf from openntf.org, you MUST sign all the plugins (Actions/Sign all).
  • In order for the Web preview to work, you will need to manually copy the plugin and feature files found respectively in

    C:\Program Files (x86)\IBM\Notes\Data\workspace\applications\eclipse
    to
    C:\Program Files (x86)\IBM\Notes\Data\domino\workspace\applications\eclipse\features

  • finally, when you read ‘restart http’ the command you want is

    Restart Task HTTP

    not

    Tell HTTP Restart

And here are the most useful articles and ressources I found on the interwebs:

Deploy an Eclipse update site to IBM Domino and IBM Domino Designer by John Dalsgaard

Extension Library deployment

XPages beyond the basics by Ulrich Krause

Notes Client Performance optimization with Notes RPC Parser: new Version 1.0.13 available

A new version of the Notes RPC is now available for download. Have a look here:

Lars Bentrop-Bos contacted me last week with a couple of bugs he had found in the application. Since I was already updating things, I made a large release, with many small improvements that I had been thinking of:

New function: Clear cache.ndk

Screen Shot 2014-04-07 at 10.08.41
NRPC Calls are logged only for calls between the server and the client. As a performance booster, Notes caches design element information on a local file called cache.ndk (in the notes data directory). If the file already exists in the local cache, it’s not downloaded by the server. The new button clears the local cache, so that you can simulate the kind of response times that first-time users have of your application.

New Navigation: using unread marks

Screen Shot 2014-04-07 at 10.12.34

I have cunningly made the particularly slow transactions unread documents, so that the end-user can jump from one to another.

Jump to Note
Screen Shot 2014-04-07 at 10.14.37
If a particular transaction concerns a particular note, you can now jump to that note. If it’s a data note, the client is opened, if it’s a designer note, the designer client is opened.

New UI:
1995 came by and took the old UI back. I have spruced things up and added new icons, including a nifty application icon showing some lightning