2. Who am I?
• Bill Buchan, CEO of hadsl - one of the
sponsors of this show
• Come visit the booth - we don’t bite
• Dual PCLP in v3, v4, v5, v6, v7, v8, and v8.5
• Enterprise-level consultant on Domino
since 1995
Thursday, 22 March 12
3. Agenda
• What is LotusScript? Where is it going?
• LotusScript Basics
• LotusScript Advanced
• Web Services
Thursday, 22 March 12
4. What is LotusScript
• LotusScript is:
• A p-code partially compiled, partially
interpreted language
• Syntactically identical toVisual Basic 3
• In most Notes Applications.
Thursday, 22 March 12
5. What is LotusScript
• LotusScript
• is old. It was introduced with Notes v4,
and was first implemented in Ami Pro
• Supports Object Orientated techniques
• Is fast, scalable, robust
• Is Multi-Platform
Thursday, 22 March 12
6. Where is it going?
• Number of LotusSphere 2012 sessions that
mentioned LotusScript: one
• No language modifications since Notes v4.6
• (Every version has had class extensions
to support some new version features)
• Its fair to say that it is not considered a
priority for Lotus
Thursday, 22 March 12
7. So why are we here?
• I wanted to give you a single session that
covered everything I knew about
LotusScript
• We still have to maintain applications
Thursday, 22 March 12
8. Agenda
• What is LotusScript? Where is it going?
• LotusScript Basics
• LotusScript Advanced
• Web Services
Thursday, 22 March 12
9. Basics: How to code
• Code for maintenance.
• You will change this code.This code will
run for 10+ years. Unchanged.
• Log everything.
• If the users find out before you, you’ve
lost.
• Good log information means faster
debugging
Thursday, 22 March 12
10. Basics: How to code
• Bugs cost money.The closer to production,
the more expensive they are. More testing
and debugging and logging costs less
• Isolate business logic from display logic.
Your look and feel WILL change
• Simplicity is cheap
Thursday, 22 March 12
11. Basics: Option Declare
• You should use ‘Option Declare’ when
possible.Why?
• Not using Option declare, and not
declaring your variables in advance,
makes every variable aVARIANT
• Variants move all errors to run-time
• Variants are slower to use.
Thursday, 22 March 12
12. Basics: lsi_info
• LSI_Info was a student intern project, and is
a global variable created and maintained by
the LotusScript environment
• It contains lots of ‘interesting’ values
• Superseded by getThreadInfo
• Its not thread-safe. Heavily loaded servers
may crash if its accessed.
Thursday, 22 March 12
13. Basics: lsi_info
• lsi_info(10) gives the calling class
• lsi_info(11) gives the calling function.
• So we can write a pretty cool error
handler..
Thursday, 22 March 12
14. Function RaiseError()
Dim thisType As String Dim es as String
thisType = Typename(Me)
' Not a class, use the calling module instead
If (thisType = "") Then thisType = Getthreadinfo(11)
es = thisType & "::" & Getthreadinfo(10) & ": "
If (Err = 0) Then
es = es + "Manually raised an error"
Else
es = es + "Run time error: (" + Trim(Str(Err)) + ") "
+ _
Error$ + " at line: "+ Trim(Str(Erl)) End If
Print es
end function
' calling code...
ExitFunction:
exit function
errorhandler:
Call RaiseError()
resume exitFunction
end function
Thursday, 22 March 12
15. Basics. NotesSession
• This piece of code:
dim s as new NotesSession
• Doesn’t actually create anything. It just
references the same global NotesSession
object, built in advance
• No performance hit for declaring it
(But that doesn’t excuse bad code!)
Thursday, 22 March 12
16. Basics:AdminP
• AdminP documents have
special fields for ReplicaID
• Stored as Notes Date/
Time fields
Dim dt As New NotesDateTime(targetDatabase.ReplicaID)
Call doc.replaceItemValue("ProxyReplicaID", dt)
Thursday, 22 March 12
18. Basics: Performance
• A crude agent profile mechanism was
introduced in Notes 7
• You enable it from the agent/web service
properties pane:
Thursday, 22 March 12
20. Basics: Lists
• A list is a
collection
of values,
which has
a fixed
lookup
value
dim Surnames list as String
Surnames(“Bill”) = “Buchan”
Surnames(“Paul”) = “Mooney”
Surnames(“Chris”) = “Coates”
Print “Bill’s surname is: “ + Surnames(“Bill”)
if (isElement(Surnames(“Charlie”))) then
Print “Charlies Surname is: “ + Surnames(“Charlie”)
else
Print “I can’t find a surname for Charlie”
end if
forall thisName in Surnames
Print listtag(thisName) + “ “ + thisName
end forall
erase Surnames(“Buchan”)
Thursday, 22 March 12
21. Basics: Lists
• So lists can collect together similar values
in an ordered way
• Lists have no real overhead
• Lists can contain millions of items
• Lists are very fast
Thursday, 22 March 12
22. Basics: Lists
• You cannot read and write Lists directly
from Documents
• Convert into a array first, and store as a
multi-value
• You have to iterate a list to see how many
items it contains
• Lists can only store values of the same type
Thursday, 22 March 12
23. Agenda
• What is LotusScript? Where is it going?
• LotusScript Basics
• LotusScript Advanced
• Web Services
Thursday, 22 March 12
24. Advanced: Classes
• LotusScript allows you to define classes:
• Classes allow you to bundle variables and
code together in reusable objects
• Classes can inherit from other classes (but
not the ‘notes*’ classes)
• Classes can help build complex systems
quickly and easily
Thursday, 22 March 12
25. Advanced: Classes
• Example class: define ‘Person’
class Person
public personName as NotesName
public UNID as String ‘ UNID to doc in NAB
sub new(doc as NotesDocument)
set personName = new NotesName( _
doc.getItemValue(“FullName”)(0) )
set UNID = doc.UniversalID
end sub
end class
Thursday, 22 March 12
26. Advanced: Classes
dim P as new Person(personDoc)
print “Person: “ + P.personName.Common + _
has document ID: “ + P.UNID
• Example class: Using ‘Person’ class
Thursday, 22 March 12
27. • Create another class that encapsulates
‘Person’
class People
public people list as Person
public count as long
sub new(nabView as NotesView)
dim doc as NotesDocument
set doc = nabView.getFirstDocument()
while not doc is nothing
dim P as new Person(doc)
set people(P.personName.Abbreviated) = P
count = count + 1
set doc = nabView.getNextDocument(doc)
wend
end sub
end class
Thursday, 22 March 12
28. Advanced: Classes
• Using ‘People’
dim folks as new People(nabView)
forall thisPerson in folks.people
print “Person: “ + thisPerson.personName.Common + _
has document ID: “ + thisPerson.UNID
end forall
Thursday, 22 March 12
29. Advanced: Classes
• Lets add logging functionality to these
classes by creating a new ‘layer’.
Class log
sub new()
end sub
public sub logMsg(msg as String)
print msg
end sub
end class
Thursday, 22 March 12
30. class Person as log
public personName as NotesName
public UNID as String ‘ UNID to doc in NAB
sub new(doc as NotesDocument)
set personName = new NotesName( _
doc.getItemValue(“FullName”)(0) )
set UNID = doc.UniversalID
logMsg(“created new person: “ + P.personName.Common)
end sub
end class
• We can ‘inherit’ ALL functionality from ‘log’
by creating ‘Person’ as a subclass of log.
Advanced: Classes
Thursday, 22 March 12
31. Advanced: Classes
• You can only ‘inherit’ from one class at a
time (other languages have mechanisms for
more)
• Every class you inherit from gets to run its
constructor in the sequence you defined
inheritance
• This allows you to quickly segment large
problems and delegate work
Thursday, 22 March 12
32. Advanced: Calling C-API
• Not all Lotus Notes API calls are defined in
LotusScript. Sometimes you want to
execute these.
• You can define ANY library/DLL function in
LotusScript and call it
• Its dangerous...
Thursday, 22 March 12
33. • You have to define EXACTLY the function
using the correct sized primitive variable
types (such as integer, etc)
• If you get any part of it wrong, you will
crash the client. Badly.
• Its Platform-specific. So you have to rewrite
this for every single platform you support
Advanced: Calling C-API
Thursday, 22 March 12
34. • Example:
NSFGetServerLatency
• Find out how many milliseconds it takes to
ping a Domino server.
• Defined as:
Advanced: Calling C-API
STATUS LNPUBLIC NSFGetServerLatency(
char far *ServerName,
DWORD Timeout,
DWORD far *retClientToServerMS,
DWORD far *retServerToClientMS,
WORD far *ServerVersion);
Thursday, 22 March 12
35. • We can define this in LotusScript using:
Advanced: Calling C-API
' This is a constant for our windows-based
' Library file:
Const LIB_W32 = "nnotes.dll"
' Declare our function for windows
Declare Function W32_NSFGetServerLatency _
Lib LIB_W32 Alias {NSFGetServerLatency} (_
Byval ServerName As Lmbcs String, _
Byval Timeout As Long, _
retClientToServerMS As Long, _
retServerToClientMS As Long, _
ServerVersion As Integer) As Integer
Thursday, 22 March 12
36. • And we can use this (on a 32-bit windows
client or server at least) by:
Advanced: Calling C-API
' A function to get network latency time...
Public Function getServerLatency (strServer As String) As Long
Dim nnServer As New NotesName(strServer)
Dim ToServer As Long, fromServer As Long
Dim ver As Integer
Dim timeout As Long
timeout = 1000 ' 1000ms == 1 second
Call W32_NSFGetServerLatency(nnServer.Canonical,_
timeout, toServer, fromServer, ver)
' Return both directional latencies added together
getServerLatency = fromServer + ToServer
End Function
Thursday, 22 March 12
37. • C-API can get to functionality that would
be impossible to implement in LotusScript
alone
• It requires FAR more testing than anything
else - use it as a last resort
• Good reference: http://www.ls2capi.com
Advanced: Calling C-API
Thursday, 22 March 12
38. Advanced: Execute
• ‘Evaluate’ in LotusScript allows you to evaluate
@Formula language:
myString = Evaluate(|@Unique|)
• Execute allows you to execute LotusScript
code
• You can write code that writes code
Thursday, 22 March 12
39. Advanced: Execute
Dim executeString as String
executeString = |
print “Hello world”
dim s as new NotesSession
dim db as NotesDatabase
set db = s.currentDatabase
print “Current Database name is: “ + db.Title
|
execute (executeString)
• Example
Thursday, 22 March 12
40. Advanced: Execute
• I use it to dynamically calculate C-API
function signatures
• http://www.hadsl.com/HADSL.nsf/
Documents/LS2CAPI+-+Calling+Notes
+C-API+from+LotusScript
• It can also be used for evil...
Thursday, 22 March 12
41. Advanced:TriggerHappy
• Imagine we wish to profile ALL our agents
in ALL our databases,ALL the time.
• We could monitor each database to see
when a profile document with form name
$BEProfileR7 is saved
• Save it in a central database...
Thursday, 22 March 12
42. Advanced:TriggerHappy
• Damien Katz (now of CouchDb, ex-Iris)
wrote a server addin called ‘TriggerHappy’,
available on OpenNtf.
• It allows you to define lotusscript which
gets executed on ANY database event at a
server level.
• RunningWithScissors++
Thursday, 22 March 12
43. Advanced:TriggerHappy
• Its detailed (with some code) on my blog
at:
• http://www.billbuchan.com/imported-20091119232548/2010/2/2/
universal-agent-profiling-in-domino.html
• We ran it in our TEST environment for
months without issue
• It also tracked Web services as well as
LotusScript and Domino agents
Thursday, 22 March 12
44. Agenda
• What is LotusScript? Where is it going?
• LotusScript Basics
• LotusScript Advanced
• Web Services
Thursday, 22 March 12
45. Web Services: Introduction
• Web services are a language and platform
independent way of wiring applications
together
• Fundamentally they’re usually web service
http calls passing back and forth XML
encoded information
Thursday, 22 March 12
46. • Lotus Domino 7 (now out of support!)
provided a simple lotusscript based Web
services provider
• Lotus Domino nd8 provides a consumer
and a provider
Web Services: Introduction
Thursday, 22 March 12
47. Web Services:
Experience
• They’re fast. 10+ calls per second. Much
faster than I expected
• But if you want performance, implement
xPages REST based web service
providers - 5x faster
• Reliable
• Look and feel like an agent
Thursday, 22 March 12
48. Web Services: Example
• A single function that returns a single string
Thursday, 22 March 12
50. Web Services:Authentication
• Two general types of Domino
Authentication:
• Session based - uses cookies back and
forth
• Username and Password based -
username and password is sent with each
transaction
Thursday, 22 March 12
51. • Client Example:
• We use Flex as a client
• It automatically inherits cookies from the
web page its launched from
• Launch it from an Authenticated page
• Keep the session active by pinging every
10 minutes
Web Services:Authentication
Thursday, 22 March 12
52. • Server Example:
• We use a windows-based service to
perform work
• We encrypt a username/password pair in
the registry, and use username/password
authentication
• It wakens up every 5 minutes and calls
home
Web Services:Authentication
Thursday, 22 March 12
53. Web Services: Complex
• You can pass back simple types. Or classes.
• Lotuscript limitation - you cannot return an
array
• So how can I return an array?
Thursday, 22 March 12
54. • Define a class which contains an Array
Web Services: Complex
Thursday, 22 March 12
56. Web Services:Thoughts
• Web service clients are not under your
control
• Decide how complicated your client can
handle
• More granular == more likely to change
• Choose wisely
Thursday, 22 March 12
57. Resources
• The LS to C-API programming manual
• http://www.ls2capi
• Calling C-API from LotusScript resource:
• http://www.hadsl.com/HADSL.nsf/Documents/LS2CAPI+-+Calling
+Notes+C-API+from+LotusScript
• Steve McConnell, Code Complete 2 (MS
Press, 2004).
• http://www.amazon.com/gp/product/0735619670
Thursday, 22 March 12
58. The End?
• This presentation, like all my others, is
available at
• http://www.hadsl.com
Thursday, 22 March 12