disableXspCache: Programmatisch GZip-Komprimierung abschalten

Mit einem kleinen Trick kann die GZip-Komprimierung einer XPage programmatisch abgeschaltet werden: Schaltet man im beforeRenderResponse-Event einer XPage den XspCache des Servlets aus, kann man hierbei ebenfalls die GZip-Komprimierung deaktivieren. Hierfür bietet die XspHttpServletResponse die Methode disableXspCache; wird diese mit dem Parameter false aufgerufen, wird die GZip-Komprimierung abgeschaltet.

Hier ein kleines Beispiel:

<xp:this.beforeRenderResponse>
    <![CDATA[#{javascript:
        var response:com.ibm.xsp.webapp.XspHttpServletResponse;
        response = facesContext.getExternalContext().getResponse();
        response.disableXspCache(false);
    }]]>
</xp:this.beforeRenderResponse>

Mit der Methode isDisableXspCache() kann abgefragt werden, ob der XspCache deaktiviert ist, oder nicht.

Veröffentlicht unter Java, Performance, Server, Web, XPages | Verschlagwortet mit , , , , , , | Schreib einen Kommentar

Java not found

Tippfehler werden von Domino (8.5.2) hart bestraft! Java kann nicht mehr gefunden werden!

Die Hashmap muß natürlich „HashMap“ heissen, und nicht „Hashmap“. Dann klappts auch…

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
    <xp:scriptBlock id="scriptBlock1"
        value="#{javascript:
            var data:java.util.HashMap = new java.util.HashMap();}">
    </xp:scriptBlock>
</xp:view>

 

Veröffentlicht unter Allgemein, Errorhandling, Java, Server, ServerSide JavaScript, XPages | Verschlagwortet mit , , , , , , | Schreib einen Kommentar

Casten von Objekten in SSJS

Beim Zugriff auf die Daten eines im Dokument gespeicherten RichText-Item ist es notwendig, das Ergebnis in ein RichTextItem umzuwandeln, da die Methode „getFirstItem()“ eines NotesDocument-Objektes nur ein normales NotesItem zurück liefert.

In Java läßt sich das durch das Casten in den gewünschten Objekt-Typ bewerkstelligen:

attachments  = (RichTextItem) document.getFirstItem("Attachments")

In SSJS ist die Syntax nicht erlaubt. Um dennoch das gewünschte Resultat zu erzielen, muß man den gewünschten Typen des resultierenden Objektes in dessen Definition vorgeben. Das Casten wird dann intern vom Dominoserver vorgenommen:

var attachments:RichTextItem  = document.getFirstItem("Attachments")
Veröffentlicht unter Allgemein, Java Script, ServerSide JavaScript, XPages | Verschlagwortet mit , , , , , | Schreib einen Kommentar

Bug: java.io.File & die Methode „delete()“

Die Methode „delete()“ für ein java.io.File-Objekt ist im Domino Designer leider nicht verwendbar, denn hier gibt es einen groben Bug (unter 8.5.2FP2 und 8.5.1).

Man erhält eine Syntax-Fehler, der nicht behebbar ist; das Highlighting versagt hier völlig (die Methode wird rot hervorgehoben, wie sonst nur spezielle Schlüsselwörter).

Alternativ läßt sich nur die „deleteOnExit()„-Methode verwenden, oder die Datei muß per Agent gelöscht werden.

<xp:this.beforeRenderResponse>
<![CDATA[#{javascript:
   var file:java.io.File = new java.ioFile();
   file.deleteOnExit()}]]>
</xp:this.beforeRenderResponse>
Veröffentlicht unter Java Script, ServerSide JavaScript, XPages | Verschlagwortet mit , , , , , | 2 Kommentare

Zeta-Dialog: Erweiterung um „Closable“-Parameter

Jeremy Hodge hat den dijit.Dialog erweitert und die wunderbare Komponente ZetaDialog für die Domino-Welt bereitgestellt, einen XPages-Kompatiblen Dojo Dialog. Doch leider fehlt dem Dialog eine Kleinigkeit, nämlich die Möglichkeit, zu Verhindern, das der User das Dialogfenster per <ESC> oder Close-Icon einfach schließt.

Daher habe ich den Code ergänzt, so dass dies programmatisch unterbunden werden kann:

<xp:scriptBlock id="scriptBlockZetaDialog">
    <xp:this.value><![CDATA[dojo.addOnLoad( function(){ 
            dijit.byId('#{id:zeta}').setCloseButtonDisabled( true );
            dijit.byId('#{id:zeta}').show(); } )]]>
    </xp:this.value>
</xp:scriptBlock>

[In Fett: die Funktion setCloseButtonDisabled verhindert das Schließen durch den User]

Hier der vollständige ergänzte Sourcecode:

//Licensed under http://creativecommons.org/licenses/by/3.0/
//
//Modified by Sven Hasselbach: Now dialog no longer closable if required!
//http://blog.hasselba.ch
//
//Oringinal Code from Jeremy Hodge on the XPages Blog
//http://xpagesblog.com/xpages-blog/2010/4/10/xpages-compatible-dojo-dialog-reusable-component.html

// com.ZetaOne.Widget.Dialog
dojo.provide('com.ZetaOne.widget.Dialog');
dojo.require('dijit.Dialog');
(function(){
    dojo.declare("com.ZetaOne.widget.Dialog", dijit.Dialog, {
            disableCloseButton: false,
             _onKey: function(evt)
            {
                if(this.disableCloseButton && 
                   evt.charOrCode == dojo.keys.ESCAPE) return;
                this.inherited(arguments);
            },
            setCloseButtonDisabled: function(flag)
            {
                this.disableCloseButton = flag;
                this._updateCloseButtonState();
            },
            _updateCloseButtonState: function()
            {
                dojo.style(this.closeButtonNode,
                "display",this.disableCloseButton ? "none" : "block");
            },
            postCreate: function(){
                this.inherited(arguments);
                this._updateCloseButtonState();
                dojo.query('form', dojo.body())[0].appendChild(this.domNode);
            },
            _setup: function() {
                this.inherited(arguments);
                if (this.domNode.parentNode.nodeName.toLowerCase() == 'body')
                    dojo.query('form', dojo.body())[0].appendChild(this.domNode);                
            }                
        })
}());
Veröffentlicht unter Allgemein, Dojo Toolkit, HTML, Java Script, Web, XPages | Verschlagwortet mit , , , , , | Schreib einen Kommentar

HTTP Daten debuggen

Manchmal ist sehr nützlich, sich die HTTP Daten so anzuschauen, wie sie auf dem Dominoserver auch ankommen. Dafür ist dieser kleine Agent gedacht, den man in einer beliebeigen Datenbank ablegen kann und dann mittels

http://server/pfad/zur/db.nsf/HTTPDebug?OpenAgent

aufrufen kann.

Hier der Code:

REM
        Agent HTTPDebug
        Created Sep 2, 2011 by Sven Hasselbach
%END REM
Option Public
Option Declare

Sub Initialize
        Dim session As New NotesSession
        Dim doc As NotesDocument
        Dim item As NotesItem

        Set doc = session.Documentcontext

        Print |<html><head><title>HTTPDebug</title></head>|
        Print |<body><table border="1" width="100%">|
        ForAll it In doc.Items

                Set item = it
                Print |<tr><td><b>| & item.Name & |</b></td>|
                Print |<td>| & item.Text & |</td></tr>|

        End ForAll

        Print |</table></body></html>|
End Sub
Veröffentlicht unter Agenten, Errorhandling, HTML, Lotus Script, Server, Web | Verschlagwortet mit , , , , , , , | Schreib einen Kommentar

HTTP-Passwortänderung sofort übernehmen

Wird das HTTP-Passwort eines Users im NAB geändert, wird diese Änderung nicht sofort übernommen, sondern es kann 5 Minuten und länger dauern, bis der Dominoserver die Änderung übernimmt. Dies liegt an zwei Umständen:

Zum Einen ist die Ansicht „($Users)“ im NAB noch nicht aktualisiert, zum Anderen muss der NameLookup-Cache auf dem Server aktualisiert werden.

Hier ein Lotusscript-Agent, der genau diese Aktionen durchführt:

REM
        Agent RefreshNAB
        Created Sep 2, 2011 by Sven Hasselbach
%END REM
Option Public
Option Declare

Sub Initialize
        Dim session As New NotesSession
        Dim nab As NotesDatabase
        Dim view As NotesView
        Dim doc As NotesDocument
        Dim ret
       
        On Error GoTo errH
       
        ' --- open NAB
        Set nab = New NotesDatabase("","names.nsf")
        If Not nab.Isopen Then
                nab.Open nab.Server, nab.Filepath
                If Not nab.Isopen Then
                   Error 10000, "Unable to open NAB!"
                End If
        End If
       
        ' --- refresh users view
        Dim usersView As NotesView
        Set usersView = nab.Getview("$Users")
        usersView.Refresh
       
        ' --- run console
        session.Sendconsolecommand "", "show nlcache reset"
       
the_end:
        Exit Sub
       
errH:
        Print "Error #" & Err & ": '" & Error & "' @ Line " & Erl
        Resume the_end
       
End Sub

 

Veröffentlicht unter Agenten, Allgemein, Infrastruktur, Lotus Script, Server, Web | Verschlagwortet mit , , , , , , | Schreib einen Kommentar

Das Speichern von Dokumenten & Events

Speichert man ein Dokument über die Javascript-Methode „save()„, werden die Events (QuerySave, Compute und PostSave) nicht ausgeführt.

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
   <xp:this.data>
      <xp:dominoDocument var="doc">
         <xp:this.querySaveDocument>
            <![CDATA[#{javascript:print ( "querySave" ) }]]>
         </xp:this.querySaveDocument>
      </xp:dominoDocument>
   </xp:this.data>

<xp:link escape="true" text="Link" id="link1">
   <xp:eventHandler event="onclick" submit="true"
   refreshMode="complete">
      <xp:this.action>
         <xp:executeScript script="#{javascript:doc.save()}">
         </xp:executeScript>
      </xp:this.action>
   </xp:eventHandler>
</xp:link>

</xp:view>

[In Fett: Speichern mittels „save()“]

Auf der Serverkonsole wird kein „QuerySave“ ausgegeben, das Event wird nicht ausgeführt. Damit die Events ausgeführt werden, muß die XPages-interne Funktion aufgerufen werden:

<xp:link escape="true" text="Link" id="link1">
   <xp:eventHandler event="onclick" submit="true"
      refreshMode="complete">
      <xp:this.action>
         <xp:saveDocument></xp:saveDocument>
      </xp:this.action>
   </xp:eventHandler>
</xp:link>

Verwendet man mehrere Datasources, muß die Reihenfolge beachtet werden, denn nur die letzte Datenquelle ist von der Aktion betroffen.

Allerdings kann man auch die Eigenschaften  eines Save-Buttons verwenden, um ein Event dazu zu bewegen, ein Dokument zu speichern und die Events der Datenquellen auszuführen:

<xp:link escape="true" text="Link" id="link2">
   <xp:eventHandler event="onclick" submit="true"
      refreshMode="complete" immediate="false" save="true">
   </xp:eventHandler>
</xp:link>

[In Fett: Die Eigenschaften eines Save-Buttons auf einem Link]

EDIT:

Nutzt man die Aktion „<xp:saveDocument>“ kann man die zu speichernde Datasource mittels dem „var„-Parameter angeben. Dann ist die Reihenfolge der Datasources irrelevant:

<xp:saveDocument var="trialDoc"></xp:saveDocument>

[In Fett: Erzwungene Speicherung der Datasource „trialDoc“]

Veröffentlicht unter Allgemein, ServerSide JavaScript, XPages | Verschlagwortet mit , , , , , | Schreib einen Kommentar

NotesException: Search

Heute erhielt ich beim Entwickeln einer Applikation eine interessante Fehlermeldung:

Screenshot NotesException: Search

Screenshot: Unable to create new document - NotesException: Search

Erst der Stacktrace gibt eine grobe Spur, weshalb das Problem auftritt (ich habe mich daran gewöhnt, praktisch niemals eine wirklich auf den ersten Blick aussagekräftige Information im Stacktrace zu finden)

...
NotesException: Search
    com.ibm.domino.napi.c.BackendBridge.computeWithForm(Native Method)
...

[Fett: „computeWithForm“ schlägt fehl]

Im Code der XPage findet sich dann die Ursache: Der Formname ist falsch, die Form existiert also nicht.

<xp:this.data>
    <xp:dominoDocument var="trialDoc" formName="trialFomr"
        computeWithForm="both" concurrencyMode="force">
    </xp:dominoDocument>
</xp:this.data>

[Fett: Der Formname // In Rot: Der Typo]

Nach dem Ändern des Namens ist der Fehler behoben und die XPage läuft. Nicht wirklich kompliziert, aber es ist wiedermal eine „aussagekräftige“ Fehlermeldung geworfen worden, die mehr Verwirrung stiftet, als wirklich hilft…

Veröffentlicht unter Allgemein, Errorhandling, JSF, XPages | Verschlagwortet mit , , , , | Schreib einen Kommentar

Dynamisches Data Binding

Das Data Binding ist eine  einfache und komfortable Möglichkeit, Datenquellen und XPages miteinander zu verbinden. Zum Einen lassen sich Frontend und Backend miteinander koppeln (also z.B. Feld eines Notes Dokumentes mit einem Label auf der XPage), zum Anderen ist eine Speicherung von Informationen innerhalb der XPages-Applikation möglich (z.B. das Ablegen eines Wertes im sessionScope-Objekt).

<xp:inputText id="inputText1"
   value="#{document1.feldName}">
</xp:inputText>

[Data binding einer Datenquelle an ein Textfeld // In Fett: Die Zuweisung per Expression Language(EL)]

Data bindings lassen sich auch dynamisch erstellen, da die Zuweisung während des Aufbauens des JSF-Baumes geschieht: Wird die Berechnung des Bindings währenddessen durchgeführt, ist es möglich, z.B. eine Zuweisung durch die Expression Language (EL) programmatisch zu beeinflussen.

<xp:inputText id="inputText1">
   <xp:this.value><![CDATA[${javascript:
      var fName = "Test";
      return '#{document1.' + fName + '}';
   }]]></xp:this.value>
</xp:inputText>

[Fett: Der Name der Variable // In Rot: „Compute On Page Load“]

Dadurch, dass die Berechnung auf „Compute On Page Load“ gesetzt ist, kann eine Variable programmatisch zugewiesen werden. Im obigen Beispiel existiert jetzt eine Zuweisung der Textfeldes an „document1.Test„.

Hierdurch lassen sich einige „Spielereien“ realisieren, z.B. dynamische Zuweisungen von requestScope-Variablen:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">

<xp:div id="refreshMe">
<xp:repeat id="repeat1" rows="30" var="varcollection"
   repeatControls="true" indexVar="index">
   <xp:this.value>
      <![CDATA[${javascript:return @Explode("1,2,3,4,5",",");}]]>
   </xp:this.value>
   <xp:radioGroup id="radioGroup1">
      <xp:this.value><![CDATA[${javascript:
         var fieldName = "Radio_" + index;
         return '#{requestScope.' + fieldName + '}';}]]>
      </xp:this.value>
      <xp:selectItem itemLabel="Value1"
         itemValue="Value1"></xp:selectItem>
      <xp:selectItem itemLabel="Value2"
         itemValue="Value2"></xp:selectItem>
   </xp:radioGroup>
   <xp:br></xp:br>
</xp:repeat>

<xp:label id="label1">
   <xp:this.value><![CDATA[#{javascript:var txt = "";
      try{
         for( i=0; i<requestScope.size(); i++ ){
            if( requestScope.containsKey( "Radio_" + i ) )
            txt += requestScope.get("Radio_" + i);
         }
      }catch(e){}
      return txt;}]]>
   </xp:this.value>
</xp:label>
</xp:div>

<xp:button value="Submit" id="button1">
   <xp:eventHandler event="onclick" submit="true"
      refreshMode="partial" refreshId="refreshMe">
   </xp:eventHandler>
</xp:button>
</xp:view>

[Dynamische Zuweisung von Radio-Buttons zum Requestscope innerhalb eines RepeatControls // In Fett: Handling der dynamischen requestScope-Variablen]

Das hier gezeigte Beispiel legt fünf Radio-Button-Gruppen an, die an das requestScope-Objekt gebunden werden. Wird der Button angeklickt, werden die Daten an den Server gesendet und die ausgewählten Werte im Label angezeigt.

Veröffentlicht unter Allgemein, Expression Language, JSF, ServerSide JavaScript, XPages | Verschlagwortet mit , , , , , | Schreib einen Kommentar