Posts Tagged: ‘entwicklung’

EntwicklerCamp 2015: Java Managed Beans

3. März 2015 Posted by Bernd Hort

EntwicklerCamp

Der zweite Tag des EntwicklerCamps nähert sich dem Ende. Heute war mein Vortrag "Java Managed Beans". Nach einer kurzen Einführung in Java Managed Beans haben wir uns die Verwendung in XPages angesehen. Wobei gerade auch das Verständnis für die internen Abläufe in der XPages-Laufzeitumgebung ein wichtiger Aspekt war. Am Schluß wurden die Einsatzmöglichkeiten diskutiert.

Wie immer können die Folien und die Beispiel-Anwendung heruntergeladen werden.


Re: Re: 41. DNUG Konferenz: Track Entwicklung am 12.11.2014

13. November 2014 Posted by Roswitha Boldt

Als Antwort auf: Re: 41. DNUG Konferenz: Track Entwicklung am 12.11.2014

Gemeinsam mit meinem Team freue ich mich über dieses gute Feedback. Die positive Resonanz zu den Themen der beiden Techniktracks hatte sich schon bei der Vorauswahl der Sessions abgezeichnet.
Ein herzliches Dankeschön auch von unserer Seite an alle Referenten und Track Manager.

Re: 41. DNUG Konferenz: Track Entwicklung am 12.11.2014

13. November 2014 Posted by Thorsten Hindermann

Als Antwort auf: 41. DNUG Konferenz: Track Entwicklung am 12.11.2014

Der diesjährige Track Entwicklung, den ich als Trackmanager über die zwei Tage begleiten durfte, war nach einer Durststrecke einer der besten Entwicklertracks, die ich auf einer DNUG mitgemacht habe. Ich habe aus jedem Vortrag eine Kleinigkeit bzw. Anregung für meine tägliche Arbeit mitnehmen können. Das ist es, was die DNUG ausmacht und sichert somit ihr weiteres Bestehen. Vielen Dank an alle Referenten für Ihre spannende und interessanten Vorträge!

41. DNUG Konferenz: Track Entwicklung am 12.11.2014

28. Oktober 2014 Posted by Roswitha Boldt

Das sind die Themen:

Mobilisierung und "Sozialisierung" von Notes Anwendungen (Hans-Peter Kuessner / Jens Polster, SP Integration)

Application Development for IBM SmartCloud for Social Business (Niklas Heidloff, IBM)

Hochskalierbare Anwendungsarchitektur mit Domino XPages und JavaEE/SQL-Server im Hintergrund (Jens Ribbeck / Veit Weber, ULC / GABO)

Notes/Domino Anwendungen mit Java beleben (Knut Herrmann, Leonso)

Das Model-View-Controller-Pattern in XPages (Bert Häßler / Knut Herrmann, Leonso)

Activity Stream - how to feed the beast (Andreas Artner, Fritz & Macziol)

 

Track Management und Moderation

Oliver Busse, ULC, ein Unternehmen der GABO-Gruppe / Thorsten Hindermann, GWDG

 

 

Weitere Informationen zur Konferenz:

 

41. DNUG Konferenz: Track Entwicklung am 11.11.2014

23. Oktober 2014 Posted by Roswitha Boldt

Das sind die Themen:

Domino meets Microsoft - Eine mobile Windows App als Frontend für Notes/Domino Daten (Mirko Zellner, TÜV Rheinland / Gabor Pribil, ALLSET)

Domino Navigator - Notes Anwendungen effektiv entwickeln und managen ( Erik Schmalz)

JUnit Testing in XPages (Christian Güdemann, WebGate)

Plug-In Entwicklung (Ulrich Krause, BCC)

Neuentwicklung einer Domino Application auf BlueMix (Jörg Herbst, 10m)

 

Track Management und Moderation

Oliver Busse, ULC, ein Unternehmen der GABO-Gruppe / Thorsten Hindermann, GWDG

 

 

Weitere Informationen zur Konferenz:

 

Quick Tip: Benutzervalidierung durch erneute Passwort-Eingabe

30. September 2014 Posted by Thomas Bahn

Quick-TippIBM Notes
Ich hatte letzte Woche eine "kleine" Anforderung von einem Kunden: Er ist interessiert an der erweiterten kommerziellen Version unseres assono Password-Safes. Aber seine interne Revisionsabteilung hatte noch eine neue Anforderung: Der aktuelle Benutzer sollte vor dem Öffnen eines Dokuments oder beim Kopieren eines Passworts in die Zwischenablage direkt aus einer Ansicht vorher noch einmal sein Notes-Passwort eingeben müssen.

Dafür gibt es ein @Command: ToolsUserLogoff. Wenn es ausgeführt wird, logt es den Benutzer aus. Wenn man dieses Kommando mit etwas Code kombiniert, mit dem man auf den Server zugreift, erscheint der Passworteingabe-Dialog, wie es zum Bespiel hier beschrieben wurde: Forcing user re-entry of passwords for electronic signatures in script.

Dieser Ansatz hat aber für mich drei Nachteile:
1. Er funktioniert nicht offline, also z. B. bei einer lokalen Replik, weil der Serverzugriff notwendig ist, um den Passworteingabe-Dialog zu öffnen.
2. Ich möchte es nutzen, um das Öffnen von existierenden Dokumenten abzusichern. Wenn der Benutzer den Dialog abbricht, wird das Dokument trotzdem geöffnet.
3. Der Formel-Code muss im QueryOpen-Ereignis der Maske eingetragen werden. Dort brauche ich aber zwangsläufig LotusScript.

Also musste ich weiter suchen nach einer Lösung in LotusScript. Und ich wurde fündig bei Eknori, der in 2004 diesen Blog-Eintrag verfasst hat: @Command(ToolsUserLogoff) in Lotus Script.
Diese Lösung muss für die aktuellen Versionen von Notes angepasst werden, weil man sich jetzt nicht mehr mit F5, sondern mit Strg-F5 auslogt.

Ich war immer noch nicht überzeugt, dass dies die bestmögliche Lösung für mein Problem sein sollte. Es ist wegen der Verwendung von Windows-DLLs nicht auf andere Plattformen übertragbar, der Benutzer bleibt ausgeloggt, wenn er den Passworteingabe-Dialog abbricht, es würde wohl auch nicht lokal funktionieren usw.

Ich suchte weiter und fand diese großartige Idee: Mittels Notes C-API auf den privaten Teil der Benutzer-ID-Datei zugreifen, genauer mit der  REGGetIDInfoString-Function mit REGIDGetPrivateKey als infoType.
  • Dies würde den Passworteingabe-Dialog erzwingen, aber gleichzeitig den Benutzer nicht abmelden.
  • Es würde auch lokal ohne jeden Server-Kontakt funktionieren.
  • Und ich könnte sogar feststellen, wenn der Benutzer den Dialog abgebrochen hätte und darauf falls nötig reagieren.

Vielen Dank an Davy Vanherbergen für seinen OpenNTF Code Bin-Beitrag (von 2003!): Call notes password prompt from lotusscript 

Ich habe seine Idee genommen und auf "meine Art" neu implementiert. Dabei habe ich unsere C-API-Hilfsfunktionen genutzt, und ich lasse den Benutzer eine andere ID-Datei auswählen, wenn die in der notes.ini eingestellte nicht die seine ist.

Function ValidateCurrentUser As Boolean
        '/**
        ' * validates current user by letting him enter his password
        ' *
        ' * @return  True, if user has successfully entered his password
        ' *
        ' * @author  Thomas Bahn/assono <tbahn@assono.de>
        ' * @version 2014-09-30
        ' */

        Const MAXOUTBUFRLEN% = 4096
       
        Dim idFileName As String
        Dim returnCode As Integer
        Dim userNameBuffer As String*MAXUSERNAME
        Dim actualLen As Long
        Dim currentUserName As String                
        Dim outBufrLen As String*MAXOUTBUFRLEN
       
        If Not IsDebugMode() Then On Error GoTo errorHandler
       
        ValidateCurrentUser = False
       
        idFileName = session.GetEnvironmentString("KeyFileName", True)
        returnCode = REGGetIDInfoString(idFileName, REGIDGetName, _
                userNameBuffer, MAXUSERNAME, actualLen)
        Call ShowCAPIErrorIfAnyAndEnd(returnCode, "REGGetIDInfo", _
                NULLHANDLE)
       
        currentUserName = Left(userNameBuffer, actualLen - 1)        
        Do While session.UserName <> currentUserName
                ' ID file configured in notes.ini is not the ID file of the
                ' current user
                idFileName = uiws.OpenFileDialog(False, _
                        "Wählen Sie Ihre ID-Datei:", "*.ID|", _
                        GetNotesDataDirectory(), idFileName)(0)

                returnCode = REGGetIDInfoString(idFileName, REGIDGetName, _
                        userNameBuffer, MAXUSERNAME, actualLen)
                Call ShowCAPIErrorIfAnyAndEnd(returnCode, "REGGetIDInfo", _
                        NULLHANDLE)
               
                currentUserName = Left(userNameBuffer, actualLen - 1)
        Loop
       
        returnCode = REGGetIDInfoString(idFileName, REGIDGetPrivateKey, _
                        outBufrLen, MAXOUTBUFRLEN, actualLen)
        If returnCode = -32355 Then
                Exit Function ' user cancelled dialog
        Else
                Call ShowCAPIErrorIfAnyAndEnd(returnCode, "REGGetIDInfo", _
                        NULLHANDLE)
        End If

        ' when we get here, the user must have entered his password
        ' successfully
        ValidateCurrentUser = True
        Exit Function
       
errorHandler:
        If HandleError() = RESUME_NEXT_LINE Then Resume Next
        Exit Function
End Function

GetNotesDataDirectory() ist eine Hilfsfunktion, die das Notes-Datenverzeichnis zurück gibt. Ersetze diese Funktion durch deine eigene oder einfach eine String-Konstante.
Und passe den Fehlerbehandlungscode (IsDebugMode() and HandleError()) entsprechend deinen Standards an.

Ich benötige noch einige Deklarationen (Declarations):

Private Const LIBRARY = "Eintrag utils"

' WORD LNPUBLIC OSLoadString(HMODULE hModule, STATUS StringCode, char far *retBuffer, WORD BufferLength);
Declare Function OSLoadString Lib "nnotes" Alias "OSLoadString" (ByVal hModule As Long, ByVal stringCode As Integer, ByVal retBuffer As LMBCS String, ByVal bufferLength As Integer) As Integer

' STATUS LNPUBLIC REGGetIDInfo(char far *IDFileName, WORD InfoType, void far *OutBufr, WORD OutBufrLen, WORD far *ActualLen);
Declare Function REGGetIDInfoString  Lib "nnotes" Alias "REGGetIDInfo" (ByVal idFileName As String, ByVal infoType As Integer, ByVal outBufr As String, ByVal outBufrLen As Integer, actualLen As Long) As Integer
Declare Function REGGetIDInfoBoolean Lib "nnotes" Alias "REGGetIDInfo" (ByVal idFileName As String, ByVal infoType As Integer, ByVal outBufr As Long,   ByVal outBufrLen As Integer, actualLen As Long) As Integer

Const REGIDGetName = 7 ' Data structure returned Is char xx[MAXUSERNAME]
Const REGIDGetPrivateKey = 9 ' Data structure returned Is char xx[xx]


' STATUS LNPUBLIC NSFDbClose(DBHANDLE hDB);
Declare Function NSFDbClose Lib "nnotes.dll" (ByVal hDB As Long) As Integer


Const NOERROR = 0

Const NULLHANDLE = 0&

Const MAXUSERNAME = 256


And two support functions for the C API error handling:

Sub ShowCAPIErrorIfAnyAndEnd(errorCode As Integer, functionName As String, hDB As Long)
        '/**
        ' * shows user the C API error and aborts execution.
        ' *
        ' * @param   errorCode return code of the function's execution
        ' * @param   functionName name of the C API function called
        ' * @param   hDB handle to the open database
        ' *
        ' * @author  Thomas Bahn/assono <tbahn@assono.de>
        ' * @version 2014-07-17
        ' */                
       
        If errorCode = NOERROR Then Exit Sub ' exit if no error occured
       
        If hDB <> 0 Then
                ' if there is a valid handle, try to close database
                Call NSFDbClose(hDB)
        End If
       
        Error Err, "Fehler in Bibliothek '" & LIBRARY & "'" & Chr$(10) & _
        "Ein Fehler ist aufgetreten in der C-API-Funktion'" & _
        functionName & "': "  & Chr$(10) &_
        "Fehler-Code: " & Trim$(Str$(errorCode)) & Chr$(10) & _
        "Fehler-Text: " & Chr$(10) & GetCAPIErrorMsg(errorCode)
End Sub

Function GetCAPIErrorMsg(errorCode As Integer) As String
        '/**
        ' * gets error message for the C API error.
        ' *
        ' * @param   errorCode return code of the function's execution
        ' * @return  error message for the C API error
        ' *
        ' * @author  Thomas Bahn/assono <tbahn@assono.de>
        ' * @version 2014-07-17
        ' */        
       
        Dim length As Integer
        Dim buffer As String
       
        ' initialize a buffer of adequate length to accept the error string
        buffer = String$(256, 0)
       
        ' get the API error message from the internal Notes/Domino string
        ' tables
        length = OSLoadString(NULLHANDLE, errorCode, buffer, Len(buffer))
        If length > 0 Then
                ' remove any trailing characters from the string and
                ' return it to the caller
                GetCAPIErrorMsg = Left$(buffer, InStr(1,buffer,Chr$(0))-1)
        Else
                ' couldn’t locate the error message in the string tables
                GetCAPIErrorMsg = "Unbekannter Fehler"
        End If
End Function

Schließlich platziere Code ähnlich dem folgenden in das QueryOpen-Ereignis deiner Maske:

If continue Then
        continue = ValidateCurrentUser()
       
        If continue Then
                ' do some stuff if necessary
        End If
End If

Da der Code ausschließlich Notes C-API-Aufrufe benutzt, kann er leicht auf weitere Plattformen erweitert werden. Momentan ist er auf Windows beschränkt.

Agenda der 41. DNUG Konferenz ist online – jetzt informieren & anmelden!

22. September 2014 Posted by Solveig Schwennicke

Die DNUG Herbstkonferenz 2014 vom 11. - 12. November in Leipzig bietet Anwendern von IBM Collaboration Solutions nicht nur eine Plattform zum Networking & Erfahrungsaustausch sondern auch jede Menge Vortragshighlights - u.a.

 

  • Keynotes von Chris Crummey, Dr. Thomas Zeizel & Prof. Dr. Welsch (IBM),
  • Technik-Tracks für Admins & Entwickler an beiden Konferenztagen,
  • weitere Vortragsreihen zu IT-Strategie, IBM Solutions, Software Adoption, Social Business & User Experience, Agilem Projektmanagement & Business Partner Solutions,
  • u.v.m.

 

Jetzt informieren & anmelden!

 

Quick-Tipp: Script-Bibliothek verhindert Ausführung eines Agenten

21. August 2014 Posted by Thomas Bahn

Quick-TippIBM Notes
Heute konnte ich ein Problem eines meiner Kunden lösen: Ein geplanter Server-Agent lief einfach nicht!

Eigentlich lief er doch, nur tat er einfach nichts. Wenn man ihn z. B. per Agent Manager aufgerufen hat (z. B. mit tell amgr run "some-db.nsf" 'Test'), erschienen folgende zwei Zeilen im Server-Protokoll:
AMgr: Start executing agent 'Test' in 'some-db.nsf'
AMgr: Agent 'Test' in 'some-db.nsf' completed execution
Aber selbst ein einfaches Print "TEST" in der ersten Zeile der Initialize-Prozedur gab nichts aus - gar nicht erst zu sprechen von der eigentlichen Aufgabe des Agenten.

Wir haben (wirklich!) alles geprüft, was irgendwie Einfluss haben könnte - u.a. die Einstellungen zur Server-Sicherheit, die Anwendungseigenschaften ("Hintergrundagenten in dieser Datenbank nicht ausführen"), Zugriffskontrollliste (ACL), die Eigenschaften des Agenten...

Dann habe ich Schritt für Schritt den Agenten nachgebaut. Erst die Use-Befehle, dann Stück für Stück den restlichen Code, und alles getestet, wieder und wieder: Es lief so wie es sollte.

Schließlich habe ich den vermeintlich "korrupten" Agenten gelöscht und den neue Agenten umbenannt, so dass er hieß, wie der alte. Und in dem Moment hörte er auf zu funktionieren!

Okay, wieder zurück umbennant - läuft. Noch einmal auf den Namen des ursprünglichen Agenten geändert - läuft nicht.

Weiter im Domino Administrator den "Gottmodus" (Full-access administration) aktiviert und die Datenbank neu im Designer inspiziert. Gibt es vielleicht einen bisher unsichtbaren Agenten mit dem gleichen Namen? Nöps, auch nichts.

Aber ich fand eine Script-Bibliothek mit exakt demselben Namen wie der Agent. Naja, vielleicht... Umbenannt ... und ... der ... Agent ... LÄUFT!

Was habe ich daraus gelernt: Eine Script-Bibliothek verhindert die Ausführung eines Agenten, wenn beide gleich heißen!

Call for Abstracts zur 41. DNUG Konferenz in Leipzig – Tracks Administration & Anwendungsentwicklung

28. Juli 2014 Posted by Solveig Schwennicke

Wir laden Sie ganz herzlich ein, sich an der Vorbereitung der Agenda-Tracks Administration & Anwendungsentwicklung zur nächsten DNUG Konferenz am 11. und 12. November 2014 zu beteiligen.

 

Bringen Sie Ihre Themen aktiv ein - bewerben Sie sich im Rahmen des "Calls for Abstracts" bis zum 8. August 2014.

 

--> Technik - Administration & Infrastruktur

- Schwerpunkte & Modalitäten - Link

- Themenbeschreibung - Link

 

--> Technik - Anwendungsentwicklung

- Schwerpunkte & Modalitäten - Link

- Themenbeschreibung - Link

41. DNUG Konferenz: Sponsor DCCS IT Business Solutions zeigt AppDev mit XPages für Mobile Devices

25. Juli 2014 Posted by Solveig Schwennicke

Besondere Schwerpunkte des Sponsors DCCS IT Business Solutions liegen auf den Kompetenzfeldern Portale, Collaboration, Enterprise 2.0, Business Intelligence und eProcurement. Zur DNUG Konferenz in Leipzig trägt der Dienstleister für individuelle Software Entwicklung und IT Beratung zum Thema „AppDev mit XPages für Mobile Devices“ vor.

www.dccs.at

 

 

Mehr Informationen zur Konferenz:

Quick-Tipp: ‘Verbergen-Formeln von Aktionen bei jedem Dok’wechsel prüfen’ funktioniert nicht

24. Juli 2014 Posted by Thomas Bahn

Quick-TippIBM Notes
Es gibt immer mal wieder Tage, wo einem das Offensichtliche nicht ins Gesicht springt und man sucht und sucht und sucht...

Man kann bei einer Ansicht eine Eigenschaft einstellen, dass die Verbergen-Wenn-Formeln (hide when) jedes mal neu berechnet werden, wenn man auf ein anderes Dokument in der Ansicht geht bzw. darauf klickt.
A picture named M2

Das braucht man, wenn man z. B. Ansicht-Aktionen abhängig von Status des Dokuments anzeigen möchte, also die Aktion "Antrag genehmigen" in der Ansicht nur anzeigen möchte, wenn der aktuell ausgewählte Antrag auf "zu genehmigen" steht.

Ich wollte eine Aktion zum Kopieren des Feldinhalts in die Zwischenablage nur dann anzeigen, wenn das Feld "Passwort" ausgefüllt ist:
A picture named M3

So einfach funktioniert das - normalerweise. Und die gleiche Aktion in der Maske funktionierte auch, nur eben nicht in der Ansicht.

Nach längerer Suche und viel Ausprobieren bin ich dann auf die Lösung gekommen. Kern des Problems war, dass das Feld "Passwort" verschlüsselt gespeichert wird:
A picture named M4

Verschlüsselte Felder werden nicht "normal" im Dokument gespeichert, sondern in $SealData-Items.
A picture named M5

Sie können dann weder in Spalten angezeigt, noch in Spalten- oder Aktionsformeln benutzt werden.

Als Lösung habe ich ein neues Feld "PasswortEingegeben" in der Maske hinzugefügt, dass nur die Information speichert, ob das Passwort-Feld gefüllt ist. Im geöffneten Dokument kann man ja noch einfach auf die verschlüsselten Felder zugreifen.
A picture named M6

Danach habe ich das neue Feld in der Verbergen-Wenn-Formel der Aktion benutzt:
A picture named M7

Und es funktioniert!

Quick-Tipp: Wie du die lästigen Fehlermeldungen des Schedulers beim Domino-Server-Start los wirst

18. Juli 2014 Posted by Thomas Bahn

Quick-TippIBM Domino
Chris Miller ist sicherlich einer der besten Domino-Administratoren der Welt. Er schreibt auch regelmäßig für die SocialBiz user group und beantwortet dort schwierige Fragen rund um die IBM Notes und Domino-Administration.

Letzte Woche hat er darüber geschrieben, wie man gezielt Datenbanken vom Scheduler und Rooms and Resources Manager ausnimmt: From the SocialBiz Mailbox: Excluding Calendars from Mail-in Databases  


Du kennst wahrscheinlich auch diese "Fehlermeldungen" des Schedulers und des RnRMgr, die jedesmal kommen, wenn einer der beiden Prozess auf eine Datenbank stößt, zu der er den Eigentümer nicht (mehr) im Domino-Verzeichnis findet:
SchedMgr: Error processing calendar profile document (NoteID: NT....) in database...:
Can't find $BusyName field on profile

SchedMgr: Error processing calendar profile document (NoteID: NT...) in database ...:
Cannot find user in Domino Directory


Dass passiert zum Beispiel wenn das Personen-Dokument gelöscht wurde (Mitarbeiter arbeitet nicht mehr für das Unternehmen) und bei Mail-In-Datenbanken.

Die beiden Prozesse sind wichtig, um die Freie-Zeit-Datenbank (busytime.nsf bzw. clubusy.nsf) immer auf dem aktuellen Stand zu halten. Aber bei bestimmten Datenbanken ist das einfach nicht (mehr) relevant. Und da wäre es doch toll, wenn man den beiden Prozessen einfach sagen könnten: "Diese Datenbank bitte ignorieren."

Und Chris kennt eine Lösung: In kleines Programm namens "NoCal".

Leider hat es ein paar Nachteile
  • Es ist wirklich, wirklich alt: Release: R5, Platform: Windows 95/98/NT, Date Posted: 04.05.2001,
  • es muss von der Kommandozeile aus gestartet werden und
  • es kann die "Has Calendar"-Datenbank-Option nur ausschalten, nicht wieder anschalten, wenn man aus Versehen die falsche Datenbank erwischt hat.
Es juckte mich in den Fingern: Das kann ich doch besser, oder?  
  • Meine Lösung sollte klein und transportabel sein, wie z. B. ein Agent, den man einfach in die Schablone oder jede Datenbank packen kann,
  • sie sollte in der Lage sein, die Option an- und auszuschalten und
  • sie sollte einfach aus dem Notes-Client heraus aufgerufen werden können.
Nach ausgiebiger Recherche, vielen (erfolglosen) Versuchen und einigen C-API-Aufrufen habe ich es geschafft.

Im Kern sieht der Agent so aus:

Sub Initialize
        '/**
        ' * gets current database's options, prints "Has Calendar" option,
        ' * toggles it and prints new status
        ' *
        ' * @author        Thomas Bahn/assono <tbahn@assono.de>
        ' * @version        2014-07-17
        ' */                

        Dim session As NotesSession
        Dim returnCode As Integer
        Dim hDB As Long
        Dim retDbOptions As Long
       
        On Error GoTo miniErrorHandler

        Set session = New NotesSession
       
        ' open the current database
        returnCode = NSFDbOpen(session.CurrentDatabase.FilePath, hDB)
        Call ShowCAPIErrorIfAnyAndEnd(returnCode, "NSFDbOpen", hDB)

        ' get current options
        returnCode = NSFDbGetOptions(hDB, retDbOptions)
        Call ShowCAPIErrorIfAnyAndEnd(returnCode, "NSFDbGetOptions", hDB)
       
        ' print current status
        If retDbOptions And  DBOPTION_HAS_CALENDAR Then
                Print "Database has calendar"
        Else
                Print "Database doesn't have calendar"
        End If
       
        ' toggle option
        returnCode = NSFDbSetOptions(hDB, _
                        retDbOptions Xor DBOPTION_HAS_CALENDAR, _
                        DBOPTION_HAS_CALENDAR)
        Call ShowCAPIErrorIfAnyAndEnd(returnCode, "NSFDbSetOptions", hDB)
       
        ' get current options
        returnCode = NSFDbGetOptions(hDB, retDbOptions)
        Call ShowCAPIErrorIfAnyAndEnd(returnCode, "NSFDbGetOptions", hDB)
       
        ' print new status
        If retDbOptions And  DBOPTION_HAS_CALENDAR Then
                Print "Database now has calendar"
        Else
                Print "Database now doesn't have calendar"
        End If
       
        ' close the database
        returnCode = NSFDbClose(hDB)
        Exit Sub
       
miniErrorHandler:
        MessageBox "Error #" & Err & " occurred in line " & Erl & Chr$(10) &_
                "Error message: " & Chr$(10) & Error$, 48, "Error"
       
        If hDB <> 0 Then ' if there is a valid handle, try to close database
                returnCode = NSFDbClose(hDB)
        End If
End Sub

Er braucht noch einige Deklarationen (Declarations):

' STATUS LNPUBLIC NSFDbOpen(char far *PathName, DBHANDLE far *rethDB);
Declare Function NSFDbOpen Lib "nnotes.dll" (ByVal pathName As LMBCS String, rethDB As Long) As Integer

' WORD LNPUBLIC OSLoadString(HMODULE hModule, STATUS StringCode, char far *retBuffer, WORD BufferLength);
Declare Function OSLoadString Lib "nnotes" Alias "OSLoadString" (ByVal hModule As Long, ByVal stringCode As Integer, ByVal retBuffer As LMBCS String, ByVal bufferLength As Integer) As Integer

' STATUS LNPUBLIC NSFDbGetOptions(DBHANDLE  hDB, DWORD far *retDbOptions);
Declare Function NSFDbGetOptions Lib "nnotes.dll" (ByVal hDB As Long, retDbOptions As Long) As Integer

' STATUS LNPUBLIC NSFDbSetOptions(DBHANDLE hDB, DWORD DbOptions, DWORD Mask);
Declare Function NSFDbSetOptions Lib "nnotes.dll" (ByVal hDB As Long, ByVal dbOptions As Long, ByVal mask As Long) As Integer

' STATUS LNPUBLIC NSFDbClose(DBHANDLE hDB);
Declare Function NSFDbClose Lib "nnotes.dll" (ByVal hDB As Long) As Integer

' DBOPTION_HAS_CALENDAR          -  TRUE if database stores calendar events.
Const DBOPTION_HAS_CALENDAR& = &H00002000

Const NOERROR = 0

Const NULLHANDLE = 0&


Und zwei unterstützende Funktionen für die C-API-Fehlerbehandlung:

Sub ShowCAPIErrorIfAnyAndEnd(errorCode As Integer, functionName As String, hDB As Long)
        '/**
        ' * shows user the C API error and aborts execution.
        ' *
        ' * @param        errorCode return code of the function's execution
        ' * @param        functionName name of the C API function called
        ' * @param        hDB handle to the open database
        ' *
        ' * @author        Thomas Bahn/assono <tbahn@assono.de>
        ' * @version        2014-07-17
        ' */                
       
        If errorCode = NOERROR Then Exit Sub ' exit if no error occured
       
        MessageBox _
        "An error occurred in C API function '" & functionName & "'"  & Chr$(10) &_
        "Error code: " & Trim$(Str$(errorCode)) & Chr$(10) & _
        "Error message:" & Chr$(10) & GetCAPIErrorMsg(errorCode), _
        48, "Error calling C API"
       
        If hDB <> 0 Then ' if there is a valid handle, try to close database
                Call NSFDbClose(hDB)
        End If
        End
End Sub

Function GetCAPIErrorMsg(errorCode As Integer) As String
        '/**
        ' * gets error message for the C API error.
        ' *
        ' * @param        errorCode return code of the function's execution
        ' * @return        error message for the C API error
        ' *
        ' * @author        Thomas Bahn/assono <tbahn@assono.de>
        ' * @version        2014-07-17
        ' */                
       
        Dim length As Integer
        Dim buffer As String
       
        ' initialize a buffer of adequate length to accept the error string
        buffer = String$(256, 0)
       
        ' get the API error message from the internal Notes/Domino string tables
        length = OSLoadString(NULLHANDLE, errorCode, buffer, Len(buffer))
        If length > 0 Then
                ' remove any trailing characters from the string
                GetCAPIErrorMsg = Left$(buffer, InStr(1, buffer, Chr$(0)) - 1)
        Else
                ' couldn’t locate the error message in the string tables
                GetCAPIErrorMsg = "Unknown error"
        End If
End Function

Erstelle einfachen einen LotusScript-Agenten, der manuell gestartet wird mit dem Ziel "Keine".

Hier ist eine kleine Datenbank mit dem Agenten - fertig zum Kopieren:


Die Datenbank enthält auch eine erweiterte Version des Agenten, mit dem man andere Datenbanken umstellen kann.
Der Benutzer wählt als erstes die Datenbank aus, bekommt den aktuellen Status angezeigt und kann dann entscheiden, ob er die Einstellung ändern möchte.
A picture named M2


Wichtig: Soweit meine Versuche ergeben haben, wird die Änderungen der Datenbank-Option nicht repliziert. Du musst also jede Replik auf jedem Server einzeln umstellen.

Domino Designer and XPages Extensibility APIs Javadoc 9.0.1

10. Juni 2014 Posted by Bernd Hort

XPages

During IBM Connect this year I asked in the developer lab about an update for the Javadoc documentation which came with the first version of the Extension Library.

A couple of days ago I finally found it in the Domino Wiki:

Domino Designer & XPages Extensibility APIs Javadoc 9.0.1

It is a really helpful source for anybody who wants to dive deeper into XPages.

Thank you IBM


Quick-Tipp: Optionale berechnete Teilmaske

30. Mai 2014 Posted by Thomas Bahn

Quick-TippIBM Notes
Manchmal möchte man eine Teilmaske in eine Maske nur einfügen, wenn eine Bedingung erfüllt ist, z. B. wenn ein bestimmter Status im Workflow erreicht wurde. Gegenüber dem Verstecken mit "Hide-When"-Formeln hat das den Vorteil, dass der Notes-Client entsprechend weniger berechnen muss (Hide-When-Formeln selbst, aber ggf.auch viele @DbLookups, Werte-Formeln, usw.) und das Dokument von unnötigen Items verschont bleibt. Dafür gibt es bei Notes die Möglichkeit der Berechneten Teilmaske.

Für eine Anpassung der Mail-Datenbank hatte ich kürzlich wieder mal diesen Fall. Nur wenn in den Mail-Vorgaben die Funktion "Zentrale Ablage" aktiviert wurde, sollte die Teilmaske zur Auswahl der zentralen Ablage und zur Verschlagwortung des Dokuments angezeigt werden. Die Formel der Berechneten Teilmaske in der Memo- und den beiden Reply-Masken sah dann (vereinfacht) so aus:
@If(
        @GetProfileField("CalendarProfile"; "CentralFilingStatus") = "1";
        "CentralFiling";
        ""
)

Das funktioniert auch wunderbar.

Einige Tage später kam dann ein Kollege auf mich zu und machte mich darauf aufmerksam, dass in der Statuszeile immer wieder die Meldung "Element des Dokuments nicht gefunden" erschien. Nach kurzer Analyse konnte ich die Meldung mit der Berechneten Teilmaske in Verbindung bringen.

Meine erste Lösung:
Eine leere Teilmaske z. B. "EmptySubform" - erstellen und deren Name (oder Alias) in die Formel einfügen:
@If(
        @GetProfileField("CalendarProfile"; "CentralFilingStatus") = "1";
        "CentralFiling";
        "EmptySubform"
)

Die zweite, etwas elegantere Lösung:
Statt des leeren Strings @Nothing zurück geben:
@If(
        @GetProfileField("CalendarProfile"; "CentralFilingStatus") = "1";
        "CentralFiling";
        @Nothing
)

EntwicklerCamp 2014: XPages – WebServices und REST

19. März 2014 Posted by Bernd Hort

EntwicklerCamp

Der letzte Tag des EntwicklerCamps ist gekommen. Heute war mein zweiter Vortrag zum Thema "XPages - WebServices und REST". In 90 Minuten habe ich ausführlich beschrieben, wie Webservices und RESTful Webservices innerhalb von XPages konsumiert werden können. Die erste Hälfte des Vortrages konzentrierte sich auf das Backend mittels Java. In der zweiten Hälfte habe ich den Blick auf JavaScript im Browser gerichtet.

Wie immer können die Folien und die Beispiel-Anwendung heruntergeladen werden. Basis für diesen Vortrag war mein Vortrag auf der IBM Connect 2014: BP 206 - Be Open - Use Web Services and REST in XPages Applications. Insofern ist die Beispiel-Anwendung die gleiche wie beim IBM Connect-Vortrag.

 

In der Beispiel-Anwendung befinden sich nicht nur XPages, um die Webservices und RESTful Webservices zu konsumieren. Damit die Beispiele auch bei Ihnen ohne Probleme laufen, sind ein Webservice und drei RESTful Webservices implementiert.

Webservice

Die WSDL-Datei zu dem Webservice kann über
http://{Ihr-Server}/{Datenbank-Pfad}/sessionService?wsdl
erreicht werden.

RESTful Webservice

Um verschiedene Techniken zu zeigen, gibt es insgesamt 3 RESTful Webservices, die alle die XPages Extension Library - OpenNTF benötigen.

Custom Database Servlet

Der erste RESTful Webservice verwendet ein Custom Database Servlet.
http://{Ihr-Server}/{Datenbank-Pfad}/xsp/services/Sessions
CustomDatabaseServlet.png

RESTService Control - xe:viewJsonService

Der zweite RESTful Webservice basiert auf einem viewJsonService.
http://{Ihr-Server}/{Datenbank-Pfad}/extensionlibrary.xsp/sessions
viewJsonService.png

RESTService Control - xe:customRestService

Zu guter Letzt gibt es einen RESTful Webservice als customRestService
http://{Ihr-Server}/{Datenbank-Pfad}/customrestservice.xsp/sessions
http://{Ihr-Server}/{Datenbank-Pfad}/customrestservice.xsp/sessions/BP206
customRestService1.png
customRestService2.png