Oje, das hat aber was gedauert. Jetzt ist es fast 3 Monate her, dass ich euch mit geschwellter Brust von meinem neuesten Projekt erzählt habe: der Installation eines Domino Servers auf einem Linux Server.
Zugegeben, eigentlich hab ich nur die Anleitung unseres neuen Super-Admins Raphael durchgehen müssen, aber offensichtlich war das gar nicht so einfach für so einen Anfänger-Nerd wie mich.
 
Dennoch kann ich euch heute mit etwas weniger geschwellter Brust berichten, dass das Projekt erfolgreich beendet wurde.
Mein Domino Server Version 9.0.1. läuft jetzt auf Linux CentOS 7.2 und ist bereit für weiteren Schabernak. Mal sehen, was ich damit noch anstelle.

Wenn ihr wissen wollt wie ich's gemacht hab, schaut euch einfach den Anhang zu diesem Artikel an. Raphael musste sich die einzelnen Schritte der Installation aus mehreren Quellen zusammensuchen und auch einiges selbst herausfinden, um euch diese komplette Step-by-Step-Anleitung zusammenstellen zu können. Darin beschreibt er z.B. auch

  • mit welchem User man welche Schritte durchführen muss, damit Linux nicht meckert,
  • warum die erste Installation des FixPacks nicht ohne weiteres funktioniert,
  • wie man die Fehlermeldung beim ersten Start des neukonfigurierten Domino Servers bezüglich der "maximum number of file handles" behebt  
  • und was man bei gemischten Infrastrukturen aus Windows- und Linux-Servern beachten sollte.

Wenn ihr noch Erweiterungsvorschläge für die Anleitung habt oder andere Erfahrungen mit Domino-Linux-Servern oder gemischten Linux-Windows-Infrastrukturen habt, dann schreibt sie doch bitte in die Kommentare.
Wenn ihr Hilfe bei der Installation, Konfiguration oder Administration von Domino-Linux-Servern braucht, ruft uns einfach an unter 05251 288160 oder schreibt uns eine E-Mail an info@itwu.de.

 

 

The createViewNavFromCategory method in the NotesView class has the following bug:

if the user has no rights to read all documents in the category you specified,
this method does NOT return an empty view navigator but a navigator FOR ALL SUBSEQUENT CATEGORIES IN THE VIEW.


Example:

You have a categorized view by company names.
Some documents in this view has a reader field, and you are not authorized to see the documents in the category "ITWU".
The view will look like this:

 

 

Now, you write the following Java code:

Database db = DominoUtils.getCurrentDatabase();
View view = db.getView("myview");
ViewNavigator nav = view.createViewNavFromCategory( "ITWU" );

You probably suppose to get an empty view navigator but that's where you are wrong;
the view navigator is for all entries in the categories Microsoft and SAP

This phenomenon does not happen in the getAllEntriesByKey method.


Workaround:

Check the first entry in the view navigator again if you have the correct category.
Attention: if the column is a multi-value field, you have to check it too.

ViewEntry entry = nav.getFirst();
if( entry != null )
{
    if( !"ITWU".equals( entry.getColumnValues().get(0).toString() ) )
    {
        System.out.println("not found");
        return;
    }
}

 

 

Problem Description

In this article I will show you how to elegantly link documents in a Notes database with the use of event handlers. At first glance linking documents together seems to be a very trivial task. It is something we all implemented hundreds of times already, either using built-in Notes response hierarchies or through building document trees of our own design. Doing that programmatically while using backend classes is as trivial as it sounds, but letting the user do it interactively is something else entirely. Because then there are certain additional requirements that should be implemented to guarantee a consistent and hassle-free user experience.

So let us take a look at those requirements for the two standard use cases:

1. The user links an already existing document to the currently open document (through a dialog field or a view selection). The title of the linked document should be displayed in a field and the document can be opened through a hotspot.

Requirements

  • If the user doesn’t save the currently open document the link should be voided i.e. the field should be empty and the hotspot action should not execute.
  • The operation should not access backend classes to avoid replication and safe conflicts.

2. The user creates a new document from an already open document. The new document should be linked to the already opened one and its title should be displayed in a field (and can, after the initial save, opened through a hotspot).

Requirements

  • If the user doesn’t safe the new document AND the current document the link should be voided i.e. the field should be empty and the hotspot action should not execute, even if the new document has been saved.
  • The operation should not access backend classes to avoid replication and safe conflicts.
  • Every change the user performs on the new document should immediately be reflected in the old document.

 

Implementation

During the following demonstration I will call the document that provides the link the parent and the link target the child. I also will not make use of the Parent-Response-Hierarchy but will implement my own hierarchy using document IDs I generate myself programmatically. I am sure you know why that is . Of course you can use a Parent-Response Hierarchy instead and, if you are feeling lucky, you can even use Universal IDs to define the link.

 

Case 1: Linking to an existing document

The first case is more or less trivial. The child already exists and will not be opened during the linking operation hence we actually can (have to actually) access it using backend classes, specifically an instance of NotesDocument or built-in functions e.g. a dialog list field.
We create a dialog list field on the parent form and populate the choices with a column of a lookup view. The column formula should be something like the following:

doc_title + “|” + doc_id

Now make sure “Allow keyword synonyms” is checked in the field properties and you are done.

If you have to actually use backend classes, for example in conjunction with the NotesUIWorkspace Functions PicklistCollelction or PicklistStrings you can use the NotesUIDocument Function FieldSetText to set the value. And yes you can set computed and even hidden fields that way, too. I normally use a dialog list field even if the field is computed and set with FieldSetText. That way I can set the doc_id and after a NotesUIDocument.Refresh the displayed value is automatically translated to the title. For this to work you of course have to check the option “Refresh choices on document refresh” in the field properties.

The hotspot action performs a lookup in the same view (the first sorted column has obviously to be doc_id) and opens the document.

 

Case 2: Linking a new document

This case requires a little more work. So let us split the requirements into two steps to make it clearer.

For the purpose of code clarity and management we create persistent backend classes which serve as a wrapper for NotesUIDocument instances. We accomplish that through creating an instance of our wrapper in the PostOpen event and saving the reference in a variable declared in the Globals section of the form. For more details read my previous articles on the subject:

Event Handling mit LotusScript Teil I - Persistente Event-Handler

 

Step 1: Creating the child

In the backend class for the parent we first declare a private member variable:

Private childUIDoc As NotesUIDocument

 

And the following sub:

Public Sub actionCreateChild()

   Dim ws As New NotesUIWorkspace()
   Dim db As NotesDatabase
   Dim childDoc As NotesDocument

   Set db = ws.CurrentDatabase.Database
   Set childDoc = db.CreateDocument()

   Call childDoc.ReplaceItemValue( "Form", "childDoc" )
   Call childDoc.ComputeWithForm( False, False )

   Set me.childUIDoc = ws.EditDocument( True, childDoc )


End Sub

 

That sub will be called by the action which we use to create the child document. In effect our persistent instance of the parent wrapper class now has a handle on the NotesUIDocument instance of the just created child.
 

Step 2: Handling Child Events in the Parent-Wrapper

Next we want to notify the parent if and when the child gets saved or closed. For that purpose we bind the corresponding events, which are fired by the child NotesUIDocument instance, to event handlers we define in our parent wrapper.

Public Sub actionCreateChild()
    
    Dim ws As New NotesUIWorkspace()
    Dim db As NotesDatabase
    Dim childDoc As NotesDocument
    
    Set db = ws.CurrentDatabase.Database
    Set childDoc = db.CreateDocument()
    
    Call childDoc.ReplaceItemValue( "Form", "childDoc" )
    Call childDoc.ComputeWithForm( False, False )
    
    Set me.childUIDoc = ws.EditDocument( True, childDoc )

    On Event PostSave From me.childUIDoc Call OnPostSave_Child
    On Event QueryClose From me.childUIDoc Call OnQueryClose_Child

End Sub

 

All the PostSave event handler has to do is to set the doc_id and refresh the NotesUIDocument instance of the parent document. This way the current title of the document is always displayed.

Public Sub OnPostSave_Child( Source As NotesUIDocument )
    
    Call me.mUIDoc.FieldSetText( "child_id", _
                                  Source.FieldGetText( "doc_id" ) )
    Call me.mUIDoc.Refresh()
    
End Sub

 

In the QueryClose event handler we first check if the child has been saved. Since we created the document using backend classes we need to check the property IsNewNote on the backend document rather than the property IsNewDoc which is provided by the NotesUIDocument instance (and hence will always be false). If the child has been saved we do nothing, everything already has been taken care of by the PostSave event handler. If it has not been saved we reset the link field to the empty string, thus removing the link.

Public Sub OnQueryClose_Child( Source As NotesUIDocument, _
                               Continue As Variant )
    
    If childUIDoc.Document.IsNewNote Then
          Call me.mUIDoc.FieldSetText( "child_id", "" )
          Call me.mUIDoc.Refresh()
    End If
    
End Sub

 

And that is it. If the child doesn’t get saved the link will be empty. If the parent doesn’t get saved the link won’t change at all. If it was empty before the child was created it will obviously stay that way regardless whether or not the child has been saved.

 

Step 3: Opening the link

To keep the behavior consistent we also have to obtain the child NotesUIDocument instance when the user follows the link. For that we create a new sub for the sole purpose of opening the document.

Public Sub actionOpenChild()

    Dim ws As New NotesUIWorkspace()
    Dim db As NotesDatabase
    Dim view As NotesView
    Dim childDoc As NotesDocument
    Dim childID As String
    
    childID = me.mUIDoc.Document.GetItemValue( "child_id" )(0)
    
    If Not childID = ""  Then
          Set db = ws.CurrentDatabase.Database()
          Set    view = db.GetView( "lkpChildDoc" )
          Set childDoc = view.GetDocumentByKey( childID, True )
        
          If Not childDoc Is Nothing Then
                Set me.childUIDoc = ws.EditDocument( True, childDoc )
          End If
    End If
    
End Sub

 

So in theory we are done but what if the child gets opened end edited outside of the parent context? Well if we use the dialog list approach we are still done because when the child gets edited the view entry will change and the link title will be updated the next time you open the parent (into edit mode). But what if you want the parent to reflect changes in the child immediately?
 
There probably is a reason why you made one document the child and the other the parent and not the other way around. You built your hierarchy to reflect some piece of business logic or maybe even real logic .

In consequence it is highly likely that the user is already editing the parent when he opens the child. Hence updating the parent programmatically through the child without having the parent context invites all kinds of trouble. So don’t! Rather write an agent that runs once a night and performs a ComputeWithForm on all parent documents.


 


"tell router pause"
"tell router resume"

These little commands for the IBM Domino Server console can be very usefull when troubleshooting mail routing, name resolving or mail group expanding issues.

„tell router pause“ pauses the mail router so it won't deliver any mails. While the router is paused, you can send testmails, analyze them in the mail.box and delete them before you resume the router. Take note that the router splits mails at a certain amount of recipients, so make sure you delete all parts of the mail in the (perhaps multiple) mail.box's before starting the router again with "tell router resume".