ChadSmiley Blog Things about family, life, coding, and more

9Sep/0613

Domino Document Locking Class 1.3

Here is an update to the Document Locking Class 1.1 and Document Locking Class , this update allows the unlocking overriding for Manager access (coded by Michael Sobczak) or overriding by group or role.

Public Sub new ( inDoc As Variant )
Public Sub SetCurrentUser ( user As String )
Public Function hasDocument ()
Public Sub setDocument ( inDoc As NotesDocument )
Public Sub setUIDocument ( inUIDoc As NotesUIDocument )
Public Property Get CurrentUser As String
Public Property Get toString As String
Public Property Get ShowPrompts As Boolean
Public Property Set ShowPrompts As Boolean
Public Function LockingEnabled () As Boolean
Public Function IsLockedByCurrentUser () As Boolean
Public Function IsDocumentLockedByCurrentUser (doc As NotesDocument ) As Boolean
Public Function IsUIDocumentLockedByCurrentUser ( uiDoc As NotesUIDocument ) As Boolean
Public Function LockedBy ( ) As String
Public Function IsLocked ( ) As Boolean
Public Function IsDocumentLocked ( doc As NotesDocument ) As Boolean
Public Function IsUIDocumentLocked ( uiDoc As NotesUIDocument ) As Boolean
Public Function Lock ( ) As Boolean
Public Function LockUIDocument (uiDoc As NotesUIDocument ) As Boolean
Public Function LockDocument ( doc As NotesDocument ) As Boolean
Public Function UnLock ( ) As Boolean
Public Function UnLockUIDocument ( uiDoc As NotesUIDocument ) As Boolean
Public Function UnLockDocument ( doc As NotesDocument ) As Boolean
Public Sub RoleGroupOverRide ( RoleGroup As String )

Domino Document Locking

%INCLUDE "LSCONST.LSS"
 
'/**
' * A rapper around the built-in document locking that is available in Notes/Domino 6.
' *	The purpose is to provide a better more consistant way of locking and unlocking documents.
' *	Will not lock a new document since it can not be locked.  Will only show warnings once.
' *
' *	@author	Chad Schelfhout		http://www.chadsmiley.com/
' *	@version	1.3
' *	@history
' *		1.0 Created
' *		1.1 Added ability to check the current user or a different user
' *		1.2 Added Manager override. by Michael Sobczak
' *		1.3 Added Role or Group override
' */
Class DominoDocumentLocking
 
	Private pUser As String
	Private pDoc As NotesDocument
	Private pToString As String 
	Private pShowPrompts As Boolean
	Private pDatabase_Locking_Not_Enabled As String
	Private pDatabase_Locking_Not_Enabled_Title As String
	Private pDocument_Locked As String
	Private pDocument_Locked_Title As String
	Private pEnabled As Boolean
	Private pAlreadyLocked As Boolean
	Private pRoleGroupOverRide As String
	'Flag used so user is only informed once that database locking is not enabled	
	Private pDatabasePrompted As Boolean
 
	Private db As NotesDatabase
 
	'/**
	' * Constructor
	' */
	Public Sub new( inDoc As Variant )
		pDatabase_Locking_Not_Enabled = "Database locking has not been enabled."
		pDatabase_Locking_Not_Enabled_Title = "Locking Not Enabled"
		pDocument_Locked = "Unable to lock, currently locked by: "
		pDocument_Locked_Title = "Document Locked"
		pDatabasePrompted = False
		pAlreadyLocked = False
		pShowPrompts = True
		pToString = ""
		If Not inDoc Is Nothing Then
			If Typename( inDoc ) = "NOTESDOCUMENT" Then
				Set pDoc = inDoc
			Elseif Typename( inDoc ) = "NOTESUIDOCUMENT" Then
				Set pDoc = inDoc.Document
			End If
		End If
 
		Dim Session As New NotesSession
		pUser = Session.UserName 
		'Msgbox "Current user is = " & pUser
 
		Set db = Session.CurrentDatabase
 
		If db.IsDocumentLockingEnabled Then
			pEnabled = True
		Else
			pEnabled = False
		End If
	End Sub
 
	'/**
	' * Determines if the document is locked 
	' */
	Private Function HasLock ( ) As Boolean
		If pDoc Is Nothing Then
			HasLock = True
		Else
			'if there is no text then it is not locked
			HasLock = Len( pDoc.LockHolders(0) ) > 0
		End If
	End Function
 
	'/**
	' * Gets the current user
	' */
	Private Property Get CurrentUser As String
		CurrentUser = pUser
	End Property
	'/**
	' * Gets the current user
	' */
	Public Sub SetCurrentUser( user As String )
		pUser = user
	End Sub
	'/**
	' * Determines if the document is locked but the current user.
	' */
	Private Function CurrentUserHasLock( ) As Boolean
		CurrentUserHasLock = HasLock ()
		If CurrentUserHasLock Then
			If pDoc.LockHolders(0) = pUser Then
				CurrentUserHasLock = True
			Else	'Not the current user.
				CurrentUserHasLock = False
			End If
		End If
	End Function
 
	'/**
	' * Determines if a document exists
	' */
	Public Function hasDocument()
		hasDocument = Not pDoc Is Nothing
	End Function
	'/**
	' * Sets the Document
	' */
	Public Sub setDocument( inDoc As NotesDocument )
		Set pDoc = inDoc	
	End Sub
	'/**
	' * Sets the document base on the UI document
	' */
	Public Sub setUIDocument( inUIDoc As NotesUIDocument )
		If inUIDoc Is Nothing Then
			Call setDocument( inUIDoc.Document )
		End If
	End Sub
 
	'/**
	' * Returns string of any messages
	' */
	Public Property Get toString As String
		toString = pToString
	End Property
 
	'/**
	' * Returns wether prompts are displayed
	' */
	Public Property Get ShowPrompts As Boolean
		ShowPrompts = pShowPrompts
	End Property
	'/**
	' * Sets wether prompts are displayed
	' */
	Public Property Set ShowPrompts As Boolean
		pShowPrompts = ShowPrompts
	End Property
 
	'/**
	' * Determines if database locking is enabled.
	' */
	Public Function LockingEnabled() As Boolean
		If Not pEnabled Then
			If Not pDatabasePrompted Then
				pToString = pDatabase_Locking_Not_Enabled
				If showPrompts Then
					Msgbox pToString , MB_ICONSTOP , pDatabase_Locking_Not_Enabled_Title
				End If
				pDatabasePrompted = True
			End If
		End If
		LockingEnabled = pEnabled
	End Function
 
	'/**
	' * Determines if the current document is locked by the current user.
	' */
	Public Function IsLockedByCurrentUser () As Boolean
		IsLockedByCurrentUser = LockingEnabled()
		If IsLockedByCurrentUser Then
			IsLockedByCurrentUser = CurrentUserHasLock( )
		Else	'Locking not enabled
			IsLockedByCurrentUser = False
		End If
	End Function	
	'/**
	' * Determines if the document is locked but the current user.
	' */
	Public Function IsDocumentLockedByCurrentUser (doc As NotesDocument ) As Boolean
		Call SetDocument( doc )
		IsDocumentLockedByCurrentUser = IsLockedByCurrentUser
	End Function
 
	'/**
	' * Determines if the UI document is locked but the current user.
	' */
	Public Function IsUIDocumentLockedByCurrentUser ( uiDoc As NotesUIDocument ) As Boolean
		Call setUIDocument( uiDoc )
		IsUIDocumentLockedByCurrentUser = IsLockedByCurrentUser(  )
	End Function
 
	'/**
	' * Returns who the document is locked by 
	' */
	Public Function LockedBy ( ) As String
		If hasDocument() Then
			LockedBy = pDoc.LockHolders(0)
		Else
			LockedBy = ""
		End If
	End Function
	'/**
	' * Determines if the currnet document is locked 
	' */
	Public Function IsLocked ( ) As Boolean
		isLocked = LockingEnabled()
		If isLocked Then
			isLocked = HasLock( )
		Else	'Locking is not enabled
			isLocked = False
		End If
	End Function
	'/**
	' * Determines if the the document is locked 
	' */
	Public Function IsDocumentLocked ( doc As NotesDocument ) As Boolean
		Call setDocument( doc ) 
		isDocumentLocked = IsLocked()
	End Function
	'/**
	' * Determines if the UI document is locked 
	' */
	Public Function IsUIDocumentLocked (uiDoc As NotesUIDocument ) As Boolean
		'Check to make sure that there is a document, If there is none it is a new document
		If ( uiDoc.Document Is Nothing ) Then
			IsUIDocumentLocked = False
		Else
			IsUIDocumentLocked= IsDocumentLocked( uiDoc.Document )
		End If
	End Function
 
	'/**
	' * Locks the current document
	' */
	Public Function Lock() As Boolean
 
		Me.Lock = LockingEnabled()
		If Me.Lock Then	'Check to make locking is enabled.
			If Not pAlreadyLocked Then	'Make sure that the document is not allready locked.
				If HasLock( ) Then
					'Msgbox "Document is currently locked"
					If CurrentUserHasLock( ) Then
						'Msgbox "Document is currently locked by the current user"
						'Since the current user has the document locked then we don't need to.
						pAlreadyLocked = True
						Me.Lock = True
					Else
						'Msgbox "Document is not currently locked by the current user"
						'Document is locked by someone else.  Let's display the name
						pToString = pDocument_Locked + pDoc.LockHolders(0)
						If showPrompts Then
							Msgbox pToString , MB_ICONSTOP, pDocument_Locked_Title 
						End If
						Me.Lock = False
					End If
				Else
					'Msgbox "Document is not locked"
					'Make sure that there is a document to lock, New documents can not be locked.
					If Not pDoc.IsNewNote Then
						Call pdoc.Lock
					End If
					pAlreadyLocked = True
					Me.Lock = True
 
				End If
			End If
		End If
 
	End Function
	'/**
	' * Locks the UI document
	' */
	Public Function LockUIDocument (uiDoc As NotesUIDocument ) As Boolean
		Call setUIDocument( uiDoc )
		LockUIDocument = Me.Lock()
	End Function
 
	'/**
	' * Locks the document
	' */
	Public Function LockDocument (doc As NotesDocument ) As Boolean
		Call setDocument ( doc ) 
		LockDocument = Me.Lock()
	End Function
 
	'/**
	' *  Unlocks the current document
	' */
	Public Function UnLock () As Boolean
 
		Me.UnLock = False
 
		If Not pDoc Is Nothing Then
			If Not pDoc.IsNewNote Then
				'Only unlock if the current user has it locked
				'or if the current user is defined as a Manager in the ACL.
				If ( CurrentUserHasLock () ) Then
					pDoc.UnLock
					Me.UnLock = True
				Elseif ( OverRideDocumentOwner() ) Then
					On Error Goto NotAuthor
					Call pDoc.RemoveItem( "$PWriters" )
					Call pDoc.RemoveItem( "$WritersDate" )
					Call pDoc.RemoveItem( "$Writers" )
					Call pDoc.Save( True, False , False )
					Me.UnLock = True
NotAuthor:
					pToString = Error
					If showPrompts Then
						Msgbox pToString , MB_ICONSTOP, pDocument_Locked_Title 
					End If
					Exit Function
				Else
					'Msgbox "Current user does not have the lock"
				End If
			Else
				'Msgbox "Current document is a new note"
			End If
		Else
			'Msgbox "Document is nothing"
		End If
 
	End Function
	'/**
	' *  Unlocks the UI document
	' */
	Public Function UnLockUIDocument (uiDoc As NotesUIDocument ) As Boolean
		Call setUIDocument( uiDoc )
		UnLockUIDocument = Me.UnLock()
	End Function
 
	'/**
	' * Unlocks the document
	' */
	Public Function UnLockDocument (doc As NotesDocument ) As Boolean
		Call setDocument( doc )
		UnLockDocument = Me.UnLock()
	End Function
 
	'/**
	'* Is User Database manager
	' */
	Private Function IsUserDbManager () As Boolean
		If ( db.CurrentAccessLevel = ACLLEVEL_MANAGER ) Then
			IsUserDbManager = True
		Else
			IsUserDbManager = False
		End If
	End Function
 
 
	'/**
	' * Role or Group Override
	' * The group or role will be used to determine if document can be unlocked
	' * even if the current user does not have the document locked.
	' */
	Public Sub RoleGroupOverRide( RoleGroup As String )
		pRoleGroupOverRide = RoleGroup
	End Sub
 
	'/**
	' * Determine if the role or group allows the unlocking to be overridden
	' */
	Private Function OverRideDocumentOwner () As Boolean
		OverRideDocumentOwner = IsUserDbManager
		If Not OverRideDocumentOwner Then
			Dim unl As Variant
			unl = Evaluate ( "@UserNamesList" )
			OverRideDocumentOwner = Not Isnull( Arraygetindex ( unl , pRoleGroupOverRide ) )
			If Not OverRideDocumentOwner Then
				OverRideDocumentOwner = Not Isnull( Arraygetindex ( unl , "["+pRoleGroupOverRide+"]" ) )
			End If
		End If
	End Function
End Class
Filed under: Domino Leave a comment
Comments (13) Trackbacks (1)
  1. Hi Chad,
    just want to emphasize the requirement for overiding the manager access:
    Unlocking without manager rights does only work if you are explicitly listed in an author item of the document – by Name, Role or Groupmembership.
    Editor or designer access does not suffice.
    Otherwise you recieve an error that the document is already locked by another user. :-

    Thanks for sharing.
    VM

  2. Hi Chad

    Is that work on the web?

    And with a load balancing cluster…

    Thanks

  3. I have used it on the web, so yes it will. As for the balancing cluster, it should work because this class is using the Domino Document Locking feature and nothing else, this class is just a wrapper to handle the common errors/situations that are not provided by Domino.

  4. Hi Chad, great work the Domino Document Locking Class, but I’ve got a problem unlocking a doc using that code from a web agent. The problem is in line

    pUser = Session.UserName

    because Session.UsersName returns the server name where the agent is executed rather than the user name, so when you check if user can unlock a doc the comparison always fails.

    I avoid that issue using this code

    pUser = Session.EffectiveUserName

    I don’t check if with this change the code still work on client.

  5. Thanks Dennis I will take a look at it.

  6. I am new to Domino. Where do I past the document locking logic.

  7. I would place the code into a script library so it can be used by anything.

  8. Chad I need a help,

    I paste code ‘Domino Document Locking’ in script library.
    Where and how I can call function from this class.
    Thank’s Bojana

  9. Bojana, it all depends on what you need done. Is this a UI or backend usage. For the most basic usage you would need to call LockUIDocument and UnLockUIDocument if you where need to lock a UI document.

  10. Hello Chad

    The locking feature has helped me a lot. How I used it is

    In the querymodechange event I used

    Sub Querymodechange(Source As Notesuidocument, Continue As Variant)
    If source.EditMode Then
    Dim locker As New DominoDocumentLocking( source )
    Call locker.LockUIDocument( source )

    End If
    End Sub

    and in the Queryclose event I used

    Sub Queryclose(Source As Notesuidocument, Continue As Variant)
    If source.EditMode Then
    Dim locker As New DominoDocumentLocking( source )

    Call locker.UnLockUIDocument( source )
    End If
    End Sub

    When one document is locked by a user and another user tries to edit the same document the code works fine.

    Here is one problem I am facing

    When the same user opens two instances of the same document then it allows both the instances of the document to get into the edit mode and then when you save the documents there is a replication conflict

    I have tried checking using the following code in the query open

    Dim locker As New DominoDocumentLocking( source )
    Dim islocked As Boolean
    islocked =locker.IsUIDocumentLockedByCurrentUser ( Source)
    If islocked = True Then

    Msgbox “Another copy of this document is already open”
    Continue = False

    End If

    this works in the query open but not in the Querymodechange it returns True in both the cases and I cannot check if it is the first instance that is being sent into the edit mode

    Please suggest what i need to do

  11. As I was review the code, this jumped out at me:

    Call pDoc.RemoveItem( “$WritersDate” )
    Call pDoc.RemoveItem( “$Writers” )

    Why not check the time of the $WritersDate, and see if it is the current time, or relatively close, if it is then it is the current document. I no longer have a Domino server to do any testing, but that is the first idea that came :-)

  12. Hi Chad . Thanks .

    This is if others face this issue of the same user opening two instances of the same document. I used environment variables and set an environment variable using the document id I have the following code in the QueryOpen
    Dim session As New NotesSession
    Dim latestNumber As String

    latestNumber = session.GetEnvironmentString(source.Document.UniversalID)

    If latestNumber =”" Then

    Call session.SetEnvironmentVar( Cstr(source.Document.UniversalID), Cstr(source.Document.UniversalID) )
    Else
    Msgbox “Another instance of this document is already open ”
    Continue = False
    End If


Leave a comment