This page (revision-63) was last changed on 26-Mar-2013 12:05 by Dieter Käppel

This page was created on 07-Jun-2009 20:54 by Dieter Käppel

Only authorized users are allowed to rename pages.

Only authorized users are allowed to delete pages.

Page revision history

Version Date Modified Size Author Changes ... Change note
63 26-Mar-2013 12:05 26 KB Dieter Käppel to previous
62 26-Mar-2013 12:05 26 KB Dieter Käppel to previous | to last
61 24-Nov-2012 12:00 26 KB Dieter Käppel to previous | to last

Page References

Incoming links Outgoing links

Version management

Difference between version and

At line 1 changed one line
Die Intersult Taglib ist eine Facelet-Taglib mit einigen nützlichen Tags für die Entwicklung von JEE-Applikationen unter JSF und Seam.
__Achtung:__ [Intersult Taglib] ist nur für JSF 1.2. Für die aktuelle Version JSF 2.1 gibt es [JSF Ext].
At line 3 added 12 lines
Die Intersult hat die Herstellung von JSF-Components revolutioniert: Die [Intersult Taglib] ermöglicht erstmals die Erstellung vollwertiger Facelet-Tags in XHTML. Und das ohne eine Zeile Java-Code zu schreiben.
Die effiziente Herstellung von Components hat einen gravierenden Vorteil: Einzelteile werden wiederverwertbar, das Web-System einheitlicher. Die Components können weiterentwickelt werden, während das Gesamtsystem wächst.
Wir beraten Sie gerne über den Einsatz von Components und die effiziente Strukturierung von JEE-Projekten. Wir liefern Ihnen die für Ihr Projekt nützlichen Components.
!!!Inhalt
[{TableOfContents }]
!!!Was ist Meta-UI?
Die Intersult Taglib "meta-ui" ist eine Taglib zur Produktion von Taglibs. Die produzierten Tags sind geeignet für die Entwicklung von JEE-Applikationen unter JSF 1.2, Seam, Facelets, Tomahawk und Richfaces. Damit produzieren Sie alle denkbaren Tags in hoher Geschwindigkeit, auch mit Javascript, AJAX, Styles oder Images.
At line 4 changed one line
Der wohl interessanteste Tag in der Intersult Bibliothek com.intersult.ui ist der meta-Tag. Was ist ein Meta-Tag? Das ist ein Tag zur Konstruktion einer Component mittels einer XHTML-Datei mit vollwertigem Id- und Rendering-Verhalten. Der Bau eigener Components wird damit zum Kinderspiel, da in der Regel kein Java-Code mehr geschrieben werden braucht.
Der wichtigste Tag der Gruppe "com.intersult", Artifact "meta-ui" ist der meta-Tag. Was ist ein Meta-Tag? Das ist ein Tag zur Konstruktion einer Component mittels einer XHTML-Datei mit vollwertigem Id- und Rendering-Verhalten. Der Bau eigener Components wird damit zum Kinderspiel, da in der Regel keine komplizierten Tag-, Renderer- und Handler-Klassen mehr geschrieben werden brauchen. Eine Java-Klasse bauen Sie nur noch, wenn Ihre Komponente ein Datenmodell braucht, also mit dem value-Attribut an einen Wert gebunden wird.
At line 18 added 2 lines
Dabei sind Features enthalten, wie Component-Id-Generierung, JSF-Client-Id-Access aus Javascript, Javascript- und CSS-Header-Insertions, Resource-Exposition aus dem JAR, Text-Interpolation (Evaluierung von EL-Expressions) in allen Text-Resources etc. Das Gießen eigener Taglibs ist noch nie so einfach gewesen wie heute!
At line 10 removed 2 lines
** __id__ Innerhalb des meta-Tags kann hier eine Id abgerufen werden und als Zuweisung für eine andere Komponente verwendet werden. Diese Id darf natürlich nur einmal verwendet werden, da die im Component-Tree von JSF eindeutig sein muss. Werden mehrere Ids gebraucht, können diese mit #{comp.id}-suffix erzeugt werden.
** __clientId__ Innerhalb des meta-Tags kann hier die clientId, als die im HTML-Code tatsächlich heraus generierte Id abgefragt werden. Dies wird vom JavaScript-Code gebraucht.
At line 28 added 5 lines
* __value:__ Attribut zum Binden an eine EL-Expression, die dann auf der Komponente als Property zur Verfügung steht.
* __type:__ Angabe eines Typs für die Component, standard ist 'com.intersult.ui.tag.meta.Component'. Es kann eine davon abgeleitete Component angegeben werden. Durch hinzufügen von Properties und Methoden können einer Instanz Daten zugeordnet und Funktionen zur Verfügung gestellt werden.
* __attribute:__ Damit kann ein Attribut der Parent Component überschrieben werden, z.B. "onclick" um den Javascript-Event onclick zu überschreiben. Über das Attribut ''get'' spezifiziert wird der entsprechende Wert gesetzt. Optional kann über das Attribut ''set'' der Setter überschreiben werden. Der so erzeugte Tag muss nach A4J- oder Richfaces-Handler gestellt werden, da diese den Handler einfach überschreiben würden. Der meta-Tag hingegen konkateniert die Handler, sodass beide ausgeführt werden. Das so überschriebene Attribut der parent Component kann über "#{comp.attribute}" zugegriffen werden.
* __get:__ Dieses Attribut wird zusammen mit ''attribute'' verwendet, um ein Attribut der Parent Component zu überschreiben. Wurde mit ''attribute'' ein Attribut spezifiziert, muss mit ''get'' ein Wert angegeben werden, der beim Lesen des original Attributs der Parent Component geliefert wird. Der Wert ''#{comp.attribute.value}'' entspricht dabei der ursprünglichen Zuweisung. Das Überschreiben des Setters kann durch das Attribut ''set'' erfolgen.
* __set:__ Dieses Attribut wird zusammen mit ''attribute'' und ''get'' verwendet, ist jedoch optional. Wenn mit ''attribute'' ein Attribut der Parent Component spezifiziert wurde, wird nicht der originale Wert gesetzt, sondern der unter ''set'' spezifizierte. Wie bei ''get'' kann es sich hier um eine EL-Expression handelt, der original zu setzende Wert ist unter der Varialbe '''' zugreifbar. Wird kein Setter spezifiziert entspricht das dem Ausdruck "#{comp.attribute.newValue}".
At line 34 added 18 lines
Wie unter dem Attribut ''var'' beschrieben wird das Object innerhalb des Component Scope einer Variable mit dem unter ''var'' spezifiziertem Namen zugeordnet. In den Beispielen ist das meist ''comp''. Unter diesem Component Object kann auf verschiedene Properties zugegriffen werden:
* __id:__ Innerhalb des meta-Tags kann hier eine Id abgerufen werden und als Zuweisung für eine andere Komponente verwendet werden. Diese Id darf natürlich nur einmal verwendet werden, da die im Component-Tree von JSF eindeutig sein muss. Werden mehrere Ids gebraucht, können diese mit #{comp.id}-suffix erzeugt werden.
* __clientId:__ Innerhalb des meta-Tags kann hier die clientId, als die im HTML-Code tatsächlich heraus generierte Id abgefragt werden. Dies wird vom JavaScript-Code gebraucht.
* __parentId:__ Die JSF-Id des übergeordneten Tags.
* __parentClientId:__ Die ClientId des übergeordneten Tags. Damit ist es möglich, z.B. Javascript-Tags zu bauen, die Aktionen für einen Event durchführen.
* __javascriptId:__ Eine aus der ClientId abgeleitete Id, die für Javascript Variablen und Funktionen benutzt werden kann. Die ClientId kann nicht verwendet werden, da diese Id das Trennzeichen ':' enthält.
* __index:__ Liefert die Position des eigenen Tags im Parent Tag. Damit lassen sich Tabellen einfach mit gestreiftem Muster versehen, erste und letzte Zeile mit besonderem Style versehen etc.
* __count:__ Liefert die Gesamtzahl der Tags im Parent Tag.
* __first:__ Liefert einen boolean-Wert ob der Tag der erste Tag im Parent Tag ist. Damit lassen sich z.B. Header einfärben oder mit anderen Images versehen.
* __last:__ Wie first, nur dass hier auf den letzten Tag geprüft wird.
* __get/set:__ Mit dem generischen getter-/setter-Paar "Object get(String property)" und "void set(String property, Object value)" erhalten man Zugriff auf die UI-Parameter, die an die Komponente übergeben wurden.
* __attribute:__ Über dieses Property kann auf Informationen zu dem über das Attribut ''attribute'' gebundenen Attribute der Parent Component zugegriffen werden:
** __name:__ Name des gebundenen Attributs.
** __attributeValue:__ Der Attribute-Value der gebundenen Komponente. Dieser ist nur gesetzt wenn es sich um einen konstanten Wert und nicht um eine EL-Expression handelt.
** __value:__ Der aktuelle Value des Attribute der parent Component das mit ''attribute'' spezifiziert wurde. Sie auch Attribute ''get''.
** __expression:__ Die ValueExpression der parent Component die an das mit ''attribute'' spezifizierte Attribute gebunden ist.
** __newValue:__ Der neu zuzuordnente Wert der dem durch das ''attribute'' spezifizierten Attribute der parent Component. Nur im Scope der Auswertung des Attribute ''set'' erfügbar. Siehe auch Attribute ''set''.
At line 137 added 152 lines
!Beispiel Menü
Eine eigene Menükomponente wird durch die Tage menu und menuItem gebaut. Zunächst wird eine Resource in der components.xml definiert:
{{{
<component name="resource" class="com.intersult.ui.util.ClassPathResource" scope="application">
<property name="resourcePath">/test</property>
<property name="classPath">/de/test/ui/resource</property>
</component>
}}}
Dann der Tage "menu":
{{{
<ui:composition>
<i:meta var="comp" useId="#{id}" rendered="#{empty rendered or rendered}"
stylesheet="#{resource.get('/test.css')}">
<table id="#{comp.clientId}" cellpadding="0" cellspacing="0">
<i:clear var="id,rendered">
<ui:insert/>
</i:clear>
</table>
</i:meta>
</ui:composition>
}}}
Und schließlich der Tag "menuItem":
{{{
<ui:composition>
<i:meta var="itemComp" useId="#{id}" rendered="#{empty rendered or rendered}"
stylesheet="#{resource.get('/test.css')}">
<tr>
<td class="#{itemComp.last ? 'test-menuL' : 'test-menuI'}"/>
<td class="test-menuContent">
<i:clear var="id,rendered">
<ui:insert/>
</i:clear>
</td>
</tr>
</i:meta>
</ui:composition>
}}}
Schließlich wird das Ganze wieder in die test.taglib.xml eingetragen, und in die test.tld, sodass der Content-Assist in der Entwicklungsumgebung den Tag auch anzeigen kann. Die die vorkommenden Styles in die test.css eingetragen. Mit diesen Tags können dann einfach eigene Menüs inklusive beliebig verschachtelter Untermenüs gebaut werden:
{{{
<o:menu>
<o:menuItem>
<s:link value="#{msg['menu1']}" action="menu1" propagation="none"/>
</o:menuItem>
<o:menuItem>
<s:link value="#{msg['menu2']}" action="menu2"/>
<o:menu>
<o:menuItem>
<s:link value="#{msg['menu2.1']}" action="home" propagation="none"/>
</o:menuItem>
</o:menu>
</o:menuItem>
</o:menu>
}}}
!Beispiel Handler
Es soll ein Tag gebaut werden, der an einen Event-Handler in Javascript hinzugefügt werden kann.
{{{
<i:meta var="comp" useId="#{id}" rendered="#{empty rendered or rendered}" attribute="#{event}" get="#{comp.javascriptId}(this); #{value}">
<script type="text/javascript">
function #{comp.javascriptId}() {
<ui:insert/>
}
</script>
</i:meta>
}}}
Der Facelet-Taglib-Eintrag:
{{{
<tag>
<tag-name>setValue</tag-name>
<source>/com/intersult/ui/tag/setValue.xhtml</source>
</tag>
}}}
Und die TLD-Definition:
{{{
<tag>
<name>setValue</name>
<tag-class/>
<body-content>empty</body-content>
<description>Set a value and call onchange handler</description>
<attribute>
<name>id</name>
</attribute>
<attribute>
<name>rendered</name>
</attribute>
<attribute>
<name>event</name>
<description>Event to set value for</description>
</attribute>
<attribute>
<name>clientId</name>
<description>ClientId of the target input html element to set value for.</description>
</attribute>
<attribute>
<name>value</name>
<description>Value to apply to target input html element</description>
</attribute>
</tag>
}}}
Der Tag kann nun eingesetzt werden, um z.B. bei einer rich:suggestionbox weitere Felder mit zu befüllen:
{{{
<h:inputText id="patient" autocomplete="off"/>
<h:inputText id="gender"/>
<h:inputText id="room"/>
<h:inputText id="patientId"/>
<rich:suggestionbox id="suggest" for="patient" var="suggestion" width="500" height="200"
suggestionAction="#{patient.suggestLabel}" fetchValue="#{patient.label}"
usingSuggestObjects="true" minChars="3">
<i:setValue event="onselect" clientId="#{comp.namingPrefix}gender"
value="#{suggestion.gender}"/>
<i:setValue event="onselect" clientId="#{comp.namingPrefix}room"
value="#{suggestion.room}"/>
<i:setValue event="onselect" clientId="#{comp.namingPrefix}patientId"
value="#{suggestion.id}"/>
<h:column>
<h:outputText value="#{suggestion.label}" escape="false"/>
</h:column>
</rich:suggestionbox>
}}}
!Beispiel Invertierte Checkbox
Hat man z.B. eine Modellklasse ''Article'' mit einem Property ''sold'' und möchte auf der Oberfläche eine Checkbox ''available'' anzeigen, ist dies mit JSF nicht möglich. Der Modellklasse möchte man in der Regel keinen transientes getter-/setter-Paar hinzufügen, da keine Business-Logik eingebracht werden soll.
Eine sehr einfache Lösung erfolgt mit dem meta-Tag:
{{{
<h:selectBooleanCheckbox id="available" value="#{article.sold}">
<i:meta attribute="value" get="#{!value}" set="#{!value}"/>
</h:selectBooleanCheckbox>
}}}
Der meta-Tag im Beispiel arbeitet wie folgt:
* Das Attribut ''attribute="value"'' legt fest, dass das Attribut ''value'' des äußeren Tags ''selectBooleanCheckbox'' überschrieben wird.
* Sobald die Component ''selectBooleanCheckbox'' auf ''value'' zugreift, liefert der meta-Tag stattdessen den Wert des Attributs ''get'' zurück, also ''#{!value}''. Die Variable ''value'' innerhalb der EL-Expression referenziert dabei den Originalwert ''#{article.sold}''. Durch Einsetzen des Originalwert erhält man ''#{!article.sold}''.
* Wenn die Component ''selectBooleanCheckbox'' einen neuen Wert auf ''value'' zurückschreibt, wird stattdessen der Wert des Attributs ''set'' vom meta-Tag geschrieben, im Beispiel also ''#{!value}''. Die Variable ''value'' innerhalb der EL-Expression referenziert hier den Wert, den die Component setzen möchte.
At line 355 added 23 lines
!!!Tag cell
Der cell-Tag erlaubt die Generierung klickbarer Tabellen, wie z.B. eines Kalenders. Die herausragende Eigenschaft von <i:cell> ist der Event "onclick". Cell kann innerhalb von table/tr verwendet werden, um Events zu steuern. Insbesondere AJAX-Calls wie durch a4j:support. Im Folgenden ist die "<<"-Taste eines Kalenders dargestellt, der bei einem [Kunden|Intersult Kunden] produktiv eingesetzt wird (Code aus datenschutzrechtlichen Gründen leicht modifiziert):
{{{
<i:cell styleClass="calendar-cell">
<h:outputText value="&lt;&lt;"/>
<a4j:support event="onclick" action="#{comp.page(-3)}" reRender="#{comp.id}-panel"
limitToList="true" ajaxSingle="true"/>
</i:cell>
}}}
!!!Tag validator
Mit dem validator-Tag können Validators anhand EL-Expressions geschrieben werden. Das Schreiben vieler Validator-Classes wird dadurch erspart. Darüber hinaus ist mit dem validator-Tag eine Parametrisierung der Validierung möglich.
Beispiel ist ein Validator für zwei Datumswerte, der den Anfang eines Events vor dessen Ende prüft:
{{{
<i:inputCalendar value="#{event.from}/>
<i:inputCalendar value="#{event.to}>
<i:validator expression="#{event.from lt value}" message="From before to!"/>
</i:inputCalendar>
}}}
At line 184 changed 3 lines
!!!Installation
!Manuell
Folgende Bibliotheken sind im Stand vom 07.06.2009. Daher sind nicht alle oben beschriebenen Features enthalten. Es wird dringend der im nächsten Abschnitt beschriebene Einsatz von Maven2 empfohlen.
Alle Resources mit Mime-Type text/* werden dabei interpoliert. Insbesondere CSS-Stylesheets und Javascript-Dateien die durch den meta-Tag geladen werden, können dabei mit EL-Expressions versehen werden. Dies ist z.B. interessant beim Styles vom Typ "background-image", da hier über "url(...)" auf eine Resource zugegriffen wird.
At line 188 changed 12 lines
* [Intersult Taglib/com.intersult.ui-1.0-20090607.204442-8.jar]
* [Intersult Taglib/com.intersult.util-1.0-20090607.204442-7.jar]
* JBoss Seam 2.1.2.CR2
* Richfaces 3.3.0.GA
* Facelets 1.1.15.B1
* JSF API/IMPL 1.2_12
* Tomahawk 1.1.8
* Servlet API 2.5
* JSP API 2.0
* Apache commons-lang 2.1
* Apache commons-collections 3.2
* Apache commons-beanutils 1.6
!!!UrlResource
Web-Sites bestehen heute nicht mehr aus einem einzigen Server, sondern aus einer Infrastruktur mit internen und externen Services. Diese Services können Binärdaten als Stream liefern, z.B. wenn Icons angezeigt werden müssen. Die URLs sind oft aufgrund der Sicherheit oder aus technischen Gründen nicht direkt durchreichbar, werden also über den Web-Server gestreamt.
At line 399 added 77 lines
Die Intersult Taglib stellt eine Bean auf Applicationebene zur Verfügung, mit der URLs gestreamt werden können:
{{{
<h:graphicImage value="#{urlResource.get(some.bean.url)}"/>
}}}
Was macht urlResource.get(...)? Die Methode generiert aus einem URL, der nur innerhalb der Infrastruktur zugreifbar ist einen virtuellen URL auf dem Web-Server. Über diesen URL kann später auf den ursprünglichen URL zugegriffen, also auch gestreamt werden. Der Zugriff ist dabei sicher, da von außen keine URLs generisch erzeugt werden können. Nur im Component-Tree gerendete URLs sind gültig.
!!!ResourceBundle
Das ResourceBundle ist eine Erweiterung der Resource-Bundles (länder- und sprachspezifisches Laden von *.properties Resourcen) von JSF und Seam um folgende Features:
* __JAR-Resources:__ JAR-Dateien können Resources enthalten, die vom verwendenten WAR überschrieben werden können. Eine Taglib kann damit eigene Resources mitliefern.
* __Runtime-Loading:__ Die Resourcen können im laufenden Deployment geändert werden und können sofort zugegriffen werden.
Dazu wird einfach ein Einträge nach folgendem Schema in die components.xml der Taglib-JARs und der Applikation gemacht:
{{{
<component name="transportBundles" class="com.intersult.ui.util.ResourceBundle" scope="application" startup="true">
<property name="bundleNames">
<value>transport-messages</value>
</property>
</component>
}}}
Die Resource-Bundles werden dann sauber zusammengeführt und geladen.
!!!Interception
Mit der Intersult taglib können EJB3 Interceptoren durch Events realisiert werden. Konkret heißt das, alle Method Invocations auf Seam- und EJB3-Beans können per Observation abgefangen werden.
!!Eigene Interceptoren
{{{
@Observer("com.intersult.interceptor.preInvoke")
public void preInvoke(InterceptorContext context) throws Exception {
...
}
@Observer("com.intersult.interceptor.postInvoke")
public void postInvoke(InterceptorContext context) throws Exception {
...
}
}}}
InterceptorContext enthält dabei die Felder:
* __invocationContext:__ Der IncovationContext der Methode
* __proceed:__ Nur relevant bei preInvoke, Boolean Feld ob nach Abarbeitung aller Obersvators die Methode ausgeführt werden sollen. Dabei ist zu beachten dass sich mehrere Observatoren gegenseitig überschreiben könnten, der Implementor ist verantwortlich für die Auflösung von Konflikten.
* __result:__ Nur relevant bei postInvoke, Object Feld das das Ergebnis der Invocation enthält. Das Ergebnis kann verändert werden. Dabei ist zu beachten dass sich mehrere Observatoren gegenseitig überschreiben könnten, der Implementor ist verantwortlich für die Auflösung von Konflikten.
!!EjbInjector
Der EjbInjector ist eine bereits in der Intersult taglib enthaltener Interceptor der auf der Event-Technologie basiert. Werden in Seam-Beans @EJB-Injections benutzt, sind diese normaler Weise unwirksam. Der EjbInjector löst diese Abhängigkeiten auf. Entweder der vollständige Name wird angegeben:
{{{
@EJB(name = "earName/beanName/local"
private Bean bean;
}}}
Oder der Name wird generiert aus dem Seam jndiPattern aus der Init-Komponente, die in der components.xml definiert wird:
JBoss:
{{{
<core:init jndi-pattern="ear-name/#{ejbName}/local"/>
}}}
Glassfish:
{{{
<core:init jndi-pattern="java:comp/env/#{className}/#{fieldName}"/>
}}}
In der Seam-Bean braucht dann nur noch die @EJB-Annotation zu stehen:
{{{
@EJB
private Bean bean;
}}}
!!!Installation
At line 202 changed one line
Wesentlich einfacher gestaltet sich die Integration der com.intersult.ui-Bibliothek, wenn ein Build mit [Maven2|http://maven.apache.org/] durchgeführt werden kann:
Läuft der Build-Prozess in Ihrem Projekt bereits auf [Maven2|http://maven.apache.org/]? Wenn nicht, sollten Sie es sich gründlich überlegen. Der Aufwand zum Einlernen ist sehr gering und der Benefit beim Dependency, Build, Deployment, Distribution, Source Code, Development Environment und andere Prozesse profitieren wesentlich.
At line 479 added 2 lines
Um die Taglib einzubinden, brauchen Sie nur folgende Einträge in Ihrem pom.xml vorzunehmen:
At line 211 changed 2 lines
<artifactId>com.intersult.ui</artifactId>
<version>1.0-SNAPSHOT</version>
<artifactId>meta-ui</artifactId>
<version>1.1-SNAPSHOT</version>
At line 506 added 2 lines
Bei dem Arbeiten mit Eclipse, ist die Taglib nach einem "mvn eclipse:eclipse" und einem Refresh des Projekts verfügbar. Ihnen ist unklar, wie der Content-Assist unter Eclipse für Tags korrekt konfiguriert wird? Wir beantworten gerne diese und weiter Fragen. Nehmen Sie Kontakt mit uns auf.