• Browse Blogs
  • My Blog
  • My Updates

+Tags Get help with tags?

  • View as cloud  | list

+ Similar Blogs

photo

Yellow is the...

72 Entries |  Tim Tripcony
Updated 
RatingsRatings 2     CommentsComments 34
photo

Lotus Nut

111 Entries |  Chris Whisonant
Updated 
RatingsRatings 23     CommentsComments 157
photo

Patrick Picar...

62 Entries |  Patrick Picard
Updated 
RatingsRatings 2     CommentsComments 112
photo

Urs Meli

42 Entries |  Urs Meli
Updated 
No RatingsRatings 0     CommentsComments 48
photo

TexasSwede

109 Entries |  Karl-Henry Martinsso...
Updated 
No RatingsRatings 0     CommentsComments 94

+ Bookmarks

+ Blog Authors  

1 - 10 of 10
  • Previous
  • Next
  • Page   1

LS Version @WebDBName

Peter Presnell |   | Tags:  .dominoframework lotusscript | Comments (3)  |  Visits (837)

The @WebDBName function provides a quick way to get a reference to the current database in a format that can be used as a URL.  I am working on an application that needed much the same thing except I needed a link to another Notes database.  I decided to create a LS equivalent of the @WebDBName function that takes a single parameter.  This parameter can be Nothing (current database), String (filepath of database) or a NotesDatabase object and returns the URL for that database.  This function will be added to the next release of the  Domino.@Functions namespace (possibly released on OpenNTF this weekend).

'/** ' * Returns the name of a Notes database encoded for URL inclusion. ' * ' * @author Peter Presnell ' * @param Source Database path - Nothing = current database ' */ Function atfWebDBName(Source As Variant) As String Dim Filepath As String Select Case Typename(Source) Case "NOTESDATABASE" FilePath$ = Source.FilePath$ Case "STRING" FilePath$ = Cstr(Source) Case "OBJECT" FilePath$ = Session.CurrentDatabase.FilePath$ End Select atfWebDBName$ = atfReplaceSubstring(FilePath$,Split("\\: ",":"),Split("/:%20",":")) End Function
Note: In some cases an alternative to the above could be to use the NotesDatabase.HttpURL property.
The code for the atfReplaceSubstring (LS version of @ReplaceSubstring) is as follows:-
'/** ' * Replaces specific words or phrases in a string with new words or phrases that you specify ' * ' * @author Peter Presnell ' * @param Source he string whose contents you want to modify. ' * @param Search A list containing the words or phrases that you want to replace. ' * @param ReplaceTo A list containing the replacement words or phrases. ' * @return The sourceList, with any values from fromList replaced by the corresponding value in toList. ' * If none of the values in fromList matched the values in sourceList, then sourceList is returned unaltered. ' */ Function atfReplaceSubstring(Source As Variant, Search As Variant, ReplaceTo As Variant) As Variant Dim Results As Variant ' Interim results Dim Index As Long Dim ReplaceToItem As Variant ' Replacement value for match Try: On Error Goto Catch If Isarray(Source) Then Redim Results(Lbound(Source) To Ubound(Source)) For Index& = Lbound(Source) To Ubound(Source) Results(Index&) = atfReplaceSubstring(Source(Index&),Search,ReplaceTo) Next Index& atfReplaceSubstring = Results Else atfReplaceSubstring = Source If Isarray(Search) Then For Index& = Lbound(Search) To Ubound(Search) If Isarray(ReplaceTo) Then If Index& > Ubound(ReplaceTo) Then ReplaceToItem = ReplaceTo(Ubound(ReplaceTo)) Else ReplaceToItem = ReplaceTo(Index&) End If Else ReplaceToItem = ReplaceTo End If atfReplaceSubstring = atfReplaceSubstring(atfReplaceSubstring,Search(Index&),ReplaceToItem) Next Index& Else ' Covert all parameters to strings If Isarray(ReplaceTo) Then ReplaceToItem = Cstr(ReplaceTo(0)) Else ReplaceToItem = Cstr(ReplaceTo) End If Source = Cstr(Source) Search = Cstr(Search) ' Locate each occurence of search item and replace with replacement item If Search <> ReplaceToItem Then While Instr(atfReplaceSubstring, Search) > 0 atfReplaceSubstring = Left$(atfReplaceSubstring, Instr(atfReplaceSubstring, Search) - 1) + ReplaceToItem +_ Right$(atfReplaceSubstring, Len(atfReplaceSubstring) - Instr(atfReplaceSubstring, Search) - Len(Search) + 1) Wend End If End If End If Exit Function Catch: Stop Call ReportError Exit Function End Function
No RatingsRatings 0

DominoBES class

Peter Presnell |   | Tags:  java bes blackberry .dominoframework | Comments (0)  |  Visits (1,242)
I am now in the process of extending the .Domino Framerwork to support the publishing of Notes applications on a Blackberry client.  A new DominoBES class has been added as a way of allowing Notes applications to communicate with a Blackberry device via the Blackberry Enterprise Server (BES).  Unlike the rest of the framework, this class has been developed in Java due to the need to send an HTTP POST request.  The first method - browserChannelPush (see below) provides a wrapper for executing a Channel Push, effectively adding an icon to the Blackberry device, which when selected invokes the nominated URL.

import java.net.*;
public class DominoBES
{
  public void DominoBES()
  {
  }
  public void browserChannelPush(String mdsHost, int mdsPort,String email,String docURL, String unreadIconURL, String readIconURL, String pushID, String pushTitle)
  {
    try
    {
      URL mdsURL =  new URL("http",mdsHost,mdsPort,"push?DESTINATION=" + email + "&PORT=7874&REQUESTURI=/");
      HttpURLConnection connection = (HttpURLConnection)mdsURL.openConnection();
      connection.setRequestMethod("Post");
      connection.setRequestProperty("X-RIM-Push-Type","Browser-Channel");
      connection.setRequestProperty("X-RIM-Push-Title",pushTitle);
      connection.setRequestProperty("X-RIM-Push-Channel-ID",pushID);
      connection.setRequestProperty("X-Rim-Push-Read-Icon-URL",readIconURL);
      connection.setRequestProperty("X-Rim-Push-Unread-Icon-URL",unreadIconURL);
      connection.setRequestProperty("Content-Location",docURL);
    }
    catch (Exception e)
    {
      System.err.println("Push failure");
      e.printStackTrace(System.err);
    }
  }
}

import java.net.*;
public class DominoBES
{
  public void DominoBES()
  {
  }
  public void browserChannelPush(String mdsHost, int mdsPort,String email,String docURL, String unreadIconURL, String readIconURL, String pushID, String pushTitle)
  {
    try
    {
      URL mdsURL =  new URL("http",mdsHost,mdsPort,"push?DESTINATION=" + email + "&PORT=7874&REQUESTURI=/");
      HttpURLConnection connection = (HttpURLConnection)mdsURL.openConnection();
      connection.setRequestMethod("Post");
      connection.setRequestProperty("X-RIM-Push-Type","Browser-Channel");
      connection.setRequestProperty("X-RIM-Push-Title",pushTitle);
      connection.setRequestProperty("X-RIM-Push-Channel-ID",pushID);
      connection.setRequestProperty("X-Rim-Push-Read-Icon-URL",readIconURL);
      connection.setRequestProperty("X-Rim-Push-Unread-Icon-URL",unreadIconURL);
      connection.setRequestProperty("Content-Location",docURL);
    }
    catch (Exception e)
    {
      System.err.println("Push failure");
      e.printStackTrace(System.err);
    }
  }
}

No RatingsRatings 0

Blackberry JavaScript Limitations

Peter Presnell |   | Tags:  blackberry javascript | Comments (0)  |  Visits (885)

The following is a list of limitations I have found in trying to implement JavaScript to run in Domino Web applications running on a BlackBerry device:-

  1. Any JavaScript placed in the JS Header
  2. eval statement
  3. control.length
  4. control.disabled
No RatingsRatings 0

LotusScript Version of @DBColumn

Peter Presnell |   | Tags:  @dbcolumn .dominoframework | Comments (0)  |  Visits (818)
The .Domino Framework provides the LotusScript equivalent for many @Functions.  These can be found in the Domino.@Functions namespace.
Note: Because LotusScript does not allow the "@" character to be used for function names I have adopted the naming standard of atf (AT Function).
I have just expanded the functionality of the atfDBColumn to provide support for NotesDocumentCollections.  This may not be the most efficient way to achieve the result, but it is a very fast way to code the need to get a list of field values from a database/view/document collection - e.g. when prototyping.  The expanded atfDBColumn method provides the ability to:-
  1. Pass either a database, view, or document collection as the source.
  2. Request either the contents of a column number or fieldname to be returned.
'/**
' * Returns an array containing the list of values for a specific column/field for any collection of documents
' *
' * @author Peter Presnell
' * @param ClassCache Not used
' * @param Database NotesDatabase object, server/filepath, or replicaid id, or Nothing (current database)
' * @param View NotesDocumentCollection, NotesView, name of view, or Nothing (All documents in database)
' * @!param Column Column number or name of field corresponding to values to be returned
' * @return List of values
' */
Function atfDBColumn(ClassCache As Variant, Database As Variant,View As Variant, Column As Variant) As Variant

Dim iDB As New NotesDatabase("","") ' Database to perfrom lookup
Dim iCollection As Variant ' View/Document Collection used to perfrom lookup
Dim EntryList As NotesViewEntryCollection ' List of all entries in view
Dim Entry As NotesViewEntry ' Current entry in view
Dim Doc As NotesDocument ' Document that corresponds to current entry in view
Dim ColumnValues As Variant
Dim Results As Variant ' Interim results
Dim Index As Long ' Counter used to loop through array
Try:
On Error Goto Catch

' Setup database/view

Redim Results(0)
Select Case Typename(Database)
Case "NOTESDATABASE"
Set iDB = Database
Case "STRING"
Call iDB.OpenByReplicaID(Session.CurrentDatabase.Server,Cstr(Database))
Case "STRING ()"
If (Ubound(Database) = 1) Then
If Database(1) = "" Then Set iDB = Session.CurrentDatabase Else Call iDB.Open(Database(0),Database(1))
End If
End Select

Select Case Typename(View)
Case "NOTESDOCUMENTCOLLECTION"
Set iCollection = View
Case "NOTESVIEW"
Set iCollection = View
Set iDB = iCollection.Parent
Case "OBJECT"
If iDB Is Nothing Then Set iDB = Session.CurrentDatabase
Set iCollection = iDB.AllDocuments
Case "STRING"
If (iDB Is Nothing) Then Set iDB = Session.CurrentDatabase
Set iCollection = iDB.GetView(Cstr(View))
Case Else
Exit Function
End Select
If iCollection Is Nothing Then Error 1000, "View not found"

' Extract values

Select Case Typename(iCollection)
Case "NOTESDOCUMENTCOLLECTION":
Set Doc = iCollection.GetFirstDocument
While Not Doc Is Nothing
Select Case Typename(Column)
Case "INTEGER","LONG"
If (Ubound(Doc.ColumnValues) >= Cint(Column)-1) Then
ColumnValues = Doc.ColumnValues(Column-1)
If (Isarray(ColumnValues)) Then
Forall ColumnValue In ColumnValues
Redim Preserve Results(Index&)
Results(Index&) = ColumnValue
Index& = Index& + 1
End Forall
Else
Redim Preserve Results(Index&)
Results(Index&) = ColumnValues
Index& = Index& + 1
End If
End If
Case "STRING"
Redim Preserve Results(Index&)
If (Doc.HasItem(Cstr(Column))) Then
Results(Index&) = Doc.GetItemValue(Cstr(Column))(0)
Index& = Index& + 1
End If
End Select
Set Doc = iCollection.GetNextDocument(Doc)
Wend
Case "NOTESVIEW":
Set EntryList = iCollection.AllEntries
Set Entry = EntryList.getFirstEntry
While Not Entry Is Nothing
Select Case Typename(Column)
Case "INTEGER","LONG"
If (Ubound(Entry.ColumnValues) >= Cint(Column)-1) Then
ColumnValues = Entry.ColumnValues(Column-1)
If (Isarray(ColumnValues)) Then
Forall ColumnValue In ColumnValues
Redim Preserve Results(Index&)
Results(Index&) = ColumnValue
Index& = Index& + 1
End Forall
Else
Redim Preserve Results(Index&)
Results(Index&) = ColumnValues
Index& = Index& + 1
End If
End If
Case "STRING"
Redim Preserve Results(Index&)
Set Doc = Entry.Document
If (Doc.HasItem(Cstr(Column))) Then
Results(Index&) = Doc.GetItemValue(Cstr(Column))(0)
Index& = Index& + 1
End If
End Select
Set Entry = EntryList.getNextEntry(Entry)
Wend
End Select

atfDBColumn = Results
Exit Function

Catch:
Stop
Call ReportError
Exit Function

End Function
No RatingsRatings 0

Why I Bleed Yellow

Peter Presnell |   | Tags:  bleedyellow notes | Comments (0)  |  Visits (799)
image Simply put...  I bleed yellow because I am able to develop applications of high quality in a fraction of the time required for most other application development platforms.  That's right, I develop applications with Lotus Notes.  So on   Yellow Day   I thought I would outline some of the aids I now use that give me an advantage over and above the edge Lotus Notes already provides.

1) BA/BSAs
This might surprise a few people, but my number one aid is working as part of a small team with either a Business Analyst (BA), or Business/Systems Analyst  (BSA).  I have found that in larger corporations Lotus Notes is increasingly being caught up in greater demands for compliance and corporate governance.  Just Enough Governance is a great blog site on this topic.  While not all BA/BSAs can adapt to the subtle differences of Notes development (e.g. its speed), those that can make a huge difference to developer productivity. I happily allow them to handle all the documentation/compliance needs of my projects while I focus on understanding the requirements and writing the code.

2) Multiple Monitors
One day my chair ran over the video cable of my computer monitor at home.  I didn't notice and thought my monitor had simply blown up.  I chose the fast path solution of rushing down to my local computer store and buying a new monitor.  Later the original problem got noticed and my orginal monitor was soon working again (duh).  I then decided to connect both monitors.  I was so impressed with what I could now do I took my 2nd monitor into work so I could get these savings where it counted most.  Now I have three monitors at home and I insist on having two monitors where I work.  If possible my preference is to have at least one wide screen monitor as the extra width really helps when doing development (e.g. Notes 8 sidebar).  To give me increased flexibility I use USB DVI adapters that allow me to quickly plug one or more external monitors into my laptops.

3) Newsgator FeedDemon
You might already be using a better RSS feed reader.  But if you don't have one at all I would strongly urge you to get one.  The Notes 8 RSS reader is a good start but it is not great.  Newsgator provide an excellent feed reader at the perfect price (FREE)...  Since I started using a feed reader I have felt connected to an immense network of brilliant Lotus Notes minds.  I am presently monitoring 75 separate Lotus Notes feeds via my feed reader.  The software operates very much like my e-mail database (e.g. "in-box", folders, mail rules, search), except I am getting almost no spam.  If anything at all happens in the Notes world my feed reader soon alerts me wherever I may be (home/work/travelling).  If you are unable/unwilling to get access to a feed reader, the next best thing is planetlotus.org.

4) OOP/Framework
After spending a period doing C# development I found it impossible to return to Notes programming without doing ALL my LotusScript in Object Oriented Programming.  Procedural programming had become too counter-intuitive.  One of the advantages of OOP is that it allows me to develop a framework so that the generic code can be inherited from the framework and I only need to focus on the code specific to each application.  Frameworks can vary in size and complexity.  I have developed my own framework (.Domino Framework) which is now an OpenNTF project.  I genuinely believe that OOP/Framework allows me to build Notes applications 50% faster than before.  It is not unusual for me to be able to deliver a prototype application within 24 hours of the first requirements session with the users.   Sometimes even the most ardent "Notes-haters" find themselves taking a new look at this platform because they can't argue with the results they get.

5) (FREE) TeamStudio Tools
One of the downsides of OOP/LotusScript is that the present Domino Developer IDE SUCKS when it comes to coding classes.  Notes 8.5.1 (or beyond???) will address this with a new Eclipse IDE.  In the interim TeamStudio provide two free tools that can be a big help to navigate the huge chunk of code that now resides in the Declaraions sections of each LotusScript library.  ScriptBrowser is a Class browser that allows you to see your class structures and quickly jump to a specific class/proipery/method.  LSGoto allows you to quickly jump to a specific line in a LotusScript module.  Teamstudio also market a range of Notes productivity tools.  I am a big time user of Design Manager, CIAO, Configurator, and Delta and use some of their other products from time to time (Note: these tools are not FREE).

6) MyEclipse
Apart from LotusScript, the Domino Developer IDE also sucks when it comes to maintaining code written in Java, JavaScript, HTML, CSS, or XML.  Domino Designer also does not provide an image editor.  To meet these needs I have recently started using MyEclipse This tool is Eclipse based and looks remarably similar to the new Domino 8.5 IDE.  No surprise given they are both Eclipse based.  The basic version costs $30 and a professional version costs a mere $60.

7) Web Browser Tools
While I probably spend less than 20% of my time developing Domino Web applications, when I do, I find I get great value out of developer toolbars.  These toolbars allow me to see what is going on inside my HTML.  Microsoft's Internet Explorer Toolbar and the Firefox add-on Web Developer meet most of my needs.   Both products are free.

8) Blackberry
No, I don't do Blackberry development on my Blackberry, but this device does save me a lot of time by allowing me to use otherwise dead time to great effect processing my mail,  browsing web sites etc.  I have started developing applications for delivery to Blacberry devices so it doesn't hurt to have a device.  I find the physical device is a little easier to control than the Blackberry simulator and it doesn't come with some of the simulator's limitations (e.g. all simulators have the same PIN and so only one can be connected at a time).

9) Bleedyellow Community
The Lotus911 folk have done a great job of bringing the Notes Developer community together via its bleedyellow Web site.  This site allows me to tap into the collective skills of the Lotus911 gurus and many of brilliant Notes developers who connect via the SameTime bleedyellow group.  None of the sites I work for have Lotus Connections so this site allows me to experience the product first hand, including the ability to create blog sites such as this.. (Having a blog site is definitely NOT a productivity aid!!!).

10) Non-Notes Development
Finally I would like to encourage all serious Notes developer who have not already done so to rack up some serious time (6+ months) doing development in a non-Notes development platform.  It is a great way to broaden your horizons as a programmer and the skills learnt can often be applied back to Notes development.  e.g. If you don't already do OOP then a period of time doing C#, VB.NET, or Java development will soon get you into the habit.  It may be hard to go back to LotusScript, because of its limitations as a OOP programming language, but you will appreciate the speed of Notes like never before.

No RatingsRatings 0

Building "Composite" Applications In Notes 6

Peter Presnell |   | Tags:  .dominoframework compositeapplications oop events | Comments (3)  |  Visits (817)

I am presently working on a project that requires coordination between separate components contained within a frameset.  In Notes 8 this would be considered a composite application but I need to implement this solution in Notes 6.0.  Fortuantely there has been some excellent articles recently posted by Tim TripconyJan Shulz , and Nathan T Freeman on the subject of remote event binding - an important part for creating composite applications.

I have now extended the .Domino Framework by adding a new DominoListener class.  This class is designed to listen for events that occur in a nominated Notes UI class.

Class DominoListener As DominoBaseClass Private iParent As Variant ' The object requesting a listener Private iTarget As Variant ' The UI object being monitored for one or more events Sub New(Parent As Variant,Target As Variant), DominoBaseClass(ENUM_CLASS__ABSTRACT + "DOMINOLISTENER") End Sub Property Get Parent As Variant Set Parent = iParent End Property Property Set Parent As Variant Set iParent = Parent End Property Property Get Target As Variant Set Target = iTarget End Property Property Set Target As Variant Set iTarget = Target End Property End Class

The DominoLIstener class is extended by DominoDocumentListener and DominoViewListener  classes designed to specifically listen for events in NotesUIDocument and NotuesUIView classes.  ( a DominoDatabaseListener may be added later).

Class DominoViewListener As DominoListener Sub New(Parent As Variant,Target As Variant) Call DominoBaseClass..ValidateClass(ENUM_CLASS__ABSTRACT,"DOMINOVIEWLISTENER") If (Not Typename(Target) = "NOTESUIVIEW") Then End Set iTarget = Target End Sub End Class Class DominoDocumentListener As DominoListener Sub New(Parent As Variant,Target As Variant) If (Not Typename(Target) = "NOTESUIDOCUMENT") Then End Set iTarget = Target End Sub End Class

The above classes are all abstract classes and demonstrate the use of a DominoBaseClass covered in a previous blog to implement/enforce class abstraction.

To wire two objects together I need to create a Listener class that defines the events to be monitored and the action to take when the event occurs.  The following demonstrates a single event, but I could just as easily monitor multiple events by adding additional delegates/methods to the code.

Class OpenFeatureListener As DominoDocumentListener Sub New(Parent As Variant,Target As Variant) If Not Parent Isa "DominoFeature" Then End Set iParent = Parent On Event PostOpen From Target Call DelegatePostOpen End Sub Sub DelegatePostOpen(Source As NotesUIDocument) Dim DesignListUIDoc As NotesUIDocument Dim DesignListDoc As NotesDocument Dim DesignList As DominoDesignList Set DesignListDoc = New NotesDocument(Source.Document.ParentDatabase) Call UIW.SetTargetFrame(ENUM_FRAME_DESIGN_LIST) Set DesignListUIDoc = UIW.ComposeDocument("","",ENUM_FORM_DESIGN_LIST) Set DesignList = New DominoDesignList(DesignListUIDoc) DesignList.Title$ = iParent.Title$ Call DesignListUIDoc.Refresh() End Sub End Class

The listener is invoked in the parent object with a simple statement

Set Handler = New OpenFeatureListener(Me,Source)

Within a composite application an object may have the need to observe multiple objects.  I have therefore created a DominoBroker class as a container for Listeners.

Class DominoBroker Private iListeners As Variant Sub Register(Listener As Variant) If Not Listener Isa "DominoListener" Then End If Not Isarray(iListeners) Then Redim iListeners(0) Else Redim Preserve iListeners(Ubound(iListeners)+1) Set iListeners(Ubound(iListeners)) = Listener End Sub End Class

This is not unlike Nathan's totally cool concept of a unicache Ideally I would like to have a single Broker for an entire Notes session, but presently I seem to be constrained by LotusScript to only being able to get a handle on UI objects that are currently active (one NotesUIDocument, one NotesUIView) or when LotusScript code launches a UI object (e.g. UIW.EditDocument).  So far I have only been able to share the love (broker) around between UI objects that have been loaded by a common UI object (class). Documents opened in preview mode from a view, embedded views etc. are a Remote event black hole.

Combining the above with framesets (to contruct the presentation layer) allows me to implement design patterns in Notes 6 very similar to Notes 8 composite applications.  The down side(?) is that I am restricted to only wiring Notes components and only for some very specific scenarios.  On the plus side this is all Notes code with no Eclipse required.

Note: The above is designed for Notes 6/7 only.  Notes 8 provides additional classes to support composite applications as well as a composite application editor.

No RatingsRatings 0

Document Collection

Peter Presnell |   | Tags:  .dominoframework notesdocumentcollection | Comments (2)  |  Visits (805)

The NotesDocumentCollection class has a few attributes that can be rather annoying:-

  1. The Notesdatabase object from which the NotesDocumentCollection is derived must remain in memory.  e.g. A function that returns a NotesDocumentCollection will return an empy object if the NotesDatabase used to create the collection is local to the function.  The NotesDatabase must be either passed as a parameter to the function, or be a global variable.
  2. Documents can only be added to the collection if they are from the same NotesDatabase from which the NotesDocumentCollection was created.

As a way around these issues the following represents an alternate way  to represent a document collection.  This is to store the collection as an array of NotesURLs.  Not only does this technique remove the issues above but it also has the added advantage that it can be easily serialized. e.g. Being an array of strings the values can be easily stored as a field in a Notes document or can be passed back from a Web service.  Of course your application must understand this representation of a document collection and how to process such a collection.

The following function demonstrates how an array of NotesURLs can be created from an Notesdocumentcollection:-

' */ ' * Convert collection to an array of NotesURLs ' */ Function toArray(iDocumentCollection As NotesDocumentCollection) As Variant Dim Doc As NotesDocument Dim Results As Variant Set Doc = iDocumentCollection.GetFirstDocument While Not Doc Is Nothing If Isarray(Results) Then Redim Preserve Results(Ubound(Results)+1) Else Redim Results(0) Results(Ubound(Results)) = Doc.NotesURL$ Set Doc = iDocumentCollection.GetNextDocument(Doc) Wend toArray = Results End Function

I favor the NotesURL format for representing a document because of the ease in which it can be converted to a NotesDocument via the NotesSession.Resolve method.  Unlike a NotesDocumentCollection the array of NotesURLs is enumerated so requires less code to process:-

Forall DocURL In Results Set Doc = Session.Resolve(DocURL$) ' code to process document End Forall

The DominoDocumentCollection class within the .Domino Framework provides a toArray method to convert an existing NotesDocumentCollection.  The constructor of the DominoDocumentCollection class is able to accept an array of NotesURLs to create a NotesDocumentCollection from the NotesURLs.  Note: If documents exist in multiple databases only documents from the first database found are added.

No RatingsRatings 0

Adding Abstract Classes To A Framework

Peter Presnell |   | Tags:  .dominoframework oop classes | Comments (2)  |  Visits (1,677)

After writing my blog about implementing abstract (and other) classes in LotusScript I started to think about ways to reduce the code that would be required to implement this into each and every abstract/sealed class in a framework.  I have now gone back to my own .Domino Framework and added a new base class that implements much of the logic for abstract/sealed classes (and interfaces). 

Class DominoClass
Sub New(Source As Variant)
Dim Params As Variant ' Parameters passed to this class
Select Case Typename(Source)
Case "STRING"
Params = Fulltrim(Split(Source))
If (Ubound(Params) = 1) Then Call ValidateClass(Params(0),Params(1))
End Select
End Sub
'/**
' * Validate a class to ensure it conforms to rules for special class types
' */
Sub ValidateClass(ClassType As String,ClassName As String)
Select Case ClassType$
Case ENUM_CLASS__ABSTRACT: ' Abstract classes cannot be implemented directly
If (Typename(Me) = ClassName$ )Then
Error ERROR_USER_FATAL,ClassName$ + " is abstract and cannot be implemented directly"
End ERROR_USER_FATAL
End If
Case ENUM_CLASS__INTERFACE: ' Interfaces cannot be implemented directly
If (Typename(Me) = ClassName$) Then
Error ERROR_USER_FATAL,ClassName$ + " is an interface and cannot be implemented directly"
End ERROR_USER_FATAL
End If
Case ENUM_CLASS__SEALED: ' Sealed classes cannot be extended
If (Typename(Me) <> ClassName$) Then
Error ERROR_USER_FATAL,ClassName$ + " is sealed and cannot be extended by " + Typename(Me)
End ERROR_USER_FATAL
End If
End Select

End Sub
End Class

Now any class that extends this class (directly or indirectly) can assert itself as being an abstract class, sealed class, or interface on one of two ways:

Constructor: The following  scenario can be used when the constructor shares the same footrpint as the base class (single parameter of type variant) and there is no need to pass the original parameter to any intermediate base/super class.  It work by directing the constructor of the base class to take an alternative value than the one passed to the extended class.

Class AbstractClass As DominoClass
Sub New(Source As Variant), DominoClass(ENUM_CLASS__ABSTRACT + " ABSTRACTCLASS" )
...
End Sub
End Class

Method: The alternative is to invoke the ValidateClass method directly

Class SealedClass As AbstractClass
Sub New(Source As Variant)
Call ValidateClass(ENUM_CLASS__SEALED,"SEALEDCLASS" )
End Sub
End Class
No RatingsRatings 0

Reducing Programming Language Differences

Peter Presnell |   | Tags:  vb.net lotusscript oop java c | Comments (2)  |  Visits (733)
One of the things that struck me when I attended my first C# programming class was the fact that the instructor was often switching between code examples written in either c# or VB.Net.  These two languages had evolved in such a way that in many ways they had become the same.  This means programmers in one language can more easily adapt to develop/maintain code in the other.  This started me thinking about the opportunity to write Notes applications in such a way that non-Notes developers could better make the transition to develop/maintain LotusScript code.  The same concept also holds true for java, which is not all that different to C#.  The following are some of the coding practices that can be applied to LotusScript to give them a look/feel more like these other programming languages.
Note: The goal here is coding consistency between programming languages.  These suggestions do absolutely nothing to improve the functional nature of the LotusScript code and actually increases the length of the resulting code. 

Object Oriented Programming:
Java, C#, and VB.Net are all examples of object oriented programming languges.  With LotusScript the use of OOP (e.g. classes) is optional.  If you get into the habbit of using OOP when developing Notes applications via LotusScript the chances are the code will be WAY more understandable to a java or .Net developer.  Note: Without a proper class editor for LotusScript it can be a little more painful to maintain code in classes but the pain does subside after a while and a new eclipse editor for LotusScript is not far away...

Error Handling:
LotusScript does not support the try/catch construct found in many modern programming languages, but it is possible to simulate this by adding a non-functional try label at the start of the code and always using catch as the error handling label.  This results in code block similar to the following:-
Try:
On Error Goto Catch
.... (normal code)
Exit Sub
Catch:
.... (error handling)
Exit Sub

This concept can be extended to include the optional finally block used for code to be executed after both normal completion or an error.
Try:
On Error Goto Catch
.... (normal code)
Goto Finally
Catch:
.... (error handling)
Resume Finally
Finally:
.... (final code)
Exit Sub

If... Then... Else
Both java and c# require conditional expressions be enclosed in parenthesese - with LotusScript this is optional.  For consistency make it habbit to use this optional capability of LotusScript.
If (iDocument Is Nothing) Then ... Else ... End If
Method Calls
When invoking a methods (sub or function) with zero parameters in c# or java it is a requirement to place empty parentheses at the end of the method name - with LotusScript this is optional.  Again, for consistency, make it a habbit to use this optional capability of LotusScript.  The use of parentheses helps to make methods distinct from properties.  Note: LotusScript also requires the somewhat redundant Call statement to be used with methods - but thats another story...
Call UIW.ReloadWindow()

Inheritence
Both java and C# support the this statement as a way of referring to methods/properties of the current class.  With VB.Net and LotusScript the equivalent statement is the me statement.  To refer to a property/method in a base/super class that has been overriden in the current class .. notation is used. While it is only ever necessary to use either statement when the same variable/method/property exists in different scopes, it is often a good idea to use either statement to make it clear wherever a method/property defined elsewhere in the class is being invoked.  This also provides a way to minimize the use of variable names like EmployeeName1 to avoid clashes with property names.
If (Me.EmployeeName$ <> EmployeeName$) Then Me.EmployeeName$ = EmployeeName$

If (baseclass..EmployeeName$ <> EmployeeName$) Then baseclass..EmployeeName$ = EmployeeName$


No RatingsRatings 0

Implementing abstract classes, sealed classes, and interfaces in LotusScript

Peter Presnell |   | Tags:  lotusscript oop .dominoframework classes | Comments (0)  |  Visits (966)
This post was prompted after following all the fun Tim Tripcomy was having building a mini-framework to demonstrate remote event binding....

Rather than just getting frustrated with the lack of progress by IBM in developing the LotusScript language - in line with Microsoft's version of BASIC (VB.Net) - I started building the .Domino Framework.  This was my way of getting more out of LotusScript so that I could be even more productive.  And it works. I find that by using a framework I can build new Notes applications around 50% faster than before.  And we ALL know that Notes development is already signficantly faster than most (All?) other development platforms - right!!?  LotusScript currently falls short in providing a number of important OOP concepts, including abstract classes, sealed classes, and interfaces. Within the .Domino Framework I have chosen to implement these constructs as described below.  Note: One of the key difference with LotusScript is that errors for violating "the rules" are thrown at run-time and not at compile time.  Other OOP languages such as C#, VB.Net, and Java implement these OOP constructs with class modifiers such as "abstract", "sealed", and "interface" (can you guess which is which?).  These languages stop you making mistakes when you first try to write the errant code.

Abstract Classes
An abstract class is defined as a way of providing attributes (properties, methods, and events) that can be shared by subclasses.  e.g. An Employee class defines attributes common to FullTimeEmployee, PartTimeEmployee, and Contractor classes.  The employee class is deemed "abstract" if you cannot implement an employee class directly but must implement one of the available subclasses.  An abstract class can be simulated in LotusScript by using the constructor.  When an instance of a class is defined the constructor of ALL base classes are also invoked.  We can therefore do a check to ensure the class being implemented is not the abstract class itself:-
Class AbstractClass
    Sub New(Source As Variant)
        If Typename(Me) = "ABSTRACTCLASS" Then
            Error ERROR_USER_FATAL,"AbstractClass is abstract and cannot be implemented directly"       
            Exit Sub
        End If
    End Sub
End Class


Sealed Classes

Sealed classes are used when you wish to prevent a class being extended by another class.  Again the constructor can be used to validate sealed classes.
Class SealedClass As AbstractClass
    Sub New(Source As Variant)
        If Typename(Me) <> "SEALEDCLASS"     Then
            Error ERROR_USER_FATAL,"SealedClass is sealed and cannot be extended by " + Typename(Me)
            Exit Sub
        End If
    End Sub
End Class


Interfaces

Like abstract classes, Interfaces are not designed to be implemented directly.  They differ from abstract classes in that they provide no code for properties, methods, events but define the properties, classes, and events that must be present for a class to meet the requirements of the interface. e.g. in Tim's example he has certain methods that must be implemented to make a specifc class "bindable remotely" This could be achieved by implementing an IsBindable Interface.  Another common example would be an "IsSortable" interface that is used to define classes that can be sorted.  Classes implementing such an interface may require GetFirst, GetNext, and Compare methods for a sort function to work.  Interfaces are more challenging to implement in LotusScript.  Because we are restricted to extending classes in a single chain we can only implement multiple interfaces by definining them in the underlying base class(es).  In C# we could implement multiple interfaces by listing each required interface as part of the class definition.  e.g. if I have interface A, B, and C I cannot easily implement classes in LotusScript with interface requirements A, B ,C, AB, AC, BC, and ABC without repeating a LOT of code (YUK).  We also have no way of checking if all of the required properties, methods, events have been implemented correctly, rather we can merely thow an error when we attempt to invoke one of those attributes.  The code for an interface could look something like this....
Class Interface
    Sub New(Source As Variant)
        If Typename(Me) = "INTERFACE" Then
            Error ERROR_USER_FATAL,"Interface is defined as an interface and cannot be implemented directly"
            Exit Sub
        End If       
    End Sub   
    Sub Method1
        Error ERROR_USER_FATAL,Typename(Me) + " has not implemented method Method1"
    End Sub
    Sub Method2
        Error ERROR_USER_FATAL,Typename(Me) + " has not implemented method Method2"
    End Sub
End Class


The next release of the .Domino Framework will provide an example agent that demonstrates the above.
No RatingsRatings 0

  • Previous
  • Next
Jump to page of 1
Skip to main content link. Accesskey S
IBM Lotus Connections Help Tools About