Monday, May 16, 2011

Force embedded views to open on the same server as the app containing them

I've been doing some Notes development lately. I've noticed that the embedded views are being loaded from the server where the app that have the embedded views was opened last. I wrote a little procedure that you can run on PostOpen in database script.

Input parameter: the name(s) of the forms with external embedded views.

The code inspects the DXL of the form and fetches all the replicaids of the external embedded views. It then tries to open these databases and add them to the workspace with the server the user is currently on. As far as I've tested, it seems to work as described. Let me know if there are bugs.

Sub loadEmbeddedViewsOnCurrentServer( formsWithEmbedded As Variant )
On Error GoTo bubbleError
'// Goes through the form(s) specified by name in formsWithEmbedded and opens the dbs
'// that have the embedded views on the same server as the code is running
If DataType( formsWithEmbedded ) = 8 Then
formsWithEmbedded = Split( formsWithEmbedded, "¤¤¤" )
End If

Dim s As New NotesSession, db As NotesDatabase, currentServer As String
Set db = s.currentDatabase
currentServer = db.server

'// Find forms
Dim noteCol As NotesNoteCollection
Set noteCol = db.createNoteCollection( False )
noteCol.selectForms = True
noteCol.selectionFormula = |$title="| + Join( formsWithEmbedded, |":"| ) + |"|
Call noteCol.buildCollection()

Dim formNoteId As String, formDoc As NotesDocument
Dim dxlExporter As NotesDXLExporter, dxlStream As NotesStream
Dim embeddedPosition As String, embeddedView As String
Dim formDxl As String, embeddedViews As Variant, replicaid As String
Dim workspace As New NotesUIWorkspace(), embeddedViewDb As NotesDatabase
Dim openedDbs As Variant, result As Variant

openedDbs = Split( "" )
Set dxlStream = s.createStream()

formNoteId = noteCol.getFirstNoteId()
While formNoteId <> ""
Set formDoc = db.getDocumentById( formNoteId )

'// Extract DXL from form
Set dxlExporter = s.createDxlExporter( formDoc, dxlStream )
Call dxlExporter.process()

dxlStream.position = 0
formDxl = dxlStream.readText

'// Get embedded view info
embeddedPosition = InStr( formDxl, "<embeddedview" )
While embeddedPosition > 0
'// Embedded views can be defined as <embeddedview /> or <embeddedview></embeddedview> - try both
embeddedView = StrLeftBack( StrRightBack( formDxl, "<embeddedview" ), "</embeddedview>" )
If embeddedView = "" Then embeddedView = StrLeftBack( StrRightBack( formDxl, "<embeddedview" ), "/>" )

'// Open databases
If InStr( embeddedView, "database" ) > 0 Then
replicaid = Strtoken( StrRightBack( embeddedview, "database='" ), "'", 1 )
If replicaid <> "" Then
'// If db hasn't been opened before in the script - open
If IsNull( ArrayGetIndex( openedDbs, replicaid ) ) Then
Set embeddedViewDb = New NotesDatabase( "", "" )
Call embeddedViewDb.openByReplicaId( currentServer, replicaid )
If Not embeddedViewDb Is Nothing Then
If embeddedViewDb.isOpen Then
Call workspace.addDatabase( currentServer, embeddedViewDb.filePath )
End If
End If

openedDbs = ArrayAppend( openedDbs, replicaid )
End If
End If
End If

'// Remove start tag for the processed embedded view - only run once per embedded
formDxl = Replace( formDxl, "<embeddedview" + embeddedView, "" )

'// Find next embedded view
embeddedPosition = InStr( formDxl, "<embeddedview" )

Call dxlStream.truncate()
formNoteId = noteCol.getNextNoteId( formNoteId )

Exit Sub
Error Err, Error
End Sub


Glen Urban said...

Hi Tommy,

I've experienced similar issues and developed something similar.

Don't know if you're aware of this but DB PostOpen doesn't trigger if a user follows a document link. So to be doubly sure you need to run this in the forms QueryOpen.