• 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

Document Locking Bug

Peter Presnell |   | Tags:  .dominoframework documentlocking | Comments (0)  |  Visits (377)

With Notes 6.0 there appears to be a bug with document locking in the scenario in which UserA is editing a document and UserB then attempts to edit the same document on another server while UserA is still editing the document. When this happens UserB will be able to open the document but it will remain in read mode while UserA is editing the document.  When UserA has finished editing the document UserB can then place the document in edit mode.  The first time this is attempted a warning message is issued that USerB must re-open the document from the parent view and the document remains in Read mode.  If UserB ignores the message and again attempts to edit the document without reopening it from the parent view the document actually opens in edit mode.  If UserB then closes the document without making any changes, a lock is placed on the document by UserB that is not released after the document is closed.  This can lead to an accumulation of locked documents in the database.

 

To solve this scenario I have extended the .DominoFramework as follows:-

 

A property has been added to the DominoDocument class that allows the detection of a document that is locked by somebody else:-

 

Property Get IsLockedBySomeoneElse As Boolean
  IsLockedBySomeoneElse = iDocument.LockHolders(0) <> "" And Isnull(Arraygetindex(iDocument.Lockholders,Session.UserName))
End Property

 

A new PreventEditIfLocked method can then be invoked by the PostOpen event on the form.  This adds additional code to the QueryModeChange event to trap the scenario in which a locked document is subsequently placed in edit mode:-

 

 Sub PreventEditIfLocked(Source As NotesUIDocument)
  If Me.IsLockedBySomeoneElse Then On Event QueryModeChange From Source Call Reload
 End Sub

 

The Reload method that is now triggered by the OnQueryModeChange event then closes the document and re-opens the document.  This is done via an agent as I was unable to find any other way of forcing the current document to be closed and the re-opened.  It was also necessary to unlock the document at this stage as it appears this is where the forgotten lock is enabled.

 

Sub Reload(Source As NotesUIDocument, Continue As Variant)
  Dim Agent As NotesAgent
  
  On Error Resume Next
  Call Source.Document.UnLock
  Call Source.Close(True)
  Set Agent = DB.GetAgent("aReopenDocument")
  If Not Agent Is Nothing Then Call Agent.Run(iDocument.NoteID$)
 End Sub

 

And finally, the agent to open the document is as follows:-

 

Sub Initialize
 Dim Session As New NotesSession
 Dim UIW   As NotesUIWorkspace
 Dim Agent  As NotesAgent
 Dim Doc   As NotesDocument
 
 If Session.IsOnServer Then Exit Sub
 Set Agent = Session.CurrentAgent
 Set Doc = Session.CurrentDatabase.GetDocumentByID(Agent.ParameterDocID$)
 If Doc Is Nothing Then Exit Sub
 Set UIW = New NotesUIworkspace
 Call UIW.EditDocument(True,Doc,,,False)
 
End Sub

 

All of the above code will be included as part of the 0.4 beta of the .Domino Framework planned for this weekend.

No RatingsRatings 0

Removing Duplicates

Peter Presnell |   | Tags:  .dominoframework duplicates | Comments (0)  |  Visits (381)

Today I had an application in development in which an  LEI Activitiy was somehow creating a small number of duplicate records.  Rather than try to figure out why LEI was creating duplicates I chose to simply create an agent to delete the duplicates.  I have extended the .Domino Framework to add a RemoveDuplicates method for the DominoView class.

 

To Make this work:-

  1. Create a view that sorts documents by the "key" with the key being in a column (for partial keys concatenate the values).
  2. (Optional) add a second columns that sorts the documents in such a way that the duplicate to be retained is at the top (e.g. creation date)
  3. Invoke the method using an action button on the view, and agent (manual or scheduled).

The methods created takes a column number as a parameter for the column containing the key anbd returns a count of the number of duplicates removed.

 

 '/**
 ' *  Remove all duplicate entries in view by retaining the first entry listed for each duplicate value
 ' *
 ' * @param ColumnPos The column number to be used to identify the unique values
 ' * @return  The number of documents deleted from the view
 ' */
 Function RemoveDuplicates(ColumnPos As Integer) As Long
  Dim AllEntries   As NotesViewEntryCollection
  Dim Doc     As NotesViewEntry
  Dim LastDoc   As NotesViewEntry
  Dim NextDoc   As NotesViewEntry
  
  If iView Is Nothing Then Exit Function
  Set AllEntries = iView.AllEntries 
  Set LastDoc = AllEntries.GetFirstEntry
  Set Doc = AllEntries.GetNthEntry(2)
  While Not Doc Is Nothing
   Set NextDoc = AllEntries.GetNextEntry(Doc)
   If Doc.ColumnValues(ColumnPos%) = LastDoc.ColumnValues(ColumnPos%) Then
    RemoveDuplicates = RemoveDuplicates + 1
    Call Doc.Document.Remove(True)
   Else
    Set LastDoc = Doc
   End If
   Set Doc = NextDoc
  Wend
 End Function

 

View Action:

 

Sub Click(Source As Button)
 Dim Count As Long
 Count& = View.RemoveDuplicates(0)
 If Count& > 0 Then
  Msgbox Cstr(Count&) + " duplicate documents deleted",MB_OK+MB_ICONINFORMATION
 Else
  Msgbox "No duplicates found",MB_OK+MB_ICONINFORMATION
 End If
End Sub

No RatingsRatings 0

ODS 48 And Unfiled Documents

Peter Presnell |   | Tags:  domino8 | Comments (0)  |  Visits (508)

This is an FYI for those currently in the process of migrating to Domino 8.0/8.0.1.....

 

One of my clients is migrating from 7.0 to 8.0.1.  They have customized their mail template to include a view that displays documents not filed in any folders.  This view uses the special view type "Shared, contains documents not in any folders" It was found that when a user's mail database was upgraded to the lated ODS (48), this view would no longer work.  The view simply does not display inside the mail database and the Domino server reports error trying to process the view.  For now we have held off on upgrading mail files to ODS 48 pending a solution to the issue.

No RatingsRatings 0

Document Locking

Peter Presnell |   | Tags:  documentlocking .dominoframework | Comments (2)  |  Visits (413)

 One of the projects I am presently working on involves enabling document locking for an application using the Document Locking feature introduced with Notes 6.0.  I had done this before with Notes 6.0 and recall there are issues with documents sometimes remaining locked even after the user has finished editing the document.  And sure enough, when we started UAT we got reports of document being locked even though no-one was still editing the document.  As part of the process for resolving this I have added Document Locking as a new feature within the .Domino Framework.

 

A new view ($Locked) has been created as a way of clearly displaying those documents that are presenty locked (i.e. the $Writers fields is present).

I have added a view action to remove the lock by deleteing the $Writers and $WritersDate field from the document .  This allows people without Manager access to maintain the locks.

 

Testing done so far has shown that when the lock fails to be removed,  the $writers field is present but the $WritersDate field is not present.  I have therefore added a RemoveInvalidLocks method to the DominoDatabase class that will remove any document in the ($Locked) view for which this situation arises.  By creating an agent the runs periodically against the database invoking this method it is possible to locate and correct these issues as they occur.

 

Note: Further testing is still required to ensure that only invalid locks are being removed and that this technique is identifying all the document locks that persist after they are no longer needed....

No RatingsRatings 0

Replication And Merging

Peter Presnell |   | Tags:  replication | Comments (1)  |  Visits (425)

Today I was testing an application to make sure that changes made to ensure replication merged changes at the field level rather than the default document level.  To do this we set up replicas on two different dev servers.  Because the two servers do not normally repolicate with each other (and because we didn't want to wait that long) I decided to replicate the databases manually from my workstation.  When I did, I found that the documents did not merge changes at the field level but at the document level.  My initial thoughts were that there was a problem with the field level merging.  Later we figured out a way to get the servers to do the replication.  When the servers initiated the replication the field level merging took place as intended.

 

It would appear that replication that is initiated from the Notes client (Notes 6.0) does not perform field level replication.  I need to do some further tests to confirm this, but obvioulsy I need to be careful when I use my workstation to replicate databases as this may very well result in a different outcome for applications designed to merge changes at the field level...  Yikes

No RatingsRatings 0

Adding an RSS Feed To A Notes Application

Peter Presnell |   | Tags:  .dominoframework rss | Comments (0)  |  Visits (522)

On of my challenges for last week was to find an easy way to add an RSS feed to a Notes application.  After doing some research on the topic I found that the XML required for an RSS feed is fairly simple and there were already a number of excellent examples out there within the Notes community.  In the spirit of the .Domino Framework I wanted a generic solution which could easily applied to multiple applications.  In the end I based some of my my code on the OpenNTF Blogsphere (thanks Declan).

 

I have created a new DominoRSS Feed class.  This is intented to be part of a new Domino.Applications.RSS namespace but I have been having  technical problems getting the same code to run as a Web agent when placed in a LotusScript library.  So, for now, the class definition is included as part of the agent.

 

A new agent has been developed with an alias of content.rss that invokes various methods/properties in the class to generate the necessary XML.  The code for the agent is as follows:-

 

Sub Initialize
 Dim RSSEngine As DominoRSSFeed
 
 Set RSSEngine = New DominoRSSFeed(Nothing)
 RSSEngine.NotesLinks = True
 Call RSSEngine.GenerateHeader
 Call RSSEngine.GenerateViewContent("($RSS)",0)
 Call RSSEngine.GenerateFooter
 Call RSSEngine.WriteXML
End Sub

  • The NotesLinks property is used to determine if the RSS Feed should publish links using http protocol (default) or Notes protocol.  In my case I wanted the documents to launch in the Notes client as the source application is not Web-enabled.
  • The GenerateHeader method creates the initial XML for the feed/channel
  • The GeneratViewContent method creates the XML for the feed based upon the contents of the provided view.  The view can be any view with the programatic column name for each column used to create XML elements.  Use any of the available RSS feed attributes such as "title", "description","author","pubDate" to map the view content to the RSS feed.
  • The GenerateFooter method creates the closing XML
  • The WriteXML method takes the XML held internally within a NotesStream and writes it back to the screen.

I can now make any application RSS enabled by simply adding the agent (with the DominoRSSFeed Class) and having a view that meets the requirements above.

 

Note: The code for the class will be published as part of the next beta of the .Domino Framework later this month.  .Domino Framework wiki will provide documentation on the RSS Feed XML.   I will also be working on an enhancement to define various RSS attributes (e.g. Description) as part of the Application Settings.

No RatingsRatings 0

Universal Time

Peter Presnell |   | Tags:  .dominoframework | Comments (0)  |  Visits (340)

The following property has been added to the DominoDateTime class to allow a date/time value to be represented in a format consistent with ISO 8601's Universal Time (UTC).  This will be available as part of beta 0.4 later coming this month.

 

'/**
 ' * ISO Coordinated Universal Time (UTC) format for date
 ' */  
 Property Get UTC As String
  
  Dim UTCDayName As String
  Dim UTCDay    As String
  Dim UTCMonth   As String
  Dim UTCYear   As String
  Dim UTCTime   As String
  Dim UTCSign   As String
  Dim UTCZone   As String
  
  If iDate Is Nothing Then Exit Property
  
  UTCDayName$ = Format$(iDate.LSLocalTime, "ddd")
  UTCDay$= Format$(iDate.LSLocalTime, "dd")
  UTCMonth$ = Format$(iDate.LSLocalTime, "mmm")
  UTCYear$ = Format$(iDate.LSLocalTime, "yyyy")
  UTCTime$ = Format$(iDate.LSLocalTime, "hh:nn:ss")
  If Sgn(iDate.TimeZone) < 0 Then UTCSign$ = "-" Else UTCSign$ = "+"
  If iDate.TimeZone < 10 Then UTCZone$ = "0" + Cstr(Abs(iDate.TimeZone)) Else UTCZone$ = Cstr(Abs(iDate.TimeZone))
  UTCZone$ = UTCSign$ + UTCZone$ + "00"
  UTC$ = UTCDayName$ + ", " + UTCDay$ + " " +UTCMonth$+ " " +UTCYear$ + " " +UTCTime$ + " " + UTCZone$
  
 End Property

No RatingsRatings 0

Programming Events In both @Language and LotusScript

Peter Presnell |   | Tags:  .dominoframework | Comments (0)  |  Visits (583)

Have you ever wished it was possible to program an event such as QuerySave in both @Language and LotusScript?  Sometimes the most efficient (or only) way to perform a specific task is to code the event using @Formula and @Commands.  That works fine until a request comes along in which LotusScript is the only solution.  Using Evaluate within LotusScript  can sometimes be a solution but there is another way to achieve this.

 

1) Create a class

2) In the constructor for the class create an event handler for the event and set it to invoke a sub of that class

3) Create the method using the same signature as the event with the LotusScript code and put all the LotusScript code in there

4) In the QueryOpen event create an instance of the class passing the NotesUI object (this can be any event invoked prior to the called event - QueryOpen is usually the first and is usually the best)

5) Place the @Language component in the actual event on the form/page.view

 

When the event is fired the @Language coded in the the actual event will be executed and then the eventhandler coded in the class will be executed....

 

Form example:

 

Class MyClass

  Sub New(Source As NotuesUIDocument)

    On Event QuerySave From Source Call OnQuerySaave

  End Sub

 

  Sub OnQuerySave(Source as NotesUIDocument,Continue As Variant)

  ' Place all LS QuerySave code here

  End Sub

End Class

 

Dim Var As MyClass

 

Sub QueryOpen(Source As NotesUIDocument)

  Set Var = New MyClass(Source)

End Sub

No RatingsRatings 0

@BusinessDay

Peter Presnell |   | Tags:  .dominoframework | Comments (0)  |  Visits (393)

A common feature request I get for applications is the ability to adjust dates so that they do not fall on a weekend or a business holiday.  Whilst there is no @BusinessDay function, I often wish there is one.  The .Domino Framework now provides a LotusScript equivalence for what I envisage an @BusinessDay function should/could look like.  It takes a date or array of dates (of LS type DATE or NOTESDATETIME), and array of non-worrking  days and adjusts the dates so that none of them fall on a weekend or holiday.  This is available in the Domino.AFunctions namespace.

 

The code is as follows:-

 

/**
' * Returns a list of business days for a list of dates, adjusting those dates that fall on a weekend or holiday
' *
' * @author Peter Presnell
' * @param  Source     A list of one or more dates
' * @param Holidays    A list of dates that are considered non-working dates
' * @param MoveAfter    True = move date to next working day, False = move date to previous working day
' * @return  A list containing the dates adjusted for weekends and holidays
' */
Function atfBusinessDay(Source As Variant, Holidays As Variant,MoveAfter As Boolean) As Variant
 
 Dim Index   As Integer  ' Counter used to loop through arrays
 Dim Results  As Variant  ' Interim results of atfBusinessdays
 Dim DateTime As Variant  
Try: 
 On Error Goto Catch
atfBusinessDay = Source
 
' If array of dates passed then caluclate business days for each pair of dates
 
 If Isarray(Source) Then
  For Index% = Lbound(Source) To Ubound(Source) 
   Redim Preserve Result(Index%)
   Result(Index%) = atfBusinessDay(Source(Index%),Holidays,MoveAfter)
  Next Index%
  atfBusinessDay = Results
 Else
  Select Case Typename(Source)
  Case "DATE"
   While Weekday(Source) = 1 Or Weekday(Source) = 7 Or atfIsMember(Source,Holidays)
    If MoveAfter Then Source = Source + 1 Else Source = Source - 1
   Wend
   atfBusinessday = Source 
  Case "NOTESDATETIME"
   DateTime = Cdat(Source.DateOnly)
   While Weekday(DateTime) = 1 Or Weekday(DateTime) = 7 Or atfIsMember(DateTime,Holidays)
    If MoveAfter Then DateTime = DateTime + 1 Else DateTime = DateTime - 1
   Wend
   Set atfBusinessDay = New NotesDateTime(DateTime)
  End Select
 End If 
 Exit Function
Catch:
 Stop
 Call ReportError
 Exit Function
 
End Function

No RatingsRatings 0

LotusScript Version of @DBLookup

Peter Presnell |   | Tags:  .dominoframework | Comments (0)  |  Visits (683)

From time to time I have found a need to perform the equivalence of @DBLookup within LotusScript.  The following is the code I have just finished revising which will implement @DBLookup using LotuScript code only (i.e. withount an evaluate).  This forms part of an effort to provide LotusScript euqivalnts for most @Functions without using Evaluate for those times when evaluate doesn't work opr to expand the functionality beyond that provided by teh basec @function...  This updated function will be included in the next beta release of the .Domino Framework as part of the Domino.@Functions namespace.

 

Note: In most cases Evaluate works just fine and will often produce a much faster result .

 

'/**
' * Given a key value, looks in the specified view (or folder) and finds all documents containing the key value in
' *  the first sorted column within the view. For each selected document, @DbLookup returns either the contents
' * of a specified column in the view, or the contents of a specified field.
' *
' * @author Peter Presnell
' * @param Database    NotesDatabase object, server/filepath, or replicaid id of database
' * @param View      NotesView or name of view
' * @Param Key      Value used to locate entries in view
' * @param Column     Column number or name of field corresponding to values to be returned
' * @return  List of matched values
' */
Function atfDBLookup(Database As Variant, View As Variant,Key As Variant, Column As Variant, FailSilent As Boolean) As Variant
 Dim iDB     As New NotesDatabase("","" ' Database to perfrom lookup
 Dim iView     As NotesView       ' View to perfrom lookup
 Dim Doc     As NotesDocument     ' Document that corresponds to current entry in view
 Dim ViewEntries   As NotesViewEntryCollection
 Dim ViewEntry   As NotesViewEntry
 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
 atfDBLookup = EmptyArray
 Redim Results(0)
 
 Select Case Typename(View)
 Case "NOTESVIEW"
  Set iView = View
  Set iDB = iView.Parent
 Case "OBJECT"
  Set iDB = Session.CurrentDatabase
 Case "STRING"
  If Isobject(Database) Then
   Select Case Typename(Database)
   Case "NOTESDATABASE":
    Set iDB = Database
   End Select
  Elseif Isscalar(Database) Then
   Call iDB.OpenByReplicaID(Session.CurrentDatabase.Server,Cstr(Database))
  Elseif Isarray(Database) Then
   If Database(1) = "" Then
    Set iDB = Session.CurrentDatabase
   Else
    Call iDB.Open(Database(0),Database(1))
   End If
  End If
  If Not iDB.IsOpen Then Error 1000,"Database not found"
  Set iView = iDB.getView(Cstr(View))
 Case Else
  Exit Function
 End Select 
 If iView Is Nothing Then Exit Function
 
' Search for matching documents
 
 Set ViewEntries = iView.GetAllEntriesByKey(Key,True)
 
' Collect values found
 
 Set ViewEntry  = ViewEntries.GetFirstEntry
 While Not ViewEntry Is Nothing
  Select Case Typename(Column)
  Case "INTEGER","LONG"
   If Ubound(ViewEntry.ColumnValues) >= Cint(Column)-1 Then
    ColumnValues = ViewEntry.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"
   Set Doc = ViewEntry.Document
   Redim Preserve Results(Index&)
   If Doc.HasItem(Cstr(Column)) Then
    Forall FieldValue In Doc.GetItemValue(Cstr(Column))
     Results(Index&) = FieldValue
     Index& = Index& + 1 
    End Forall
   End If
  End Select
  Set ViewEntry = ViewEntries.GetNextEntry(ViewEntry)
 Wend
 
 atfDBLookup = Results
 Exit Function
Catch:
 Stop
 Call ReportError
 Exit Function

 
End Function

No RatingsRatings 0

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