Posts Tagged: ‘Server’

Security: Domino Server Backdoor

7. Januar 2012 Posted by Sven Hasselbach

Mit XPages lässt sich ein Domino Server auf einfachste Weise lahm legen, da man über die Java Runtime beliebige Threads starten kann.

Ein kleiner Button startet z.B. Notepad auf einem Windows Domino Server:

<xp:button value="Start NotePad!" id="buttonStartNotePad">
   <xp:eventHandler event="onclick" submit="true"
      refreshMode="norefresh">
      <xp:this.action>
         <![CDATA[#{javascript:
            java.lang.Runtime.getRuntime().exec("notepad");}]]>
      </xp:this.action>
   </xp:eventHandler>
</xp:button>

 

Bei jedem Klick wird auf dem Domino Server einmal Notepad gestartet. Eine kleine Schleife, und auch ein großzügig dimensionierter Server geht in die Knie.

Richtig übel wird es allerdings, wenn dieser Button geklickt wird:

ACHTUNG! NICHT AUF PRODUKTIVEN SYSTEMEN AUSFÜHREN!

<xp:button value="KILL NOTES!" id="buttonKillNotes">
   <xp:eventHandler event="onclick" submit="true"
      refreshMode="norefresh">
      <xp:this.action>
         <![CDATA[#{javascript:
            java.lang.Runtime.getRuntime().exec("nsd -kill");}]]>
         </xp:this.action>
      </xp:eventHandler>
</xp:button>

Dann ist der Domino Server weg!

Bei dem “zerlegten” Server handelt es sich um eine Standard-Installation. Die java.policy wurde nicht geändert.

Quick-n-Dirty: Locale setzen

5. Januar 2012 Posted by Sven Hasselbach

Um die Locale-Einstellung einer XPage programmatisch zu beeinflussen, kann die Methode setLocaleString bzw. setLocale des context-Objektes verwendet werden.  Damit die Änderungen übernommen wird, muss die Einstellung im BeforePageLoad gesetzt werden.

So ändert ein…

context.setLocaleString("zh-tw")

… bzw. ein …

context.setLocale(java.util.Locale.TAIWAN)

…die Spracheinstellungen der generierten XPage. Sowohl das lang-Attribute der HTML-Seite als die Dojo-Konfiguration wird dabei gesetzt:

<!DOCTYPE html>
<html lang="zh-tw">
<script type="text/javascript"
src="/xsp/.ibmxspres/dojoroot-1.6.1/dojo/dojo.js"
djConfig="locale: 'zh-tw', parseOnLoad: true"></script>

Durch diese Änderung wird z.B. der Datepicker-Dialog des DojoToolkit auf Taiwanisch gerendert.

Eine Liste der möglichen Einstellungen findet sich in der Beschreibung des java.util.Locale-Objektes.

Security: Fernsteuerbare ViewDataSources

30. Dezember 2011 Posted by Sven Hasselbach

Ist bei einer Datenbank die Option “Don’t allow URL open” gesetzt, ist sie nicht mehr im Web erreichbar. Mit den URL-Parametern databaseName und viewName lässt sich in Verbindung mit einer ViewDatasource dieser Schutzmechanismus jedoch aushebeln, und könnte ein Problem darstellen, wenn sich nur auf diese Option verlassen wurde.

Als Beispiel dient hier eine lokales NAB, dass zu Demonstrationszwecken eine offene ACL hat (Default = Manager), bei dem die genannte Option jedoch aktiviert ist:

Öffnet man diese Datenbank im Browser, so erscheint eine Fehlermeldung:

Legt man jedoch eine XPages mit einer ViewDatasource in einer anderen Datenbank an, kann dieser einfache Schutzmechanismus umgangen werden, da die beiden Paramter die in der XPage definierte Quelle überschreiben; dadurch wird eine “Fernsteuerung” der ViewDataSource ermöglicht.

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

   <xp:viewPanel rows="30" var="viewCol">
      <xp:this.data>
         <xp:dominoView var="view1" viewName="" />
      </xp:this.data>
      <xp:viewColumn
         value="#{javascript:viewCol.getUniversalID()}">
     </xp:viewColumn>
   </xp:viewPanel>
   
</xp:view>

Öffnet man folgende XPage, ist die darzustellende Ansicht natürlich leer…

… hängt man allerdings die passenden URL-Parameter an, sieht die gleiche XPage entsprechend anders aus:

Es handelt sich dabei um die beiden Dokumente aus dem persönlichen Addressbuch.

Zwar müssen immer noch Berechtigungen auf die jeweilige Datenbank gegeben sein, damit Daten ausgelesen werden können, dennoch sollte prinzipiell immer ignoreRequestParams=”true” gesetzt sein.

Quick-n-Dirty: Die HTTP-Session des Domino-Servers

14. Dezember 2011 Posted by Sven Hasselbach

Um mit SSJS auf die HTTP-Session eines Domino-Servers zuzugreifen, ist nicht viel Code nötig:

var exCon = facesContext.getExternalContext();
var sess = exCon.getRequest().getSession();

Dadurch lassen sich folgende Informationen ermitteln:

  • getAttribute(Name:String)

Liefert gebundenes Objekt des Attributes “Name” zurück

  • getAttributeNames()

Liefert die Namen aller Attribute als java.util.Enumeration zurück.

  • getCreationTime()

Zeit der Session-Erstellung, Millisekunden seit 1.1.1970 GMT, z.B. “1.323785660873E12″

  • getId()

Liefert die aktuelle SessionID zurück, z.B. “D18P2LFFB5″

  • getLastAccessedTime()

Zeit, an der die Session zuletzt aufgerufen wurde. In Millisekunden seit 1.1.1970 GMT, z.B. “1.323785660873E12″

  • getMaxInactiveInterval()

Länge der maximalen Gültigkeit einer Session (in Sekunden) , die vom Servlet ohne Clientaktivität abgewartet wird.

  • isNew()

True, wenn der Client die Sessio noch nicht kennt, false wenn der Client einer bestehende Session beitritt.

  • invalidate()

Setzt eine Session zurück und löscht alle Daten der Session

  • removeAttribute(Name:String)

Löscht das Attribut “Name” und entfernt das gebundene Objekt

  • setAttribute(Name:String, obj:Object)

Setzt das Attribut “Name” mit dem Objekt “obj“.

  • setMaxInactiveInterval(int interval)

Setzt maximale Länge der Session in Sekunden, bis das Servlet die Session ablaufen lässt.

 

Um die Attribute einer Session auszugeben, kann z.B. folgender Code verwendet werden:

var attr = sess.getAttributeNames();
while( attr.hasMoreElements() ){
   var elem = attr.nextElement();
   result += elem + " -> ";
   result += sess.getAttribute( elem );
   result += " [";
   result += typeof(sess.getAttribute( elem ));
   result += "]";
 }

result

Quick-n-Dirty: Hijacking TypeAhead in CSJS

9. Dezember 2011 Posted by Sven Hasselbach

Matthias Nicklisch hat eine interessante Frage im XPages Forum gestellt, nachdem er festgestellt hat, dass im Designer zwar ein OnStart- / OnComplete-Event für die TypeAhead-Funktion angeboten wird, der Code aber als Deprecated angezeigt wird – und auf der XPage auch nicht funktioniert: Wie kann ein OnStart- / OnComplete-Event trotzdem verwendet werden?

Meine Idee dazu ist, den darunter liegenden dojo.xhr-Request zu hijacken, und auf diese Weise die Events zu erhalten. Dadurch lässt sich der Code bequem auf die jeweilige XPage einbetten, ohne das eine Manipulation der original Javascript-Dateien erfolgen muss.

Der folgender Code muß in einem CSJS-Scriptblock eingebettet werden. Dann erhält man für die TypeAhead-Funktion die Events, um zum Beispiel ein kleines “Loading”-Icon einzublenden, wenn die Daten vom Domino Server geladen werden.

var typeAheadLoad;

dojo.addOnLoad( function(){
   /*** hijacking xhr request ***/
   if( !dojo._xhr )
      dojo._xhr = dojo.xhr;

   dojo.xhr = function(){
      try{
         var args = arguments[1];
         if( args['content'] ){
            var content = args['content'];
               if( content['$$ajaxmode'] ){
                  if( content['$$ajaxmode'] == "typeahead" ){
                
                     /*** hook in load function ***/
                     typeAheadLoad = args["load"];

                     /*** overwrite error function ***/
                     args["error"] = function(){
                        alert('Error raised!')
                     };
                    
                     /*** hijack load function ***/
                     args["load"] = function(arguments){
                 
                        /*** On Start ***/
                        alert("On Start!");
                    
                        /*** call original function ***/
                        typeAheadLoad(arguments);
                    
                        /*** On Complete ***/
                        alert("On Complete!")
                     };
                 }
             }
         }
      }catch(e){}
      dojo._xhr( arguments[0], arguments[1], arguments[2] );
   }
});

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:

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>

Performance-Tuning (4): Fein-Tuning von xsp.resources.aggregate

11. November 2011 Posted by Sven Hasselbach

Mit Domino 8.5.3 wurde eine neue Option eingeführt, mit der automatisch verschiedene Ressourcen-Dateien vom Server vor der Auslieferung an den Browser zusammengefasst werden. Dadurch läßt sich die Performance einer Web-Applikation deutlich erhöhen, denn zum Einen werden dadurch weniger Anfragen vom Browser an den Server gesendet,  zum Anderen wird der Browser nicht unnötig “blockiert”, da sich die Anzahl der zu ladenden Ressourcen deutlich reduziert (siehe dazu RFC 2616)

In folgendem Artikel ist die neue Option xsp.resources.aggregate detailliert beschrieben, doch es gibt noch ein paar undokumentierte Optionen, mit denen sich das Verhalten der XPages-Engine genauer steuern läßt.

Dafür muß zu aller erst die Funktion aktiviert sein, das xsp.properties-File also folgende Zeile beinhalten:

xsp.resources.aggregate=true

Dann kann mit den folgenden Optionen das Verhalten für die einzelnen zu aggregierenden Ressourcen individuell festgelegt werden (Standardmäßig werden alle Ressourcen zusammen gefasst).

  • xsp.resources.aggregate.dojo

Wenn false, werden die Javascript-Libraries des Dojo Toolkits ausgeschlossen.

  • xsp.resources.aggregate.css

Schließt die Standard-CSS-Dateien aus, wenn false.

  • xsp.resources.aggregate.appcss

Schließt die CSS-Dateien der Applikation aus, wenn false.

  • xsp.resources.aggregate.appjs

Wenn false, werden die JavaScript-Libraries der Applikation ausgeschlossen.

Performance-Tuning (3): XSPClientLite.js

10. November 2011 Posted by Sven Hasselbach

Im xsp.properties-File gibt es einen undokumentierten Parameter, mit der sich eine abgespeckte Version der JavaScript-Routinen im Client einbinden läßt: die XSPClientLite.js. Die Library wird bei einer Standard-Installation von der IBM mitgeliefert.

Hierbei handelt es sich um eine deutlich kleinere Version der XSP Routinen, allerdings auch mit einem kleineren Funktionsumfang: Es fehlen z.B. die Routinen für Partial Refreshs, auf die aber je nach Anwendungsfall auch verzichtet werden kann. Hingegen sind z.B. die Clientseitige Validierung enthalten, oder aber die Methoden für das Auf-/Zuklappen von Sections, uvm.

Durch die kompakte Größe von nur 11 KB (rund 2/3 kleiner als die “normale” XSPClient-Library) läßt sich aber die Ladezeit verringern bzw. der Seitenaufbau der XPage beschleunigen; ob die Library die nötigen Funktionen bietet, die man auf der XPage verwenden möchte, muß aber im Einzelfall getestet werden.

Um die Library zu verwenden, muß im xsp.properties-File folgender Eintrag hinzugefügt werden:

xsp.client.script.libraries=lite

Dadurch wird die XSPClientLite.js anstelle der XSPClientDojo.js in der XPage eingebunden und vom Client verwendet.

Quick-n-Dirty: Kontrolle über $$OpenDominoDocument

9. November 2011 Posted by Sven Hasselbach

Wird ein Dokument via $$OpenDominoDocument.xsp geöffnet, muß nicht zwangsläufig eine passende XPage mit gleichem Namen der gespeicherten Form vorhanden sein, um das Dokument anzuzeigen.

Auch über das xsp.properties-File läßt sich das Verhalten steuern. Durch folgende Eintrag kann einer Form eine bestimmten XPage zugeordnet werden:

xsp.domino.form.xpage.formname=xpage

Wichtig ist, daß der Name der Form klein geschrieben sein muß. Um der Form TestForm (bzw. dem Wert des Form-Feldes) die XPage xptest.xsp zuzuordnen, muß der Eintrag so aussehen:

xsp.domino.form.xpage.testform=xptest

Quick-n-Dirty: Dojo-Version auf Datenbankebene setzen

9. November 2011 Posted by Sven Hasselbach

Will man unterschiedliche Dojo-Versionen einsetzen, ist dies nicht nur auf Serverebene möglich. Auch für jede einzelne Datenbank läßt sich die gewünschte Dojo-Version über das xsp.properties-File vorgeben.

Zwar greift die Manipulation der Dojo-Version im xsp.properties-File nur auf dem Domino-Server (die installierte Version vorausgesetzt)…

xsp.client.script.dojo.version=1.5.0

…fügt man allerdings folgende Zeile in das xsp.properties-File in der Datenbank hinzu, wird die entsprechende Dojo-Version geladen:

xsp.client.script.dojo.path=/domjs/dojo-1.5.0

[Der Pfad /domjs entspricht dem Verzeichnis \domino\js im Notes Data-Verzeichnis]

Um die korrekte Einbindung zu überrpüfen, kann die aktuelle Dojo-Version im Client mit der Funktion dojo.version ausgegeben werden.

<xp:scriptBlock id="scriptBlockDJVersion"
    value="XSP.addOnLoad( function(){ alert( dojo.version ); } );">
</xp:scriptBlock>

P.S. Leider setzt die XPages-Engine immer einen Slash vor den Pfad der eingebundenen Library, so dass die Angabe einer URL leider nicht funktioniert.

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.