Stumbling Stones: Difference between xp:panel and xp:div
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.
XPages: Notes Objekte in Java Singleton Patterns
Ich hatte ja vor einer Weile in diesem Post am Ende von einem Problem berichtet, welches ich im XPages Forum gepostet habe.
Gestern habe ich mit Philippe Riand, dem Chef-Entwickler der XPages von IBM, über das Problem gesprochen. Hier ist die Erklärung:
Ich habe ja das NoteDatabase Objekt in der Klasseninstanz als Attribut gespeichert. D.h. dass bei jedem Request das gleiche Objekt verwendet wird, wie es ja auch bei einem Singleton Pattern sein soll.
Aber: Nach jedem Request wird ein NotesDatabase Objekt recycled, und zwar schon seit 8.5.1. Das hat einfach den Hintergrund, dass in dem NotesDatabase Objekt die Credentials des Users, der den Request abgeschickt hat, mitgespeichert werden. So würde, wenn User A die Funktion aufruft und die Klasse initialisiert, und dann User B die gleiche Funktion aufruft, die gleiche Instanz verwenden, in dem das NotesDatabase von User gespeichert ist. Würde somit die Funktion mit den Berechtigungen von User A aufrufen. Das darf natürlich nicht passieren. Daher wird, schon seit 8.5.1, ein NotesDatabase Objekt nach jedem Request recycled. Da das ganze in dem Singleton Pattern abläuft ist natürlich das Objekt noch da und nicht Null, hat aber keine Referenz mehr zur eigentlichen Datenbank und wirft somit den Fehler dass das Objekt removed oder recycled wurde.
Macht von dem Gesichtspunkt her natürlich auf jeden Fall Sinn, man muss es halt nur wissen.
Natürlich ist die Frage warum es dann bei mir unter 8.5.1 funktioniert hat. Die einzige Erklärung die wir finden konnten war, dass dies ein Bug unter 8.5.1 sein muss. Das sollte man denke ich auf jeden Fall mal bei sich in den Anwendungen überprüfen, da dies theoretisch ein ziemliches Sicherheitsrisiko sein kann.
Stattdessen sollte man, z.B. beim Aufruf der getInstance Methode die aktuelle Datenbank übergeben oder sich in der Java Klasse das Objekt direkt holen und jedes Mal neu setzen.
Stolperfalle: “Cycle reference” in Serverside Javascript
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.


