Archive

Archive for the ‘Stumbling Stones’ Category

Stumbling Stone: sessionScope is for everyone…

19/07/2012 2 comments

Today, I saw something surprising that I want to share with you.

sessionScope is for everyone… Many of us know that one should be careful with the sessionScope because the handling can be quite difficult if you don’t take care whether the sessionScope is deleted or renewd if you don’t need the value anymore. Maybe I will write another article about my favorite topic, because I made a lot of mistakes in my first XPages applications.

So, what do I mean with the heading? Imagine the following example:

User1 writes a value “test 1” in the sessionScope variable “test container”. We know that means that, as long as the user is logged in, he can access this value and no other user can access this variable with this value.

That’s not correct!

User2 can also access this value, under certain circumstances. It is not very likely to happen, but if User 1 and User2 use the same computer, they share their sessionScope.

The sessionScope is saved in a cookie. And as long as this cookie isn’t deleted, all users who use the computer will have the value of User1 in their sessionScope. Even if you logout, close the browser and reopen the browser. The cookie is still there, and so is the sessionScope value.

You can try it very easily:

<?xml version="1.0" encoding="UTF-8"?>
  <xp:view xmlns:xp="http://www.ibm.com/xsp/core">
    <xp:inputText id="inputText1"></xp:inputText>
    <xp:br/>
    <xp:button value="Label" id="button1">
      <xp:eventHandler event="onclick" submit="true"
        refreshMode="complete">
        <xp:this.action><![CDATA[#{javascript:
          synchronized(sessionScope) {
            sessionScope.put("test", getComponent("inputText1").value);
          }}]]>
      </xp:this.action>
    </xp:eventHandler>
  </xp:button>
  <xp:br/>
  <xp:text escape="true" id="computedField1">
    <xp:this.value><![CDATA[#{javascript:sessionScope.get("test")}]]></xp:this.value>
  </xp:text>
</xp:view>

Open this page as User1, set any value, close the browser and reopen it, login with User2 and open this page. You will see the old value from User1.
So, if anyone has an application which is used in public, or the users of the application could switch their computer, you should be very careful. It could lead to the strangest errors in your application, or cause some trouble because of data security/ data privacy. If you even think of the idea to control some access rights via sessionScope, or store a user related object in the sessionScope, you maybe should think of another solution.

Advertisements

Stumbling Stones: Difference between xp:panel and xp:div

02/04/2012 1 comment

Today another stumbling stone.

With this post I want to announce that I will write this Blog in english from now on to reach more readers throughout the world. My old posts will be translated step by step. I hope you understand this step and continue reading my Blog.

But back to topic. Today I was customizing a module in one of my applications. The structure was implemented via xp:panel elements. I wanted to save some performance and wanted to change it to xp:div.

By the way, what is the difference between xp:panel and xp:div, you might ask. Well, it is quite easy. Both controls are container controls which are rendered as a <div> element in HTML. The difference is that you can define a datasource in xp:panel elements. Therefore, xp:panel and xp:div references different Java-classes in the backend. The class for xp:panel is more complex, that means you a bit more serverload. Here is the Java code generated:

 

xp:panel:
private UIComponent createPanel2(FacesContext context,
      UIComponent parent, PageExpressionEvaluator evaluator) {
   UIPanelEx result = new UIPanelEx();
   return result;
}

xp:div
private UIComponent createDiv(FacesContext context,
      UIComponent parent, PageExpressionEvaluator evaluator) {
   XspDiv result = new XspDiv();
   return result;
}

 

It seems not worth to mention, but imagine you have an application with, let’s say 200 div containers throughout the application. With each the server has to load the more complex class and prepare the functionality to create a datasource. If you use xp:div instead, the serverload may decrease a bit. I do not have some statistics to prove how it affects the applications performance in detail, but it is alsways a good idea to reach for maximum performance of an application.

So, what was the problem? I changed the tags to xp:div, and the design of my module was affected. I wondered, because I was thinking both elements are rendered as a <div> element in HTML. But a short glance into the Firebug told me something. For two panels, I didn’t define an ID attribute. So, the second difference between xp:div and xp:panel is that xp:panels without an ID attribute are NOT rendered in an XPage. This could affect either some CSS hierarchies and also, if you need every pixel in a container, affects the way it is displayed. In my case it had the result that an image, which I used as a button was not displayed next to an inputBox, it was displayed below that.

Here an example with the output:

 

Without IDs:

XSP:
<xp:panel>
   <xp:panel>
      test 1
   </xp:panel>
</xp:panel>

<xp:br/>

<xp:div>
   <xp:div>
      test 2
   </xp:div>
</xp:div>

HTML:
test 1
<br>
<div>
   <div>
      test 2
   </div>
</div>

With IDs:

XSP:
<xp:panel id="panel1">
   <xp:panel id="panel2">
      test 1
   </xp:panel>
</xp:panel>

<xp:br/>

<xp:div id="div1">
   <xp:div id="div2">
      test 2
   </xp:div>
</xp:div>

HTML:
<div id="view:_id1:panel1">
   <div id="view:_id1:panel2">
      test 1
   </div>
</div>
<br>
<div id="view:_id1:div1">
   <div id="view:_id1:div2">
      test 2
   </div>
</div>

 

This is not a big deal, if you know that and always set an ID attribut, as it should be, you won’t encounter that problem. But like it is always, you have to know it or you get confused by its consequences.

Stolperfalle: “Cycle reference” in Serverside Javascript

24/03/2012 1 comment

Mal wieder eine Stolperfalle.

Wochenenden sind doch etwas wunderbares um seine Zeit mit Xpages zu verschwenden =)

Ich war dabei ein bisschen Code zu testen und zum laufen zu bringen. Konkret ging es um ein paar Java Klassen mit ein paar netten Funktionen, auf welche ich von Java und Serverside Javascript aus zugreifen wollte. Daher habe ich dann noch 2 Scriptlibraries geschrieben welche diese Funktionen nutzen können.

Code lief so gesehen eigentlich wunderbar, wenn da nicht diese nervigen OutOfMemoryExceptions gewesen wären…

Nach einigem testen (8 wertvolle Stunden meines Lebens mittlerweile), bin ich dann auf die Lösung bzw. die Ursache des Problem gekommen.

Gegenseitige Referenzierung (Cycle references klingt irgendwie viel cooler =) ) von Scriptlibraries mag Notes scheinbar gar nicht.

Die eine Scriptlibrary war ein Logging Tool, das andere ein Tool um auf meine Konfigurationsdokumente zugreifen zu können. Leider kam ich auf die Idee in der Konfigurationslibrary mein Logging Tool zu verwenden und im Logging Tool die Log Datenbank aus Konfigurationsdokumenten zu laden. Diese Konstruktion war scheinbar schon vorher zum Scheitern verurteilt, denn selbst printouts im Einstiegspunkt der Libraries wurden nicht ausgegeben. Dann bin ich auf die Idee gekommen zu testen ob vielleicht die gegnseitige Refrenzierung der Grund war.

Ich schrieb mir 2 Libraries, jeweils nur mit einer Funktion welche ein Printout enthielten. Beide haben sich gegenseitig referenziert. In einer Test-Xpage habe ich dann nur eine der Libraries geladen. Sonst nichts. Kein weiterer Code, keine Funktionsaufrufe, kein gar nichts.  Auch hier erhielt ich schon die OutOfMemoryExceptions. Scheinbar verträgt Notes das gar nicht. Ob das nun ein Bug (oder normales Verhalten) in XPages oder im Javaumfeld ist weiß ich nicht. Auf jeden Fall war mir dies noch nicht bekannt, im Netz habe ich dazu auch noch nichts gefunden, und hoffe dem einen oder anderen damit vielleicht ein paar Stunden Debugging erspart zu haben.

Als Lösung versuche ich nun eine Wrapperklasse zu schreiben, welche die Libraries verwendet und somit das Problem behebt. Mal schauen obs funktioniert.

Übrigens, im XPages Forum habe ich auch noch ein anderes Phänomen gepostet, auf welches ich während meiner Debugging Orgie gestoßen bin. Hat hiermit zwar nichts zu tun, aber es geht um eine der hier verwendeten Scriptlibraries.

XPages Forum – Disappearing notesDatabase reference in Java under 8.5.3

Kurze Zusammenfassung: Im verwendeten Javacode verschwand nach dem ersten (fehlerfreien) Aufruf der Funktion die Referenz auf die aktuelle Datenbank. Keine Ahnung warum. Sobald dort etwas gepostet wurde werde ich das auch hier rein stellen.

Stolperfalle: Ids bei clientseitigen Events

Heute bin ich mal wieder über einen Fehler gestolpert, welchen ich schonmal begangen habe, und dadurch mal wieder viel Zeit verloren habe. Deshalb landets jetzt hier, in der Hoffnung dass ichs mir auch endlich mal merke =)

Ich hatte ein xp:div Element, welches eingebettet einen Text und ein Bild hatte. Mit einem onMouseover Event wollte ich die URL des zu verwendeten Bildes ändern. Leider reagierte das Element auf keinen MouseOver.

Dies kann man übrigens auf 2 Arten erreichen:

document.getElementById("#{id:zielElement}").src = "url_zum_bild.gif";

oder wenn man sich auf das aktuelle Element beziehen möchte, auf welchem das Event liegt:

try{
	if (thisEvent.originalTarget) {
		thisEvent.originalTarget.src = "btn_go_Hover.gif";
	} else {
		thisEvent.srcElement.src = "btn_go_Hover.gif";
	}
}catch(e){}

Die If-Abfrage hat den Hintergrund dass der Internet Explorer “srcElement” braucht und nicht auf originalTarget zugreifen kann.

Dass mein xp:div auf kein Event gehört hat lag einfach daran dass mein xp:div Element keine ID hatte.

MERKEN: Elemente mit einem clientseitgen Event brauchen IMMER eine ID!!

Btw: Wo wir gerade bei xp:div sind:

Mann sollte immer, wenn man nur ein einfaches div in der Seite braucht, xp:div verwenden. xp:panel hat zwar das gleiche Ergebnis, allerdings werden bei xp:panel noch ein paar Sachen im Hintergrund geladen die es ermöglichen eine Datasource anzubinden. Wenn man dies beachtet kann man noch ein paar Quäntchen Performance aus der Applikation herausholen. Besonders wenn man diese Elemente in einem xp:repeat loopt.

Stolperfalle: view.getEntryCount()

16/12/2011 1 comment

Mal wieder eine kleine Stolperfalle.

Situation war folgende: In einer Anwendung gibt es so etwas wie eine Community, jeder kann Fragen einstellen, diese können kommentiert werden usw. Das ganze soll in verschiedenen Gruppen ablaufen. Nun kann man sich entscheiden ob man die Frage öffentlich (für alle Gruppen sichtbar) oder privat (nur für meine Gruppe sichtbar) einstellen will.

Dazu musste es eine Ansicht geben, wo ich hin und her schalten kann, welche Kategorie ich sehen will.

Dazu habe ich den Viewnamen meiner Datasource berechnen lassen, je nach URL-Parameter um entsprechend die View mit den öffentlichen Dokumenten oder die mit den privaten Dokumenten abzufragen.

Auch musste innerhalb meines Codes abgefragt werden ob sich ein Dokument in der View befindet was angezeigt werden kann, um hässliche Null-Pointer Exceptions zu vermeiden.
Die Lösung dafür war denkbar einfach: myView.getEntryCount()

Damit habe ich abgefragt ob die Anzahl der Einträge 0 ist oder nicht und habe entsprechend die jeweiligen Blöcke angezeigt.

Nun habe ich mir noch jemanden zu testen  , der leider eine Null-Pointer Exception an dieser Stelle bekommen hat. Mit ein paar Printouts fiel uns auf, dass getEntryCount() bei ihm nicht 0 zurückgibt, obwohl es das hätte tun müssen.

Lange Rede kurzer Sinn: getEntryCount() ignoriert sämtliche Lese- und Autorenfelder. Bzw. wird der Befehl wahrscheinlich mit den Rechten des Servers ausgeführt, welcher die Dokumente scheinbar sehen darf.

Die bessere Lösung ist es myView.getFirstDocument() == null abzufragen. Dort bekommt man nur die Dokumente auf die man zugreifen darf.

Stolperfalle: Recycling

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.

Stolperfalle: Validierung

26/09/2011 1 comment

Heute bin ich auf ein faszinierendes Phänomen gestoßen.

Problem war folgendes:

In einer Anwendung hatten wir 2 Comboboxen. Beide wurden mit Werten aus einem Setup-Dokument befüllt. Zusätzlich fügten wir per Javascript (serverseitig) noch einen Leerstring und den Wert New… hinzu. Bei Auswahl von New… wurde ein Dialog aufgerufen.

1. Phänomen: Schloss man den Dialog so stand der Wert in der Combobox noch auf New… Wollte man nun speichern, so wurde die serverseitige Validierung angestoßen, dort tauchte die Meldung “Entry not found in Index” auf. Keiner wusste woher diese Meldung kam. Ein paar Printouts verrieten uns, dass beim ersten Speichern noch der alte Wert im Frontenddokument stand, also der Wert der vor der Auswahl von New… in der Combobox war. Konsequenz daraus, beim ersten Submit auf ein Feld wird bei fehlgeschlagener Validierung der Wert nicht ins Backend submittet, denn selbst ein getComponent(“feldname”).value brachte uns noch den alten Wert zurück. Beim zweiten Submit, wird der wert dann doch übertragen und erneut validiert. Dies kann zu merkwürdigen und schwer nachzu vollziehenden Fehlern führen.

2. Phänomen: Wo kam die Meldung “Entry not found in Index” her? Nach einigem hin und her probieren wurde klar woher er kam: Aus der Form.
Unglaublich aber war, die serverseitige Validierung schleift Fehlermeldungen von anderen Feldern aus der Form durch. Wir hatten in der Datasource des Dokuments definiert, dass beim Speichern der Datasource die Form computed werden soll. In der Form wiederum hatten wir ein Feld, welches aus der Referenz (der Wert der Combobox entsprach per Alias einer UNID) einen Klartextwert für die Volltextsuche machte. Dort wurde ein @DBLookup durchgeführt. Dieser nahm sich den Wert aus dem Feld (New…) und sucht entsprechend danach. Komischerweise gelangt der Wert nicht ins Backend, aber in den Einflussbereich dieser berechneten Formel. Da der Wert nicht da war wurde ein Fehler geworfen. Nämlich “Entry not found in Index”. Dieser wurde dann durchgeschliffen und auf der XPage angezeigt.

Daraus ergab sich die Möglichkeit in dem eigentlichen Feld, wo der Wert aus der Combobox gespeichert wird, in der InputValidation eine Formel zu hinterlegen welche unseren Feldwert validiert und entsprechend mit @Failure() eine Fehlermeldung zurückgibt. Auch diese wurde dann in der XPage angezeigt. So ergeben sich völlig neue Möglichkeiten die Validierung zu erweitern.

%d bloggers like this: