the road to damascus - a conversion experience: lotusscript and @formula to ssjs
DESCRIPTION
Tips, tricks and traps for converting IBM Domino LotusScript and Formula language to SSJS for XpagesTRANSCRIPT
MWLUG 2014
The Road to Damascus – A Conversion Experience:
LS and @Formula to SSJS
Matthew Fyleman, Product and Project Manager
Who am I?
• Matthew Fyleman
• 21 Years as a Notes/Domino Developer
• Mostly Working on:
– Xpages conversions
– Product development
What is this Talk About?
• Based on My Experiences
• Converting LotusScript and @Formula
to SSJS
• Tools that can help – particularly
regular expressions
What am I talking about?
• When should you convert existing code?
• Conversion Options– NotesAgent.run() with parameter doc
– Search and Replace
– Dedicated Tools
• Search and Replace– Preparation
– Introduction to Regular Expressions
– Examples and Demonstration
– Tips and Traps
• Dedicated Tools
• Questions
When should you convert code?
Never!
When should you convert code?
What is the problem?
• It is always going to be slow
• GIGO
• You will introduce new bugs
• Re-developing will be quicker, cheaper
and you will end up with a better result
• But if you really must ...
Conversion Options
What are your options?
• NotesAgent.run()
– Quick and Dirty
– Agent must run independently
– Only use when agents are available and time is critical
• Search and Replace
– LotusScript -> JavaScript (and Java)
– Less useful for @Formula
• Dedicated Tools
– @Formula
LotusScript to SSJS - Preparation
• Search and Replace is most useful for LS conversion
– Syntactically similar
• Easiest if you do a little refactoring first
– Option Declare
– doc.field(0) -> doc.getItemValue(“Field“)(0)
– Camel Case Notes Objects
– Make Sure Method calls are consistently named
• Best to Avoid All-In-One-Go
– Function or Sub at a Time
Regular Expressions
• Regular Expressions are your new BFF
• Sophisticated Pattern Matching
• Elements from search can be carried through to
replace
• The Search and Replace built in to DDE can use
Regular Expressions
• Useful outside LS conversion (e.g. Validation)– See Planet Lotus - http://planetlotus.org/profiles/ross-swick_97733
Starting Simple – Dim
• Tidy up first – Option Declare, remove clustering e.g.:
Dim x as Integer,y as Integer,z as Integer
• We want to match any variable name in the pattern:
Dim <var name> As <Any valid type>
• Fairly simple:
Dim[ ]+[A-Za-z0-9_]+[ ]+As[ ]+(Integer|String|Boolean|Double|Variant)
• But how do we replace?– Modify the search:
Dim[ ]+([\w]*)[ ]+As[ ]+String
– Use this for replace
var \1 = “”;
Starting Simple – Dim (2)
• For Notes Objects, Things are simpler
Dim <var name> As Notes<rest of object name>
- Ignore ... As New NotesSession for now
• Also, initialising in SSJS, = null is ok:
var <var name>:Notes<rest of object name> = null;
• So our terms are:– Search:
Dim[ ]+([\w]*)[ ]+As[ ]+(Notes[\w]*)
– Replace:
var \1\:\2 = null;
Less simple – If Statements
• For the most part, simple S & R (but order is important):End If to }
[ ]*Then to \) {
Else[ ]+If[ ]*to } else if \(
If[ ]* to if \(
• But what about:
If (x = 10) Then
• Use Search: If[ ]+([\w\(\)\[\]\.<>" ]*)=([\w\(\)\[\]\.<> "]*)[ ]+Then
• Use Replace: if \(\1==\2\) \{
• NB: Works but not optimal!
• Other comparison operators not a problem
! – session objects
• The problem:
• Session object is global in ssjs: ‘session’
• In LS it is created:
Dim sess As New NotesSession
• Need to find all LS session objects, and replace with session
• How do you get a list of session object names?
You need a coffee!
Adding Java
• Java String Object has regex search and replace
String source = “Dim x As String”;
String result = source.replaceAll(“Dim[ ]+([\w]*)[ ]+As[ ]+String”, “var $1 = \“\”;”);
• Pattern and Matcher objects make this even more powerful
Pattern p = Pattern.compile(pattern);Matcher m = p.matcher(this.source);int startPos = 0;while (m.find(startPos)) {
if (!itemList.contains(m.group(1))) {itemList.add(m.group(1));
} startPos = m.end() + 1;
}
Field Handling
• Similar Issue to Session
• Need to find all document object names, and replace field
handling methods
• Will probably need to handle dot notation
– Arrgghh!
• How do you search for dot notation?
<doc name>\.([^GetItemValue])\([0-9]+\)
• Still hard work!
Search and Replace: Tips & Traps
• There are other types than string!
– Always review and test converted code thoroughly
• Date handling is a pain
– Script libraries can help here – Java?
• Watch out for User interaction and particularly dialogues
Work out your strategies in advance!
Converting Formula
• @Formula JavaScript Wrappers help a lot
– Mostly just ‘;’ to ‘,’, and converting lists to arrays
• Some constructions are obvious:
@SetField(“Field”, Value);
• Goes to:
doc.replaceItemValue(“Field”, Value);
• Or
S: @SetField\([ ]*([\w”]*)[ ]*\,[ ]*([\w”]*)[ ]*\);
R: doc\.replaceItemValue\(\1, \2\);
• But there are some issues ...
@
Formula – List Processing
• No direct equivalent in SSJS for *+, *= *>= etc.
when applied to Lists
• Need to plan for this
• Java Class/Library to provide direct substitute
• Unfortunately, Java does not permit operator
overloading, so has to be a set of methods@!
Formula - @If, @Do and @While
@If(@Contains(_WFData_neu;_Key);"";
@Do(
@Set("_Sachgebiet_Zuordnung";@DbLookup("NOTES":"NOCACHE";"":_ADM$StructureDB;"Workflows";"WFArbeitsanweisung";"Sachgebietzuordnung"));
@If(_Sachgebiet_Zuordnung = "" | !@Contains(_Sachgebiet_Zuordnung;_Key2);@Do(
@Prompt([Ok];"Hinweis";"In der System Struktur VBM wurde für das aktuelle Sachgebiet kein Workflow definiert. Das Dokument wird zum ehemaligen
Kompetenzträger zurückgegeben, damit dieser ein neues Sachgebiet auswählen kann.");
@Set("_Kompetenzträger";Bearbeiter1);
@Set("_tmpintern";5)
);
@Do(
@Prompt([Ok];"Hinweis";"In der System Struktur VBM wurde für das aktuelle Sachgebiet ein neues Sachgebiet konfiguriert. Das Dokument wird zum
Kompetenzträger zurückgegeben, damit dieser das neue Sachgebiet auswählen kann.");
@Set("_neues_Sachgebiet";@Left(@Right(_Sachgebiet_Zuordnung;_key2);"||"));
@Set("_Elements";@Elements(@Explode(@Left(@Left(@Right(_WFData_neu;"||Sachgebiet#");"||"); _neues_Sachgebiet) + _neues_Sachgebiet; "$" )));
@Set("_KompetenzträgerData";@Explode(@Left(@Right(_WFData_neu;"||Kompetenzträger#");"||"); "$"));
@Set("_Kompetenzträger";@Subset(@Subset(_KompetenzträgerData;_Elements);-1));
@Set("_tmpintern";6)
)
)
)
); @!!
Focusing on @If
@!!!• @Formula is a FUNCTION language
• @If is a function not a statement
• In practice:
@SetField(“Author”; @If(Status=“1”; Manager; Salesman));
• Needs to convert to:if (Status == “1”) {
var author = doc.getItemValueString(“Manager”);} else {
var author = doc.getItemValueString(“Salesman”);}doc.replaceItemValue(“Author”, author);
Tools
• Search and Replace can be used for @Formula ->
SSJS ...
• ... but it can only take you so far
• A dedicated tool can go further
– Only real alternative to manual translation for complex
statements
– Time consuming to create
– Still not a silver bullet
Third Party Tools
• Espresso - http://www.ultrapico.com/Expresso.htm
– Good for learning regex, and serious regex dev
– Free!
• GREP
– Sophisticated regex file search
– Where regex started (UNIX grep)!
Resources and Information
• We4IT – www.we4it.com
• OpenNTF – www.openntf.org
• Regex Quick Reference
http://www.night-ray.com/regex.pdf
• Loads of websites for all aspects of regex development
• Mastering Regular Expressions – Jeffrey E.F. Friedl –
O’Reilly Publishing
Questions?