Posts Tagged: ‘ServerSide JavaScript’

Der neue HTTP Header ‘X-XspRefreshId’

5. Dezember 2011 Posted by Sven Hasselbach

Mit Domino 8.5.3 ist der neue HTTP Header ‘X-XspRefreshId’ eingeführt worden, mit dem sich die refreshId eines Partial Refreshs vom Server aus verändern lässt. Dadurch ist es möglich, ein Element zu refreshen, dass Ergebnis dieser Operation jedoch auf ein anderes Element im Client anzuwenden.

Hier ein kleines Beispiel anhand einer XPage, die vor dem Partial Refresh wie folgt aussieht:

Screenshot: Vor dem Partial Refresh

Der Code der XPage ist ebenfalls simpel, ausser das bei einem Partial Refresh der XPage ein Header an den Request angefügt wird. Dazu wird das Event afterRestoreView genutzt.

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

    <xp:this.afterRestoreView><![CDATA[#{javascript:
        var exCon = facesContext.getExternalContext();
        var writer = facesContext.getResponseWriter();
        var response = exCon.getResponse();
        response.setHeader("X-XspRefreshId",  getClientId('label2') ); }]]>
    </xp:this.afterRestoreView>

    <xp:button value="Label" id="button1">
        <xp:eventHandler event="onclick" submit="true"
            refreshMode="partial" refreshId="label1">
        </xp:eventHandler>
    </xp:button>
    <xp:br></xp:br>
    <xp:br></xp:br>
    <xp:label value="Label1" id="label1"></xp:label>
    <xp:br></xp:br>
    <xp:br></xp:br>
    <xp:label value="Label2" id="label2"></xp:label>
</xp:view>

Der Button löst einen Partial Refresh auf das Label label1 aus, der dazugehörige Request, der an den Server gesendet wird liefert auch den zu erwartenden HTML-Code zurück:

<span id="view:_id1:label1" class="xspTextLabel">Label1</span>

Doch nun kommt der zusätzliche Header ins Spiel. Er bewirkt, dass nicht das label1 ersetzt wird, sondern das Element label2:

Durch den in der HTTP Header in der Antwort des Servers wurde das XSP-Objekt dazu veranlasst, den HTML-Code im DOM-Baum an einer anderen Stelle zu ersetzen.

In diesem kleinen Beispiel tritt ein kleiner Seiteneffekt auf: Das Label mit der id label2 verschwindet komplett aus dem DOM-Baum. Betätigt man den Button ein zweites Mal, funktioniert der Refresh nicht mehr, und folgende Fehlermeldung erscheint im Browser:

XPages: Stolperfalle Recycling

2. Dezember 2011 Posted by airwolf89

Gestern hatte ich mal wieder eine schönes „Feature“ gefunden.

Aufgefallen ist dass eine XPage mit einer Null-Pointer Exception abgestürzt ist. Scheinbar war eine View-Datasource, dessen erstes Dokument ich mir holen wollte, nicht vorhanden.

Einige print-outs ergaben dass der Code mehrmals durchlaufen wird, was bei XPages, welche Editable Areas (Callbacks) benutzen, häufiger zu beobachten ist. Allerdings war die View bei Durchlauf 1 bis 3 noch vorhanden, beim 4. Durchlauf hatte es dann geknallt.

Nach vielen Hin und Her testen stand dann die Ursache fest. Ich hatte in einem Custom Control etwas eingebaut, wo auf eine Funktion in einer SSJS-Scriptlibrary aufgerufen wurde. In dieser Funktion wurde eine View referenziert und später wieder recycled. Normalerweise wäre hier kaum ein Zusammenhang zu erkennen. Aber, die Methode und meine XPage benutzten die gleiche View. Scheinbar ist es so, dass Designelemente nicht mehrfach referenziert werden.

D.h. wenn ich an vollkommen unterschiedlichen Stellen z.b. die gleiche View referenziere und auch nur eine davon recycle, dann werden alle Referenzen auf dieses Designelement gelöscht und es regnet entsprechende Null-Pointer Exception.

Die Lösung dieses Problems war denkbar einfach: Wir nahmen einfach das recycling aus dem Code. Normalerweise muss man auch nicht recyclen, da Domino das im Grunde selbst kann. Lediglich bei großen Schleifen wo viele Dokumente durchgeloopt werden sollte man über recycling nachdenken. Auf jeden Fall muss man aber darauf achten wie ich Designelemente referenziere um mir nicht den Ast abzusägen auf dem ich sitze.


Quick-n-Dirty: Leeres NotesDocumentCollection-Objekt instanzieren

28. November 2011 Posted by Sven Hasselbach

Domino bietet Out-of-the-Box leider keine Möglichkeit, ein leeres NotesDocumentCollection-Objekt zu instanzieren. Um trotzdem in den Genuss zu kommen, mit einer leeren NotesDocumentCollection arbeiten zu können, ist der schnellste Weg, einfach alle Dokumente der Datenbank zu verwenden und von sich selbst “abzuziehen”.

In SSJS sieht das wie folgt aus:

/*****
 *** getEmptyDocumentCollection()
 *** returns an empty NotesDocumentCollection-Object
 *****/

function getEmptyDocumentCollection(){
   var dc:NotesDocumentCollection = null;
   try{
      dc = database.getAllDocuments();
      dc.subtract( database.getAllDocuments() );
   }catch(e){}
   return dc;
}

/*** how to use ***/
var hlpDC:NotesDocumentCollection = getEmptyDocumentCollection();
var hlpDoc:NotesDocument =  database.getAllDocuments().getFirstDocument();

hlpDC.addDocument ( hlpDoc )
hlpDC.getCount();

Die gleiche Funktionalität sieht in LotusScript wie folgt aus:

%REM
    Function getEmptyDocumentCollection
    Description: Returns an empty document collection
    Created Nov 28, 2011 by Sven Hasselbach
%END REM
Function getEmptyDocumentCollection() As NotesDocumentCollection
    
    On Error GoTo errH
    
    Dim session As New NotesSession
    Dim db As NotesDatabase
    Dim dc As NotesDocumentCollection
    
    Set db = session.Currentdatabase
    Set dc = db.Alldocuments
    dc.Subtract db.Alldocuments
    Set getEmptyDocumentCollection = dc
    
the_end:
    Exit Function

errH:
    Print "getEmptyDocumentCollection() - Error #" & Err & _
    ": '" & Error & "' @ Line " & Erl
    Resume the_end

End Function

Und schon hat man eine leere NotesDocumentCollection, der man nach Belieben arbeiten kann!

OpenNTF XSnippets Beta gestartet

22. November 2011 Posted by Sven Hasselbach

XSnippets – The next generation code bin, ist als Beta gestartet.

Das neue OpenNTF Projekt dient als Sammlung für kleine Code-Schnippsel, die von der Community für die Community zur Verfügung gestellt werden. Hier sind die ersten Schnippsel zu finden.

Performance-Tuning (5): Links und xsp.redirect

18. November 2011 Posted by Sven Hasselbach

Ein serverseitiger Redirect wird durch die XPages-Engine standardmäßig so durchgeführt, daß an den Client ein spezieller HTTP-Header gesendet wird, der via Javascript ausgewertet und dann durch CSJS geöffnet wird.

Der Hintergrund hierbei ist, daß sich dadurch die URL in der Browser-Addressleiste ändert, und so dem Nutzer die Seitenänderung aktiv angezeigt wird. Das Problem hierbei ist jedoch, daß dadurch ein zusätzlicher Request vom Server an den Client gesendet wird, der zum Einen natürlich die Last auf dem Server erhöht, zum Anderen den Vorgang unnötig verlangsamt.

Ein Clientseitiger Link…

<xp:link escape="true" text="LinkClient" id="link1"
value="/Page2.xsp" />

… ist daher besser als das gleiche Konstrukt über einen Serverseitigen Event-Handler …

<xp:link escape="true" text="LinkServer" id="link2" >
   <xp:eventHandler event="onclick" submit="true"
      refreshMode="complete">
      <xp:this.action>
         <xp:openPage name="/Page2.xsp"></xp:openPage>
      </xp:this.action>
   </xp:eventHandler>
</xp:link>

… auch wenn das Ergebnis im ersten Moment daraus das gleiche Ergebnis resultiert.

Das erste Beispiel öffnet den Link direkt über den Client:

Screentshot: Firebug- Direktes Öffnen eines Links

[Beispiel 1 Firebugged: Direktes Öffnen von Page1.xsp via HTTP GET]

Das zweite Beispiel sort dafür, daß beim Klicken auf den Link zuerst ein HTTP POST-Request an den Server an die aktuelle Seite geschickt wird; die Antwort (versehen mit dem HTTP-StatusCode 302) löst dann einen zweiten Request mittels HTTP GET auslöst, durch den dann die “Page2.xsp” geöffnet wird.

Screenshot: Firebug - xsp.redirect=true

[Beispiel 2 Firebugged: POST-Request an Page1.xsp, dann GET-Request an Page2.xsp]

Daher sollte prinzipiell darauf geachten werden, daß z.B. Links in der XPage direkt eingebettet werden, und das Serverseitige Verarbeiten mittels OpenPage besser zu unterlassen.

Doch auch dieses Verhalten läßt sich noch durch eine Einstellung im xsp.properties-File modifizieren: Durch die Einstellung xsp.redirect = false wird kein Redirect mehr für das Event-basierte Link-Beispiel ausgeführt, sondern die neue Seite wird direkt an den Client übergeben:

Screenshot: Firebug - xsp.redirect = false

[Firebugged: Ergebnis mit xsp.redirect=false]

Im Browser sieht das ganze dann wie folgt aus (in den Screenshots wird ein Button verwendet), man beachte die URL im Browser:

Screenshot: Page1 - Before

[Page1.xsp vor dem Klick auf den Button]

Screenshot: Page1 - After

[Page1.xsp nach dem Klick, jetzt mit dem Inhalt von Page2.xsp]

Sieht man von dem “unschönen” Effekt ab, daß die URL im Browser sich nicht verändert hat, hat sich die Performance auch für den Client deutlich erhöht. Als Beispiel hier noch die Zeiten, die für den Seitenaufbau benötigt werden; da der DOM-Baum nur einmal im Browser geändert wird, ist auch dies deutlich schneller.

Screenshot: Zeit für Seitenaufbau mit xsp.redirect = true

[Zeit für Seitenaufbau mit xsp.redirect = true]

Screenshot: Zeit für Seitenaufbau mit xsp.redirect=false

[Zeit für Seitenaufbau mit xsp.redirect = false]

Wie sich unschwer erkennen läßt, ist mit xsp.redirect=false der Seitenaufbau in etwa der Hälfte der Zeit erledigt wie im anderen Fall. Das hierbei die ULR im Browser nicht aktualisiert wird, kann im Einzelfall natürlich zu den hier geschilderten Problemen führen, aber hier muß klar der Performance-Vorteil in den Vordergrund gestellt werden.

Weiterführende allgemeine Informationen finden sich hier: Google.com: Minimize round-trip times.

Art des Refreshs programmatisch ermitteln

13. November 2011 Posted by Sven Hasselbach

Um festzustellen, ob das Berechnen eines Elementes von einem Full Refresh oder einem Partial Refresh ausgelöst wird, kann die Klasse com.ibm.xsp.ajax.AjaxUtil verwendet werden. Die Klasse stellt die Methode isAjaxPartialRefresh() bereit, die das nötige Ergebnis zurückliefert.

Hier eine Beispiel-XPage, die die Verwendung demonstriert:

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

   <xp:label id="lblRefreshMe">
      <xp:this.value><![CDATA[#{javascript:
         var ajax = new com.ibm.xsp.ajax.AjaxUtil();
          if( ajax.isAjaxPartialRefresh(facesContext) == true)
             return "AJAX" ;

          return "NOT AJAX!"}]]>
      </xp:this.value>
   </xp:label>
   <xp:br></xp:br>
   <xp:br></xp:br>
   <xp:button value="Do Full Refresh" id="buttonFullRefresh">
      <xp:eventHandler event="onclick" submit="true"
         refreshMode="complete">
      </xp:eventHandler>
   </xp:button>
   <xp:br></xp:br>
   <xp:button value="Do Partial Refresh" id="buttonPartialRefresh">
      <xp:eventHandler event="onclick" submit="true"
         refreshMode="partial" refreshId="lblRefreshMe">
      </xp:eventHandler>
   </xp:button>
</xp:view>

Hier ein Screenshot der XPage beim Aufruf der XPage.

Durch Klick auf die Buttons läßt sich die Art des Refreshs bestimmen. Wird ein Partial Refresh durchgeführt, ändert sich das Label wie folgt:

Application-Properties mittels SSJS auslesen

13. November 2011 Posted by Sven Hasselbach

Um Serverseitig zu ermitteln, welche Dojo-Version verwendet wird, kann folgender Code verwendet werden:

<xp:label id="lblJSVersion">
   <xp:this.value><![CDATA[#{javascript:var reqParam =
      new com.ibm.xsp.context.RequestParameters ( facesContext );
      reqParam.getLibraryVersion()}]]>
   </xp:this.value>
</xp:label>

[Code liefert unter 8.5.3 in der Standard-Einstellung "1.6.1" zurück]

Um zu ermitteln, ob die Clientseitige Validierung aktiviert bzw. deaktiviert ist, liefert die Methode isClientSideValidation() das gewünschte Ergebnis:

<xp:label id="lblIsCSValidation">
   <xp:this.value><![CDATA[#{javascript: var reqParam =
      new com.ibm.xsp.context.RequestParameters ( facesContext );
      reqParam.isClientSideValidation()}]]>
   </xp:this.value>
</xp:label>

[Liefer true bzw. false zurück, je nach Einstellung der Datenbank]

Welche Komprimierungseinstellung verwendet wird, kann so ermittelt werden:

<xp:label id="lblCompressMode">
   <xp:this.value><![CDATA[#{javascript:var reqParam =
      new com.ibm.xsp.context.RequestParameters ( facesContext );
      reqParam.getCompressMode()}]]>
   </xp:this.value>
</xp:label>

[Liefert z.B. "gzip-nolength" zurück, je nach Einstellung der Datenbank]

Ob überhaupt Dojo Verwendung findet, bzw. die XSPDojoLite.js-Version, liefert folgender Code:

<xp:label id="lblJsLibrary">
   <xp:this.value><![CDATA[#{javascript:var reqParam =
      new com.ibm.xsp.context.RequestParameters ( facesContext );
      var jsLib = reqParam.getJsLibrary();

      switch(jsLib){
      case 1:
         return "dojo";
      break;
      case 2:
         return "lite";
      break;
      default:
         return "none";
      break;
      }}]]>
   </xp:this.value>
</xp:label>

Quick-n-Dirty: Manipulation von UI Komponenten via SSJS (2)

3. November 2011 Posted by Sven Hasselbach

Ist einer der Items durch einen Mehrfachwert definiert worden,  muss das entsprechende Item anders behandelt werden. Eine Definition wie folgt…

<xp:comboBox id="comboBox1">
   <xp:selectItems>
      <xp:this.value><![CDATA[#{javascript:
         var vItem = new java.util.Vector();
         vItem.add("A|1");
         vItem.add("B|2");
         vItem.add("C|3");
         vItem
      }]]></xp:this.value>
   </xp:selectItems>
</xp:comboBox>

…ist auch intern als Array zu behandeln. Eine Funktion, die mit beiden Item-Typen umgehen kann (auch im Mix), kann dann wie folgt aufgebaut sein:

function getSelectableValues( id ) {
   var ComboBox = getComponent( id );
   var ChildrenList:java.util.ListIterator;
   ChildrenList = ComboBox.getChildren().listIterator()
   while (ChildrenList.hasNext()) {
      var Child = ChildrenList.next();     
      if( typeof( Child ) == 'com.ibm.xsp.component.UISelectItemsEx' ){
         var hlp = Child.getValue();
         for( var i=0; i< hlp.length; i++ ){
            print( hlp[i].getLabel() + "|" + hlp[i].getValue() );
            hlp[i].setLabel("ABC" + i );
            hlp[i].setValue("123" + i );
            hlp[i].setDisabled(true);
         }
         Child.setValue(hlp);
      }
      if( typeof( Child ) == 'com.ibm.xsp.component.UISelectItemEx' ){
         print( Child.getItemLabel() + "|" + Child.getItemValue() );
      }
   }
}

getSelectableValues( 'comboBox1' );

[Fett: Wenn Änderungen am Mehrfachwert-Item vorgenommen werden, muss das Item nach der Bearbeitung mit "setValue()" erneuert werden]

Die Namen der Methoden sind ohne “Item” zu verwenden, z.B. setItem() anstelle von setItemValue().

Quick-n-Dirty: Manipulation von UI Komponenten via SSJS

3. November 2011 Posted by Sven Hasselbach

Serverseitig lassen sich die die Items einer Auswahlbox (z.B. eine Combobox, Listboxen, usw.) auslesen und ggf. manipulieren. Hier eine Combobox mit drei Items:

<xp:comboBox id="comboBox1">
   <xp:selectItem itemLabel="A" itemValue="1"></xp:selectItem>
   <xp:selectItem itemLabel="B" itemValue="2"></xp:selectItem>
   <xp:selectItem itemLabel="C" itemValue="3"></xp:selectItem>
</xp:comboBox>

Um via SSJS die Items der UI Komponente und deren Eigenschaften zu erhalten, kann man wie folgt darauf zu greifen:

function listSelectableValues( id ) {
   var cBox = getComponent( id );
   var cList:java.util.ListIterator;
   cList = ComboBox.getChildren().listIterator();
   while (ChildrenList.hasNext()) {
      var c = ChildrenList.next()
      print ("Label: " + c.getItemLabel() );
      print ("Value: " + c.getItemValue() );
      print ("IsDisabled: " + c.isDisabled() );
   }
}

listSelectableValues( 'comboBox1' );

Auf der Serverkonsole werden nun die Eigenschaften der drei Items ausgegeben.

Natürlich lassen sich die Items auch manipulieren:

<xp:button value="Label" id="button1">
   <xp:eventHandler event="onclick" submit="true"
      refreshMode="partial" refreshId="comboBox1">
      <xp:this.action><![CDATA[#{javascript:
         var cBox = getComponent( 'comboBox1' );
         var cBoxChildren = cBox.getChildren();
         var cBoxChild = cBoxChildren.get(0);

         // --- disablen
         cBoxChild.setItemDisabled(true);

         // --- das Label ändern
         cBoxChild.setItemLabel("DISABLED");

         // --- den Value ändern
         cBoxChild.setItemValue("disabled");
      }]]></xp:this.action>
      </xp:eventHandler>
</xp:button>

Der Button führt einen PartialRefresh auf die ComboBox aus, deaktiviert das erste Item (es ist nicht mehr selektierbar) und ändert sowohl das Label als auch den Wert des ersten Items.

Der Fluch des Partial Refreshs

30. Oktober 2011 Posted by Sven Hasselbach

Bei der Architektur von Web 2.0-Applikationen gibt es ein paar Besonderheiten zu beachten, die es im “alten” Web nicht gegeben hat, denn der konzeptionelle Ansatz, durch die AJAX-gestützten Abfragen nur einzelne Segmente einer Webseite zu laden (und diese Abfragen im Hintergrund durchzuführen), kann sich zu einem grundlegenden Problem entwickeln: Zum Einen leidet die Benutzbarkeit einer Applikation, denn das Verlinken der Inhalte ist nicht möglich, zum Anderen können Suchmaschinen die Seiten nicht oder nur noch teilweise indizieren.

Zum Erläuterung des Problems hier eine kleine Denksportaufgabe: Wie verlinke ich eine bestimmte Seite, z.B. die zweite Seite des XPages-Developer-Forums? Das Verlinken eines Beitrages stellt kein Problem dar, aber die zweite Seite zu verlinken ist nicht möglich.

Im “guten alten Web”, bei dem die Webseiten immer komplett geladen und die Optionen zum Großteil über URL-Parameter gesteuert werden, existiert als Nebeneffekt automatisch eine Möglichkeit, ein Bookmark zu setzen, wie z.B. hier: Domino 8.5 Forum, Seite 2, Kategorisierung eingeklappt.

Auch ist es für die Bots der Suchmaschinen viel einfacher, allen Verlinkungen innerhalb einer Webseite zu folgen, denn hinter dem Link verbirgt sich eine (neue) Seite, die es ebenfalls zu indizieren gilt.

Im Falle von XPages-Applikationen gibt es diese Möglichkeiten nicht Out-Of-The-Box. Man kann hier getrost vom “Fluch des Partial Refreshes” sprechen kann, denn so muß die Google-Spezifikation für durchsuchbare AJAX-Applikationen in die XPages händisch eingebaut werden. Und das für jeden Pager, jede Aktion, jeden Serverseitigen Link…

Um die Funktionalität der Bookmarks wieder herzustellen, kann der URL Hash “angezapft” werden; dieser muß jedoch via Javascript gesetzt bzw. ausgewertet werden. Eine Hilfe hierfür bietet der Dojo Toolkit mittels dojo.hash. Die Variante der URL Manipulation OHNE ein Neuladen der Webseite ist auch mit älteren Browsern möglich; mit HTML 5 ist die Möglichkeit geschaffen worden, die URL wirklich manipulieren zu können. Eine nette Implementierung findet sich auch unter https://github.com/balupton/history.js. Die HTML 5 – Variant e ist Serverseitig auswertbar, da sich die URL-Parameter ohne Reload der Seite setzen lassen (und im HTTP Request übertragen werden). Aber leider ist diese Funktionalität nicht in älteren Browser verfügbar.

Will man kompatibel bleiben, bleibt also nur der Weg über den URL-Hash. Im Falle eines Seitenaufrufs über ein Bookmark muß der Hash-Part der URL im Client ausgewertet werden, denn der Hash wird NICHT via HTTP Request übertragen (und damit auch nicht Serverseitig auswertbar). Erst nach dieser Auswertung können diese Informationen z.B. mit einen Partial Refresh übertragen werden.

Eine Beispiel-Implementation ist in Arbeit und wird bei Gelegenheit veröffentlicht.

disableXspCache: Programmatisch GZip-Komprimierung abschalten

20. Oktober 2011 Posted by Sven Hasselbach

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.

Java not found

18. Oktober 2011 Posted by Sven Hasselbach

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

Screenshot: Java Not Found

 

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>

 

Casten von Objekten in SSJS

4. Oktober 2011 Posted by Sven Hasselbach

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")

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

29. September 2011 Posted by Sven Hasselbach

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).

Screenshot: java.io.File Bug

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>