I still need to look into the mod_rewrite module for Apache via LSD::RELOAD.
Category: Uncategorized
LotusScript.doc (part 1)
LotusScript.doc is a series of script libraries that can generate HTML documentation for LotusScript libraries. It is mainly targeted at class delevelopment in script libraries but should be applicable to LotusScript in forms, views and agents.
I wrote the code last night and it looks promising. Below is a sample of some documentation I have generated. As you can see the documentation isn’t much to look at – layout will be the next issue I will address.
Sample documentation:
ScriptLibrary @ CLASS: DocumentationWriterClass @ DocumentationWriterA DocumentationWriter is used to write the documentation to an OutputStream. Method @ New[SUB] (PUBLIC) New(scripts As Vector) Method @ Write[SUB] (PUBLIC) Write(filename As String) |
The method signatures and comments are actually based on parses LotusScript code and shows that the library can parse classes with nested methods and functions. Comments are also included.
I have based the documentation format on the JavaDoc syntax:
'/** ' * Parent class. ' */ Public Class Bar End Class '/** ' * This is a class comment ' * and it may span multiple lines. The class ' * the inherits from the Bar class. ' */ Public Class Foo As Bar '/** ' * Constructor. ' */ Public Sub New() End Sub End Class
The above code generates documentation that looks like this if the code is in a script library called “FooBarLib”:
ScriptLibrary @ FooClass @ BarParent class. Class @ Foo (inherits from Bar)This is a class comment and it may span multiple lines. The class the inherits from the Bar class. Method @ New[SUB] (PUBLIC) New |
I’ll post more once I have worked a little more on the presentation.
Aspect to trace method calls in Java using AspectJ
I have never used aspects but some day it might come i handy –> Tracing an application using AspectJ
Using in JSTL under JBoss
The source of the problem could be found in the org.apache.taglibs.standard.tag.common.sql.DataSourceUtil class of the Jakarta implementation of JSTL. The problem is that the SQL function looks for the DataSource in the “java:comp/env” namespace where as my datasource was in the “java:” namespace.
The solution is to map the datasource to Tomcat using the web.xml and jboss-web.xml deployment descriptors:
web.xml
<!-- JDBC DataSources (java:comp/env/jdbc) -->
<resource-ref>
<description>The used datasource</description>
<res-ref-name>jdbc/DefaultDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
jboss-web.xml
<!-- make sure the web container can get jdbc connections -->
<resource-ref>
<res-ref-name>jdbc/DefaultDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<jndi-name>java:/pestikom2</jndi-name>
</resource-ref>
The above makes the java:/pestikom2 datasource from JBoss available in the java:/comp/env namespace in Tomcat. The datasource can now be referenced from JSTL using:
<sql:query dataSource="jdbc/DefaultDS" var="some_var" scope="page" sql="select * from foo" />
2005 season finally here
Finally !! Some weather that resembles spring… Though not as warm as one could wish for (still only around 8 degress celsius) the weather turned sunny and it seemed as though everyone chose Easter as the time to start. The road along the coast northward from Copenhagen was “packed” with happy road bikers. Me and my big brother included.
For me it all started the night before because I still hadn’t changed back to my normal gearing (52/42/12) from my mountain gearing (52/39/13). I rode across the Pyrenees last summer and once I got back I never got around to changing the gearing back, but now I’m back and riding as never before.
For the last couple of months I have been training indoors (Spinning) riding steady at 75% -> 85% of my maximal heartrate and it seems to have worked for me. I feel stronger than normally starting out. Nice. The new Polar 725 watch I bought last year has been a real help since it allows me to monitor my training using procentages instead of the heartrate.
I also allows me to transfer the data to the computer where I keep a log of my training. Below is an example from my trip to the Pyrenees. The example shows three curves – one for heartrate, one for speed and a third for altitude.

Generic Lotus Notes export library
I finally got fed up writing ad-hoc export functions for applications so I have written a generic export library for Lotus Notes. The library is written in LotusScript and can be applied to any database.
Below I’ll discuss the concepts I have defined and show how the code is used.
The export library consists of four core concepts that translate into four core (abstract) classes:
|
|
Below I’ll explain each concept in a little more detail.
|
OutputStream: In the most simple form this is a thin wrapper around the built in NotesStream class. The class has been wrapped since it allows me to subclass OutputStream while keeping the classes that use OutputStream unaware of the differences. I have defined three sub-classes so far:
ExportSource:
ExportStrategy:
ExportFormatter:
|
|
You combine the above concepts to export data. If you need to export the selected documents to a CSV-file using the format of the current view you would combine:
- LineFileOutputStream pointing to a file on disk
- SelectedExportSource to export the documents the use as selected
- CsvExportStrategy to write the exported data as CSV
- ViewExportFormatter to format the data as the current view
Example 1:
Export selected documents based on a view to a CSV-file on disk.
Option Public
Option Explicit
Use "CLASS: ExportSource"
Use "CLASS: OutputStream"
Use "CLASS: ExportFormatter"
Use "CLASS: ExportStrategy"
Sub Initialize
'declarations
Dim session As New NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Set db = session.GetDatabase("", "export_db.nsf")
Set view = db.GetView("ExportDocuments")
'we want to export selected documents only
Dim es As New SelectedExportSource()
'we want to format the documents as the current view (notesTestDocuments)
Dim formatter As New ViewExportFormatter(Nothing, "notesTestDocuments", Nothing)
'the documents should be written to a file replacing any existing file
Dim out As New LineFileOutputStream("d:\export.csv", True)
Call out.Open()
'export the data as CSV to the created OutputStream and the ExportSource
Dim strategy As New CsvExportStrategy(out, es)
Call strategy.Export(formatter, True)
'close the OutputStream
Call out.Close()
End Sub
Example 2:
Export all documents in a view to a richtext item on a document as XML.
Option Public
Option Explicit
Use "CLASS: ExportSource"
Use "CLASS: OutputStream"
Use "CLASS: ExportFormatter"
Use "CLASS: ExportStrategy"
Sub Initialize
'declarations
Dim ws As New NotesUIWorkspace
Dim session As New NotesSession
Dim db As NotesDatabase
Dim view As NotesView
Dim doc As NotesDocument
Dim rt As NotesRichTextItem
'get current database and view
Set db = session.CurrentDatabase
Set view = ws.CurrentView.View
'we want to export all documents in the current view
Dim es As New ViewExportSource(view)
'we want to format the documents as the current view (notesTestDocuments)
Dim formatter As New ViewExportFormatter(view, "", Nothing)
'the documents should be written to a rich text item
Set doc = db.CreateDocument
Call doc.ReplaceItemValue("Form", "TestDocument")
Call doc.ReplaceItemValue("Title", "XML Export " + Now)
Set rt = New NotesRichTextItem(doc, "Body")
Dim out As New RichTextOutputStream(rt)
Call out.Open()
'export the data as XML to the created OutputStream and the ExportSource
Dim strategy As New XmlExportStrategy(out, es)
Call strategy.Export(formatter, True)
'close the OutputStream
Call out.Close()
'save document
Call doc.Save(True, False)
End Sub
Since some exports (i.e. selected documents as CSV to a file) are done quite frequently I have defined some helper classes (really based on the Facade pattern). These helper classes are called Exporters and wrap the above example 1 on one line of code:
Option Public
Option Explicit
Use "CLASS: Exporter"
Sub Initialize
Dim exporter As New CsvExporter("d:\export.csv", "notesTestDocuments", True)
End Sub
Team Studio Script Browser
This FREE add-on is a must have. It installs as a toolbar button and lets you browse all LotusScript classes and see where the classes are referenced.
LotusScript class: FileWriter for R6.x
Code:
'*** Constants ***
Private Const DEFAULT_CHARSET$ = "ISO-8859-1"
'/**
' * Base FileWriter class. Normal usage scenario would we:
' * 1. Dim a new FileWriter using the filename and whether to replace any existing file.
' * 2. (Optional) Set the character set to use if different from ISO-8859-1.
' * 3. Call the Open() method to open the FileWriter.
' * 4. Call the Write(Variant) method to write data to the file.
' * 5. Call the Close() method to close the FileWriter.
' *
' * @version 1.0 (16 December 2004)
' * @author lekkim@it-inspiration.dk
' * @author it-inspiration aps
' */
Public Class FileWriter
'declarations
Private pFilename As String
Private pReplaceExisting As Boolean
Private pStream As NotesStream
Private pCharset As String
'/**
' * Constructor.
' */
Public Sub New(filename As String, replace_existing As Boolean)
Me.pFilename = filename
Me.pReplaceExisting = replace_existing
End Sub
'/**
' * Destructor.
' */
Public Sub Delete()
'make sure the stream has been closed
Call Me.Close()
End Sub
'/**
' * Sets the charset to use.
' */
Public Property Set Charset(charzet As String)
Me.pCharset = charzet
End Property
'/**
' * Opens the file.
' */
Public Sub Open()
'declarations
Dim session As New NotesSession
Dim rc As Boolean
'cannot open an open stream
If Not (Me.pStream Is Nothing) Then
Exit Sub
End If
'create stream
Set Me.pStream = session.CreateStream()
'should we replace ?
If Me.pReplaceExisting Then
'set up error handling
On Error Goto catch_fileexist
'does the file exist already
If Filelen(Me.pFilename) Then
'the file exists - delete it
Kill Me.pFilename
End If
Goto finally_fileexist
catch_fileexist:
'the file doesn't exist
Resume finally_fileexist
finally_fileexist:
'reset error handling
On Error Goto 0
End If
'try and open the file
If Me.pCharset "" Then
'use custom charset
rc = Me.pStream.Open(Me.pFilename, Me.pCharset)
Else
'use default charset
rc = Me.pStream.Open(Me.pFilename, DEFAULT_CHARSET)
End If
'did we open the file correctly ?
If Not rc Then
'could not open the file
Error 9999, "Unable to open file: " + Me.pFilename
End If
End Sub
'/**
' * Closes the file.
' */
Public Sub Close()
If Not (Me.pStream Is Nothing) Then
Call Me.pStream.Close()'
Set Me.pStream = Nothing
End If
End Sub
'/**
' * Writes text to the writer.
' */
Public Sub Write(buffer As Variant)
'make sure the stream is open
If Me.pStream Is Nothing Then
Error 9999, "The FileWriter hasn't been opened yet or has been closed."
End If
If Typename(buffer) = "STRING" Then
'write as text
Call Me.pStream.WriteText(buffer)
Else
'write as bytes
Call Me.pStream.Write(buffer)
End If
End Sub
End Class
Public Class LineFileWriter As FileWriter
'/**
' * Constructor.
' */
Public Sub New(filename As String, replace_existing As Boolean), FileWriter(filename, replace_existing)
End Sub
'/**
' * Overrides the parent implementation to make sure text is written as
' * lines. Also a check is made that only strings are written to to
' * the writer.
' *
' */
Public Sub Write(buffer As Variant)
'make sure the stream is open
If Me.pStream Is Nothing Then
Error 9999, "The FileWriter hasn't been opened yet or has been closed."
End If
If Typename(buffer) = "STRING" Then
'write as text
Call Me.pStream.WriteText(buffer, EOL_PLATFORM)
Else
'only allow text
Error 9999, "You may only write strings."
End If
End Sub
End Class
LotusScript class: LocationDocument
Example – get info from current location document:
Dim l As New LocationDocument("")
Msgbox l.EmailAddress
Example – get info from named location document:
Dim l As New LocationDocument("Office")
Msgbox l.EmailAddress
Code:
'/**
' * LotusScript class for interacting with location documents
' * in the personal name and address book.
' */
Public Class LocationDocument
'declarations
Private pSession As NotesSession
Private pDb As NotesDatabase
Private pDoc As NotesDocument
'/**
' * Constructor
' */
Public Sub New(get_location As String)
'declarations
Dim viewNab As NotesView
Dim nn As NotesName
Dim ini_location As String
Dim location As String
Dim comma As Integer
'get session
Set Me.pSession = New NotesSession()
If get_location = "" Then
'get the location from notes.ini
ini_location = Me.pSession.GetEnvironmentString("Location", True)
'parse out the location name if none specifed in the constructor
comma = Instr(1, ini_location, ",")
location = Mid$(ini_location, 1, comma-1)
Else
'use supplied location name
location = get_location
End If
'abbreviate the name
Set nn = New NotesName(location)
location = nn.Abbreviated
'get database and view
Set Me.pDb = Me.pSession.GetDatabase("", "names.nsf")
Set viewNab = Me.pDb.GetView("Locations")
'lookup location document
Set Me.pDoc = viewNab.GetDocumentByKey(location, True)
If Me.pDoc Is Nothing Then
Error 9999, "Location document not found in names.nsf"
End If
End Sub
'/**
' * Saves.
' */
Public Sub Save()
Call Me.pDoc.Save(False, False)
End Sub
'/**
' * Property to get the backend document.
' */
Public Property Get Document As NotesDocument
Set Document = Me.pDoc
End Property
'/**
' * Property to get the e-mail address.
' */
Public Property Get EmailAddress As String
EmailAddress = Me.pDoc.GetItemValue("ImailAddress")(0)
End Property
'/**
' * Returns the name of the directory server.
' */
Public Property Get DirectoryServer As NotesName
Dim nn As New NotesName(Me.pDoc.GetItemValue("DirectoryServer")(0))
Set DirectoryServer = nn
End Property
'/**
' * Sets the name of the directory server.
' */
Public Property Set DirectoryServer As NotesName
Call Me.pDoc.ReplaceItemValue("DirectoryServer", DirectoryServer.Canonical)
End Property
'/**
' * Returns the name of the Sametime server.
' */
Public Property Get SametimeServer As NotesName
Set SametimeServer = New NotesName(Me.pDoc.GetItemValue("SametimeServer")(0))
End Property
'/**
' * Sets the name of the Sametime server.
' */
Public Property Set SametimeServer As NotesName
Call Me.pDoc.ReplaceItemValue("SametimeServer", SametimeServer.Canonical)
End Property
End Class
SPOC Utility Agents
Copy companies:
Sub Initialize
Dim s As New NotesSession
Dim dbTarget As NotesDatabase
Dim dbSource As NotesDatabase
Dim docSource As NotesDocument
Dim docTarget As NotesDocument
Dim viewSource As NotesView
Dim viewTarget As NotesView
Dim copy_count As Integer
Set dbSource = s.CurrentDatabase
Set dbTarget = s.GetDatabase("server", "spoc.nsf")
Set viewTarget = dbTarget.GetView("lookupMainFirmById")
Set viewSource = dbSource.GetView("lookupMainFirmById")
viewTarget.AutoUpdate = False
viewSource.AutoUpdate = False
Set docSource = viewSource.GetFirstDocument
While Not (docSource Is Nothing)
Set docTarget = viewTarget.GetDocumentByKey(docSource.ID(0), True)
If docTarget Is Nothing Then
copy_count = copy_count + 1
Call docSource.CopyToDatabase(dbTarget)
End If
Set docSource = viewSource.GetNextDocument(docSource)
Wend
Msgbox "Copy count=" & copy_count
End Sub
Copy contacts:
Sub Initialize
Dim s As New NotesSession
Dim dbTarget As NotesDatabase
Dim dbSource As NotesDatabase
Dim docSource As NotesDocument
Dim docTarget As NotesDocument
Dim viewSource As NotesView
Dim viewTarget As NotesView
Dim copy_count As Integer
Set dbSource = s.CurrentDatabase
Set dbTarget = s.GetDatabase("server", "spoc.nsf")
Set viewTarget = dbTarget.GetView("lookupContactsByUnique")
Set viewSource = dbSource.GetView("lookupContactsByUnique")
viewTarget.AutoUpdate = False
viewSource.AutoUpdate = False
Set docSource = viewSource.GetFirstDocument
While Not (docSource Is Nothing)
Set docTarget = viewTarget.GetDocumentByKey(docSource.ContactUnique(0), True)
If docTarget Is Nothing Then
copy_count = copy_count + 1
Call docSource.CopyToDatabase(dbTarget)
End If
Set docSource = viewSource.GetNextDocument(docSource)
Wend
Msgbox "Copy count=" & copy_count
End Sub
Copy e-mails:
Sub Initialize
Dim s As New NotesSession
Dim dbTarget As NotesDatabase
Dim dbSource As NotesDatabase
Dim docSource As NotesDocument
Dim docTarget As NotesDocument
Dim viewSource As NotesView
Dim viewTarget As NotesView
Dim copy_count As Integer
Dim docEmailSource As NotesDocument
Dim docEmailTarget As NotesDocument
Dim dc As NotesDocumentCollection
Set dbSource = s.CurrentDatabase
Set dbTarget = s.GetDatabase("server", "spoc.nsf")
Set viewTarget = dbTarget.GetView("lookupContactsByUnique")
Set viewSource = dbSource.GetView("lookupContactsByUnique")
viewTarget.AutoUpdate = False
viewSource.AutoUpdate = False
Set docSource = viewSource.GetFirstDocument
While Not (docSource Is Nothing)
'find contact in target spoc
Set docTarget = viewTarget.GetDocumentByKey(docSource.ContactUnique(0), True)
'get responses
Set dc = docSource.Responses
Set docEmailSource = dc.GetFirstDocument
While Not (docEmailSource Is Nothing)
'copy
Set docEmailTarget = docEmailSource.CopyToDatabase(dbTarget)
Call docEmailTarget.Save(True, False)
'make response
Call docEmailTarget.MakeResponse(docTarget)
'increment count
copy_count = copy_count + 1
'get next
Set docEmailSource = dc.GetNextDocument(docEmailSource)
Wend
'get next
Set docSource = viewSource.GetNextDocument(docSource)
Wend
Msgbox "Copy count=" & copy_count
End Sub