IBM®
Skip to main content
    Country/region select      Terms of use
 
 
   
     Home      Products      Services & solutions      Support & downloads      My account     

developerWorks  >  Lotus  >  Forums & community  >  Best Practice Makes Perfect

Best Practice Makes Perfect

A collaboration with Domino developers about how to do it and how to get it right in Domino

As I have time, I'm working on a couple of the tools I mentioned previously -- the design element search and the toolkit of useful functions for developers. As I go along, I'm finding there are little bits that people might be able to reuse as workarounds or augmentations.

My latest dilemma: I needed data written into a stream using an appropriate character set. The process I'm using (MIME decoding of base64 data) was writing binary data into the stream and I knew it was really UTF-8 character data, but there was no way to tell the stream that, so that the data could be read out as text. The problem: you can only associate a character set with a stream by connecting the stream to a file. Clearly, then, we need a temporary file somewhere. But where to put it? The natural solution is to make it in a temp directory somewhere. I also want it to work on all the supported Notes client platforms, and each of these has a different way to locate temporary directories, as well as different rules for constructing filepaths. So it boils down to three problems:
1.        Find a temporary folder to put the files.

2.        Construct a filepath by adding a unique filename to the filepath.

3.        Manage the resulting file and stream.

I decided to write my temp file in the Notes temp folder, using a filename supplied by the @Unique function. To locate that folder, there is no built-in LotusScript function, but there's a C call in the 'notes' library that you can call. You have to declare the function using the right library name for each of the platforms you want to support, then at runtime, call the right one for your platform.

Declare Function w32_OSGetSystemTempDirectory Lib "nnotes" Alias "OSGetSystemTempDirectory" ( Byval S As String, Byval wBufLen As Integer) As Integer
Declare Function mac_OSGetSystemTempDirectory Lib "NotesLib" Alias "OSGetSystemTempDirectory" ( Byval S As String, Byval wBufLen As Integer) As Integer

Declare Function linux_OSGetSystemTempDirectory Lib "libnotes.so" Alias "OSGetSystemTempDirectory" ( Byval S As String, Byval wBufLen As Integer) As Integer

Const ERR_UNSUPPORTED_PLATFORM = 20300 ' or other value you choose.

Function GetNotesTempDirectory() As String

' Returns the path of the temporary directory used by Notes.

' Not same as system or user temp dir that you can get e.g. with Environ("TEMP") in Windows.

' Main reasons to use this instead: works crossplatform, and partitioned servers each need

' their own temp dir to avoid interfering with each other.

Dim session As New NotesSession

Dim d As String * 256

Dim s%

Select Case session.Platform

Case "Linux"

  s% = linux_OSGetSystemTempDirectory(d, 255)

Case "Macintosh"

  s% = mac_OSGetSystemTempDirectory(d, 255)

Case "Windows/32"

  s% = w32_OSGetSystemTempDirectory(d, 255)

Case Else

  Error ERR_UNSUPPORTED_PLATFORM, "In GetNotesTempDirectory, platform not supported: " & session.Platform

End Select

GetNotesTempDirectory = Left$(d, s%)

End Function

Similarly, building a filepath requires different code depending on the OS. In each case, we can append the filename to the folder path, but must delimit them with some character which is different on different platforms.

Function PathDelimiter() As String
Static SdirChar$

If SdirChar = "" Then

  Dim session As New NotesSession

  Select Case session.platform

  Case "Macintosh"

     SdirChar = "/"

  Case "OS/2v1", "OS/2v2", "MS-DOS", "Windows/16", "Windows/32"

     SdirChar = "\"

  Case "UNIX", "Linux", "OS/400"

     SdirChar = "/"

  Case Else

     Error 13445, "Unknown platform: " & session.Platform

  End Select

End If

PathDelimiter = SdirChar

End Function

Now, to manage the stream object and to make sure the temporary file gets deleted when we no longer need it, a class. I use OOP here to keep everything about managing the temp file and stream together in one place, and to take advantage of the Delete event, which runs even if the code terminates abnormally, to close and get rid of the temp file.

Class TempFileStream
m_stream As NotesStream

m_filepath As String

 
Sub New(char_set As String, Byval suffix As String)

   Dim session As New NotesSession

   If suffix = "" Then suffix = "dat"

   Set m_stream = session.CreateStream

   Dim unik

   unik = Evaluate({@Unique})

   Dim strTempPath$, strDelim$

   strTempPath = GetNotesTempDirectory()

   strDelim = PathDelimiter

   If Right(strTempPath, 1) <> strDelim Then strTempPath = strTempPath & strDelim

   m_filepath = strTempPath & unik(0) & "." & suffix

   m_stream.Open m_filepath, char_set

   m_stream.Truncate

End Sub

 
Public Property Get Stream As NotesStream

   Set Stream = m_stream

End Property

 
Public Property Get Text As String

   m_stream.Position = 0

   Text = m_stream.ReadText

End Property

 
Sub Delete

   On Error Resume Next

   m_stream.Close

   Delete m_stream  ' note this will clear the stream object from all variables, in case you made a copy.

   Kill m_filepath

End Sub

End Class

Once you've got all this, it's easy to create the stream and associate a particular character set.

Dim tfs As New TempFileStream("UTF-8", "xml")
Dim stream As NotesStream

Set stream = tfs.Stream

You must keep the TempFileStream object in scope while using the stream it creates. Since its destructor deletes the temp file and stream, copies of the Stream property become invalid at that time.

Andre Guirard | 30 September 2007 10:14:24 PM ET | Plymouth, MN, USA | Comments (7)

Search this blog 

Disclaimer 

    About IBM Privacy Contact