Posts Tagged: ‘Attribute’

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

2. April 2012 Posted by airwolf89

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.


Filed under: Stumbling Stones Tagged: Attribute, CSS, Datasource, Hierarchy, HTML, Java, Notes, Stumbling Stone, xp:div, xp:panel, XPages

XPages: Notes Objekte in Java Singleton Patterns

28. März 2012 Posted by airwolf89

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.


Einsortiert unter:Notes & XPages Tagged: Attribute, credentials, Error, ibm, Java, Notes, NotesDatabase, Parameter, Phillipe Riand, Referenz, removed or recycled, Request, Serverside Javascript, Session, Singleton Pattern, XPages

Stolperfalle: “Cycle reference” in Serverside Javascript

24. März 2012 Posted by airwolf89

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.


Einsortiert unter:Notes & XPages, Stolperfallen Tagged: Attribute, Bug, Cycle reference, gegenseitige Referenzierung, Java, libraries, Notes, OutOfMemoryException, Scriptlibrary, Serverside Javascript, Stolperfalle, XPages

XPages: Tippsammlung

18. Oktober 2011 Posted by airwolf89

Hallo,

hier mal eine kleine Ansammlung von Tipps welche meine Kollegen und ich uns im Laufe der Zeit notiert haben.

Attributbenennung im IE

Dojo scheint bei Attributselektoren (z.B. dojo.query()) im Internet Explorer Probleme zu haben, die richtigen Elemente zu finden, wenn ein Teilstring des Attributs ein reserviertes Wort (z.B. name oder id) enthält. Da Dojo wie jQuery als Selektor-Engine Sizzle einsetzt, kann dieses Phänomen auch bei jQuery auftreten!

Beispiel hierfür ist ein Input-Feld mit dem Namen „username“. Selektiert man dojo.query(‘input[id$="WFApprovalVFL"]‘) wird das username-Feld mitselektiert, obwohl es nicht auf WFApprovalVFL endet.

Selbiges gilt für Keynamen in JSON-Objekten.

Nich gerenderte Datasources werden dennoch computed

Wenn man in einem Custom Control eine Datasource verwendet, dann wird dessen Code IMMER ausgeführt, egal ob rendered=“false“ oder loaded=“false“. Der Code dazu wird immer ausgeführt. Dies kann zu schwer nachvollziehbaren Fehlern führen.

Des weiteren, wenn man mehrere Datasources in unterschiedlichen Custom Controls hat, welche auf das selbe Dokument zeigen, so werden alle diese Datasources gespeichert und ggf. mehrere Dokumente desselben Typs angelegt.
Um dieses Problem zu umgehen kann man in den Custom Controls entweder die Datasource auf der XPage direkt über den namen referenzieren, oder man übergibt die Datasource per Parameter an das Custom Control (compositeData). Da muss man allerdings manuell einen Typ auswählen, da Datasources nicht in der Liste auftauchen. Der Typ heißt: com.ibm.xsp.model.ModelDataSource

Prüfen ob ein Viewpanel kategorisiert ist

Gesetzt den Fall, das zu prüfende View Control auf der XPage heißt viewPanel1, liefert:

var model:com.ibm.xsp.model.domino.DominoViewDataModel = getComponent("viewPanel1").getDataModel();
return model.getCategoryIndentLevel();

den Wert 0, wenn die View kategorisiert ist, -1 wenn nicht.

Use case: Bei kategorisierten Views gehen die Inhalte der Kategoriespalte verloren, wenn die View umsortiert wird. Hiermit kann man prüfen, ob die View umsortiert ist und entsprechend die Anzeige wiederherstellen.

Umgehen des OnChange-Bugs im IE beim Klick auf eine CheckBoxGroup

Werden auf einer XPage oder Custom Control Radiobutton Groups oder Checkbox Groups verwendet, tritt im IE das Phänomen auf, dass beim Partial refresh die übergebenen Werte der Gruppe immer die Werte des vorangegangenen Requests sind. Dies tritt nur auf, wenn man auf das Label klickt, statt direkt auf die Box zu klicken. Grund hierfür ist, dass der IE den Partial refresh-Request abschickt, bevor auf der UI der neue Wert gesetzt wird.

rendered="#{javascript:context.getUserAgent().isIE()}"


Beispiel
:

Es gibt eine Checkbox-Gruppe mit den Optionen A, B, C, D. Beim onchange-Event wird ein Partial refresh auf ein anderes Panel ausgelöst, das abhängig von den gewählten Optionen Elemente ein- oder ausblendet. Klickt man auf das Label für die Option A, kommt kein gewählter Wert an. Klickt man anschließend auf das Label für die Option B, kommt der Wert A an. Klickt man anschließend auf das Label der Option C, kommen A und B an, usw.


Workaround
:

Im onclick-Eventhandler wird der Partial refresh beim oncomplete ein zweites Mal ausgeführt.

 <xp:this.onComplete>
<![CDATA[XSP.partialRefreshPost("#{id:refreshPanelID}");]]>
</xp:this.onComplete>

Obiger Workaround 1 wirkt nicht, wenn auf dem Eventhandler zusätzlich noch Aktionen bzw. Server Side Javascript ausgeführt werden soll. Dieser Code wird dann nur beim ersten partial refresh ausgeführt. Um diesen Eventhandler wieder gängig zu machen, muss man den Click-Event des Labels von seiner Standard-Aktion abhängen und selbst durchführen. Dies macht man in einem clientseitigen Scriptblock. Da aber die Checkbox selbst auch innerhalb des Labels liegt, muss man diese wiederum aus der eigenen Verarbeitung rausnehmen:

 <xp:scriptBlock id="scriptBlock1"
        rendered="#{javascript:context.getUserAgent().isIE()}">
        <xp:this.value><![CDATA[dojo.addOnLoad(function(){
    dojo.query("label",dojo.byId("#{id:checkBoxGroupID}")).forEach(function(el){        
        dojo.connect(el,"onclick",el,function(e){
            if (e.target.type != "checkbox") {
                e.preventDefault();
                dojo.query("input",this).forEach(function(el){
                    dojo.attr(el,"checked",!(dojo.attr(el,"checked")));
                });
            }    
        });
    });        
});]]></xp:this.value>
</xp:scriptBlock>

Ein weiterer Vorteil dieser Methode gegenüber Workaround 1 ist, dass kein zweiter Request nötig ist.

Validierung von zwei abhängigen Eingabefeldern

Bei der Validierung von zwei voneinander abhängigen Eingabefeldern muss der SubmittedValue des Feldes abgefragt werden, das validiert wird. Vergleicht man den Value des Feldes mit dem Value des zweiten Feldes, wird die Validierung nach dem ersten Fehlschlag nicht mehr ausgelöst und der Validierungsfehler bleibt bestehen.

Beispiel:

 <xp:inputText id="recipientNotesID"
   value="#{test.recipientNotesID}"
   disableClientSideValidation="true" required="true">
   <xp:this.validators>
      <xp:validateRequired message="Required value."></xp:validateRequired>
   </xp:this.validators>
</xp:inputText>
<xp:inputText id="recipientNotesPW"
   value="#{test.recipientNotesPW}"
   disableClientSideValidation="true" required="true">
   <xp:this.validators>
      <xp:validateExpression>
         <xp:this.expression><![CDATA[#{javascript:((getComponent("recipientNotesPW").getSubmittedValue()||"")!=(getComponent("recipientNotesID").getValue()||""))}]]>
         </xp:this.expression>
         <xp:this.message><![CDATA[#{javascript:"Values must not be equal."}]]></xp:this.message>
      </xp:validateExpression>
      <xp:validateRequired message="Required value."></xp:validateRequired>
   </xp:this.validators>
</xp:inputText>